Commit 7b7b68bb authored by Jiri Kosina's avatar Jiri Kosina

floppy: bail out in open() if drive is not responding to block0 read

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.
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 8586ea96
...@@ -3691,9 +3691,12 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) ...@@ -3691,9 +3691,12 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
if (!(mode & FMODE_NDELAY)) { if (!(mode & FMODE_NDELAY)) {
if (mode & (FMODE_READ|FMODE_WRITE)) { if (mode & (FMODE_READ|FMODE_WRITE)) {
UDRS->last_checked = 0; UDRS->last_checked = 0;
clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
check_disk_change(bdev); check_disk_change(bdev);
if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags)) if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
goto out; goto out;
if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
goto out;
} }
res = -EROFS; res = -EROFS;
if ((mode & FMODE_WRITE) && if ((mode & FMODE_WRITE) &&
...@@ -3746,17 +3749,29 @@ static unsigned int floppy_check_events(struct gendisk *disk, ...@@ -3746,17 +3749,29 @@ static unsigned int floppy_check_events(struct gendisk *disk,
* a disk in the drive, and whether that disk is writable. * a disk in the drive, and whether that disk is writable.
*/ */
static void floppy_rb0_complete(struct bio *bio, int err) struct rb0_cbdata {
int drive;
struct completion complete;
};
static void floppy_rb0_cb(struct bio *bio, int err)
{ {
complete((struct completion *)bio->bi_private); struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private;
int drive = cbdata->drive;
if (err) {
pr_info("floppy: error %d while reading block 0", err);
set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
}
complete(&cbdata->complete);
} }
static int __floppy_read_block_0(struct block_device *bdev) static int __floppy_read_block_0(struct block_device *bdev, int drive)
{ {
struct bio bio; struct bio bio;
struct bio_vec bio_vec; struct bio_vec bio_vec;
struct completion complete;
struct page *page; struct page *page;
struct rb0_cbdata cbdata;
size_t size; size_t size;
page = alloc_page(GFP_NOIO); page = alloc_page(GFP_NOIO);
...@@ -3769,6 +3784,8 @@ static int __floppy_read_block_0(struct block_device *bdev) ...@@ -3769,6 +3784,8 @@ static int __floppy_read_block_0(struct block_device *bdev)
if (!size) if (!size)
size = 1024; size = 1024;
cbdata.drive = drive;
bio_init(&bio); bio_init(&bio);
bio.bi_io_vec = &bio_vec; bio.bi_io_vec = &bio_vec;
bio_vec.bv_page = page; bio_vec.bv_page = page;
...@@ -3779,13 +3796,14 @@ static int __floppy_read_block_0(struct block_device *bdev) ...@@ -3779,13 +3796,14 @@ static int __floppy_read_block_0(struct block_device *bdev)
bio.bi_bdev = bdev; bio.bi_bdev = bdev;
bio.bi_iter.bi_sector = 0; bio.bi_iter.bi_sector = 0;
bio.bi_flags = (1 << BIO_QUIET); bio.bi_flags = (1 << BIO_QUIET);
init_completion(&complete); bio.bi_private = &cbdata;
bio.bi_private = &complete; bio.bi_end_io = floppy_rb0_cb;
bio.bi_end_io = floppy_rb0_complete;
submit_bio(READ, &bio); submit_bio(READ, &bio);
process_fd_request(); process_fd_request();
wait_for_completion(&complete);
init_completion(&cbdata.complete);
wait_for_completion(&cbdata.complete);
__free_page(page); __free_page(page);
...@@ -3827,7 +3845,7 @@ static int floppy_revalidate(struct gendisk *disk) ...@@ -3827,7 +3845,7 @@ static int floppy_revalidate(struct gendisk *disk)
UDRS->generation++; UDRS->generation++;
if (drive_no_geom(drive)) { if (drive_no_geom(drive)) {
/* auto-sensing */ /* auto-sensing */
res = __floppy_read_block_0(opened_bdev[drive]); res = __floppy_read_block_0(opened_bdev[drive], drive);
} else { } else {
if (cf) if (cf)
poll_drive(false, FD_RAW_NEED_DISK); poll_drive(false, FD_RAW_NEED_DISK);
......
...@@ -185,7 +185,8 @@ enum { ...@@ -185,7 +185,8 @@ enum {
* to clear media change status */ * to clear media change status */
FD_UNUSED_BIT, FD_UNUSED_BIT,
FD_DISK_CHANGED_BIT, /* disk has been changed since last i/o */ FD_DISK_CHANGED_BIT, /* disk has been changed since last i/o */
FD_DISK_WRITABLE_BIT /* disk is writable */ FD_DISK_WRITABLE_BIT, /* disk is writable */
FD_OPEN_SHOULD_FAIL_BIT
}; };
#define FDSETDRVPRM _IOW(2, 0x90, struct floppy_drive_params) #define FDSETDRVPRM _IOW(2, 0x90, struct floppy_drive_params)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment