summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikael Pettersson <mikpe@csd.uu.se>2002-05-22 00:31:36 -0700
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-05-22 00:31:36 -0700
commitd0f0cde199764cb083b3617c3739f45b1a73052d (patch)
tree62bffa26a5e1588b0fc48a348d814ea383a445d7
parentc14217358773b5954e4406e0bd63c75f8f66803f (diff)
[PATCH] possible fix for broken floppy driver, take 2
Here is an updated patch for the floppy driver which got broken in 2.5.13. "read block 0 on ->revalidate()" is now implemented through the bio interface, following a suggestion by Christoph Hellwig. I still cannot explain why block_dev.c's ->bd_block_size change caused data corruption, but removing that code fixes the floppy driver and doesn't seem to cause any problems on my test box.
-rw-r--r--drivers/block/floppy.c95
-rw-r--r--fs/block_dev.c11
2 files changed, 71 insertions, 35 deletions
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 3b3dd40bc694..14864e69cc3a 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -243,6 +243,7 @@ static int irqdma_allocated;
#include <linux/blk.h>
#include <linux/blkpg.h>
#include <linux/cdrom.h> /* for the compatibility eject ioctl */
+#include <linux/completion.h>
#ifndef fd_get_dma_residue
#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
@@ -3853,6 +3854,74 @@ static int check_floppy_change(kdev_t dev)
return 0;
}
+/*
+ * This implements "read block 0" for floppy_revalidate().
+ * Needed for format autodetection, checking whether there is
+ * a disk in the drive, and whether that disk is writable.
+ */
+
+static void floppy_rb0_complete(struct bio *bio)
+{
+ complete((struct completion*)bio->bi_private);
+}
+
+static int __floppy_read_block_0(struct block_device *bdev)
+{
+ struct bio bio;
+ struct bio_vec bio_vec;
+ struct completion complete;
+ struct page *page;
+ size_t size;
+
+ page = alloc_page(GFP_NOIO);
+ if (!page) {
+ process_fd_request();
+ return -ENOMEM;
+ }
+
+ size = bdev->bd_block_size;
+ if (!size)
+ size = 1024;
+
+ bio_init(&bio);
+ bio.bi_io_vec = &bio_vec;
+ bio_vec.bv_page = page;
+ bio_vec.bv_len = size;
+ bio_vec.bv_offset = 0;
+ bio.bi_vcnt = 1;
+ bio.bi_idx = 0;
+ bio.bi_size = size;
+ bio.bi_bdev = bdev;
+ bio.bi_sector = 0;
+ init_completion(&complete);
+ bio.bi_private = &complete;
+ bio.bi_end_io = floppy_rb0_complete;
+
+ submit_bio(READ, &bio);
+ run_task_queue(&tq_disk);
+ process_fd_request();
+ wait_for_completion(&complete);
+
+ __free_page(page);
+
+ return 0;
+}
+
+static int floppy_read_block_0(kdev_t dev)
+{
+ struct block_device *bdev;
+ int ret;
+
+ bdev = bdget(kdev_t_to_nr(dev));
+ if (!bdev) {
+ printk("No block device for %s\n", __bdevname(dev));
+ BUG();
+ }
+ ret = __floppy_read_block_0(bdev);
+ atomic_dec(&bdev->bd_count);
+ return ret;
+}
+
/* revalidate the floppy disk, i.e. trigger format autodetection by reading
* the bootblock (block 0). "Autodetection" is also needed to check whether
* there is a disk in the drive at all... Thus we also do it for fixed
@@ -3860,9 +3929,6 @@ static int check_floppy_change(kdev_t dev)
static int floppy_revalidate(kdev_t dev)
{
#define NO_GEOM (!current_type[drive] && !TYPE(dev))
-#if 0
- struct buffer_head * bh;
-#endif
int drive=DRIVE(dev);
int cf;
@@ -3889,29 +3955,8 @@ static int floppy_revalidate(kdev_t dev)
if (cf)
UDRS->generation++;
if (NO_GEOM){
-#if 0
- /*
- * What the devil is going on here? We are not guaranteed to do
- * any IO and ENXIO case is nothing but ENOMEM in disguise - it
- * happens if and only if buffer cache is out of memory. WTF?
- */
/* auto-sensing */
- int size = floppy_blocksizes[minor(dev)];
- if (!size)
- size = 1024;
- if (!(bh = getblk(dev,0,size))){
- process_fd_request();
- return -ENXIO;
- }
- if (bh && !buffer_uptodate(bh))
- ll_rw_block(READ, 1, &bh);
- process_fd_request();
- wait_on_buffer(bh);
- brelse(bh);
- return 0;
-#endif
- process_fd_request();
- return 0;
+ return floppy_read_block_0(dev);
}
if (cf)
poll_drive(0, FD_RAW_NEED_DISK);
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 654d98a256b0..27fd276f1a36 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -606,16 +606,7 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
goto out2;
}
bdev->bd_inode->i_size = blkdev_size(dev);
- if (!bdev->bd_openers) {
- unsigned bsize = bdev_hardsect_size(bdev);
- while (bsize < PAGE_CACHE_SIZE) {
- if (bdev->bd_inode->i_size & bsize)
- break;
- bsize <<= 1;
- }
- bdev->bd_block_size = bsize;
- bdev->bd_inode->i_blkbits = blksize_bits(bsize);
- }
+ bdev->bd_inode->i_blkbits = blksize_bits(block_size(bdev));
bdev->bd_openers++;
unlock_kernel();
up(&bdev->bd_sem);