Commit d0f0cde1 authored by Mikael Pettersson's avatar Mikael Pettersson Committed by Linus Torvalds

[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.
parent c1421735
...@@ -243,6 +243,7 @@ static int irqdma_allocated; ...@@ -243,6 +243,7 @@ static int irqdma_allocated;
#include <linux/blk.h> #include <linux/blk.h>
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include <linux/cdrom.h> /* for the compatibility eject ioctl */ #include <linux/cdrom.h> /* for the compatibility eject ioctl */
#include <linux/completion.h>
#ifndef fd_get_dma_residue #ifndef fd_get_dma_residue
#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA) #define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
...@@ -3853,6 +3854,74 @@ static int check_floppy_change(kdev_t dev) ...@@ -3853,6 +3854,74 @@ static int check_floppy_change(kdev_t dev)
return 0; 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 /* revalidate the floppy disk, i.e. trigger format autodetection by reading
* the bootblock (block 0). "Autodetection" is also needed to check whether * 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 * 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) ...@@ -3860,9 +3929,6 @@ static int check_floppy_change(kdev_t dev)
static int floppy_revalidate(kdev_t dev) static int floppy_revalidate(kdev_t dev)
{ {
#define NO_GEOM (!current_type[drive] && !TYPE(dev)) #define NO_GEOM (!current_type[drive] && !TYPE(dev))
#if 0
struct buffer_head * bh;
#endif
int drive=DRIVE(dev); int drive=DRIVE(dev);
int cf; int cf;
...@@ -3889,29 +3955,8 @@ static int floppy_revalidate(kdev_t dev) ...@@ -3889,29 +3955,8 @@ static int floppy_revalidate(kdev_t dev)
if (cf) if (cf)
UDRS->generation++; UDRS->generation++;
if (NO_GEOM){ 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 */ /* auto-sensing */
int size = floppy_blocksizes[minor(dev)]; return floppy_read_block_0(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;
} }
if (cf) if (cf)
poll_drive(0, FD_RAW_NEED_DISK); poll_drive(0, FD_RAW_NEED_DISK);
......
...@@ -606,16 +606,7 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * ...@@ -606,16 +606,7 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
goto out2; goto out2;
} }
bdev->bd_inode->i_size = blkdev_size(dev); bdev->bd_inode->i_size = blkdev_size(dev);
if (!bdev->bd_openers) { bdev->bd_inode->i_blkbits = blksize_bits(block_size(bdev));
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_openers++; bdev->bd_openers++;
unlock_kernel(); unlock_kernel();
up(&bdev->bd_sem); up(&bdev->bd_sem);
......
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