In case reading of block 0 during open() fails, it is not the right thing to let open() succeed. Fix this by introducing FD_OPEN_SHOULD_FAIL_BIT flag, and setting it in case the bio callback encounters an error while trying to read block 0. As a bonus, this works around certain broken userspace (blkid), which is not able to properly handle read()s returning IO errors. Hence be nice to those, and bail out during open() already; if block 0 is not readable, read()s are not going to provide any meaningful data anyway.
Unified · Split
| @@ -3691,9 +3691,12 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) · 3690 unmodified lines | ||
| 3691 | 3691 | if (!(mode & FMODE_NDELAY)) { |
| 3692 | 3692 | if (mode & (FMODE_READ|FMODE_WRITE)) { |
| 3693 | 3693 | UDRS->last_checked = 0; |
| 3694 | + clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags); | |
| 3694 | 3695 | check_disk_change(bdev); |
| 3695 | 3696 | if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags)) |
| 3696 | 3697 | goto out; |
| 3698 | + if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags)) | |
| 3699 | + goto out; | |
| 3697 | 3700 | } |
| 3698 | 3701 | res = -EROFS; |
| 3699 | 3702 | if ((mode & FMODE_WRITE) && |
| @@ -3746,17 +3749,29 @@ static unsigned int floppy_check_events(struct gendisk *disk, · 46 unmodified lines | ||
| 3746 | 3749 | * a disk in the drive, and whether that disk is writable. |
| 3747 | 3750 | */ |
| 3748 | 3751 | |
| 3749 | −static void floppy_rb0_complete(struct bio *bio, int err) | |
| 3752 | +struct rb0_cbdata { | |
| 3753 | + int drive; | |
| 3754 | + struct completion complete; | |
| 3755 | +}; | |
| 3756 | + | |
| 3757 | +static void floppy_rb0_cb(struct bio *bio, int err) | |
| 3750 | 3758 | { |
| 3751 | − complete((struct completion *)bio->bi_private); | |
| 3759 | + struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private; | |
| 3760 | + int drive = cbdata->drive; | |
| 3761 | + | |
| 3762 | + if (err) { | |
| 3763 | + pr_info("floppy: error %d while reading block 0", err); | |
| 3764 | + set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags); | |
| 3765 | + } | |
| 3766 | + complete(&cbdata->complete); | |
| 3752 | 3767 | } |
| 3753 | 3768 | |
| 3754 | −static int __floppy_read_block_0(struct block_device *bdev) | |
| 3769 | +static int __floppy_read_block_0(struct block_device *bdev, int drive) | |
| 3755 | 3770 | { |
| 3756 | 3771 | struct bio bio; |
| 3757 | 3772 | struct bio_vec bio_vec; |
| 3758 | − struct completion complete; | |
| 3759 | 3773 | struct page *page; |
| 3774 | + struct rb0_cbdata cbdata; | |
| 3760 | 3775 | size_t size; |
| 3761 | 3776 | |
| 3762 | 3777 | page = alloc_page(GFP_NOIO); |
| @@ -3769,6 +3784,8 @@ static int __floppy_read_block_0(struct block_device *bdev) · 6 unmodified lines | ||
| 3769 | 3784 | if (!size) |
| 3770 | 3785 | size = 1024; |
| 3771 | 3786 | |
| 3787 | + cbdata.drive = drive; | |
| 3788 | + | |
| 3772 | 3789 | bio_init(&bio); |
| 3773 | 3790 | bio.bi_io_vec = &bio_vec; |
| 3774 | 3791 | bio_vec.bv_page = page; |
| @@ -3779,13 +3796,14 @@ static int __floppy_read_block_0(struct block_device *bdev) · 4 unmodified lines | ||
| 3779 | 3796 | bio.bi_bdev = bdev; |
| 3780 | 3797 | bio.bi_iter.bi_sector = 0; |
| 3781 | 3798 | bio.bi_flags = (1 << BIO_QUIET); |
| 3782 | − init_completion(&complete); | |
| 3783 | − bio.bi_private = &complete; | |
| 3784 | − bio.bi_end_io = floppy_rb0_complete; | |
| 3799 | + bio.bi_private = &cbdata; | |
| 3800 | + bio.bi_end_io = floppy_rb0_cb; | |
| 3785 | 3801 | |
| 3786 | 3802 | submit_bio(READ, &bio); |
| 3787 | 3803 | process_fd_request(); |
| 3788 | − wait_for_completion(&complete); | |
| 3804 | + | |
| 3805 | + init_completion(&cbdata.complete); | |
| 3806 | + wait_for_completion(&cbdata.complete); | |
| 3789 | 3807 | |
| 3790 | 3808 | __free_page(page); |
| 3791 | 3809 | |
| @@ -3827,7 +3845,7 @@ static int floppy_revalidate(struct gendisk *disk) · 35 unmodified lines | ||
| 3827 | 3845 | UDRS->generation++; |
| 3828 | 3846 | if (drive_no_geom(drive)) { |
| 3829 | 3847 | /* auto-sensing */ |
| 3830 | − res = __floppy_read_block_0(opened_bdev[drive]); | |
| 3848 | + res = __floppy_read_block_0(opened_bdev[drive], drive); | |
| 3831 | 3849 | } else { |
| 3832 | 3850 | if (cf) |
| 3833 | 3851 | poll_drive(false, FD_RAW_NEED_DISK); |
| @@ -185,7 +185,8 @@ enum { · 184 unmodified lines | ||
| 185 | 185 | * to clear media change status */ |
| 186 | 186 | FD_UNUSED_BIT, |
| 187 | 187 | FD_DISK_CHANGED_BIT, /* disk has been changed since last i/o */ |
| 188 | − FD_DISK_WRITABLE_BIT /* disk is writable */ | |
| 188 | + FD_DISK_WRITABLE_BIT, /* disk is writable */ | |
| 189 | + FD_OPEN_SHOULD_FAIL_BIT | |
| 189 | 190 | }; |
| 190 | 191 | |
| 191 | 192 | #define FDSETDRVPRM _IOW(2, 0x90, struct floppy_drive_params) |