diff options
Diffstat (limited to 'drivers/block/floppy.c')
-rw-r--r-- | drivers/block/floppy.c | 51 |
1 files changed, 37 insertions, 14 deletions
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index d23b543..bedb689 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -170,6 +170,7 @@ static int print_unex = 1; #include <linux/mm.h> #include <linux/bio.h> #include <linux/string.h> +#include <linux/jiffies.h> #include <linux/fcntl.h> #include <linux/delay.h> #include <linux/mc146818rtc.h> /* CMOS defines */ @@ -179,6 +180,7 @@ static int print_unex = 1; #include <linux/devfs_fs_kernel.h> #include <linux/platform_device.h> #include <linux/buffer_head.h> /* for invalidate_buffers() */ +#include <linux/mutex.h> /* * PS/2 floppies have much slower step rates than regular floppies. @@ -249,6 +251,18 @@ static int irqdma_allocated; #include <linux/cdrom.h> /* for the compatibility eject ioctl */ #include <linux/completion.h> +/* + * Interrupt freeing also means /proc VFS work - dont do it + * from interrupt context. We push this work into keventd: + */ +static void fd_free_irq_fn(void *data) +{ + fd_free_irq(); +} + +static DECLARE_WORK(fd_free_irq_work, fd_free_irq_fn, NULL); + + static struct request *current_req; static struct request_queue *floppy_queue; static void do_fd_request(request_queue_t * q); @@ -413,7 +427,7 @@ static struct floppy_write_errors write_errors[N_DRIVE]; static struct timer_list motor_off_timer[N_DRIVE]; static struct gendisk *disks[N_DRIVE]; static struct block_device *opened_bdev[N_DRIVE]; -static DECLARE_MUTEX(open_lock); +static DEFINE_MUTEX(open_lock); static struct floppy_raw_cmd *raw_cmd, default_raw_cmd; /* @@ -734,7 +748,7 @@ static int disk_change(int drive) { int fdc = FDC(drive); #ifdef FLOPPY_SANITY_CHECK - if (jiffies - UDRS->select_date < UDP->select_delay) + if (time_before(jiffies, UDRS->select_date + UDP->select_delay)) DPRINT("WARNING disk change called early\n"); if (!(FDCS->dor & (0x10 << UNIT(drive))) || (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) { @@ -1062,7 +1076,7 @@ static int fd_wait_for_completion(unsigned long delay, timeout_fn function) return 1; } - if ((signed)(jiffies - delay) < 0) { + if (time_before(jiffies, delay)) { del_timer(&fd_timer); fd_timer.function = function; fd_timer.expires = delay; @@ -1522,7 +1536,7 @@ static void setup_rw_floppy(void) * again just before spinup completion. Beware that * after scandrives, we must again wait for selection. */ - if ((signed)(ready_date - jiffies) > DP->select_delay) { + if (time_after(ready_date, jiffies + DP->select_delay)) { ready_date -= DP->select_delay; function = (timeout_fn) floppy_start; } else @@ -3333,7 +3347,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g, if (type) { if (!capable(CAP_SYS_ADMIN)) return -EPERM; - down(&open_lock); + mutex_lock(&open_lock); LOCK_FDC(drive, 1); floppy_type[type] = *g; floppy_type[type].name = "user format"; @@ -3347,7 +3361,7 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g, continue; __invalidate_device(bdev); } - up(&open_lock); + mutex_unlock(&open_lock); } else { int oldStretch; LOCK_FDC(drive, 1); @@ -3674,7 +3688,7 @@ static int floppy_release(struct inode *inode, struct file *filp) { int drive = (long)inode->i_bdev->bd_disk->private_data; - down(&open_lock); + mutex_lock(&open_lock); if (UDRS->fd_ref < 0) UDRS->fd_ref = 0; else if (!UDRS->fd_ref--) { @@ -3684,7 +3698,7 @@ static int floppy_release(struct inode *inode, struct file *filp) if (!UDRS->fd_ref) opened_bdev[drive] = NULL; floppy_release_irq_and_dma(); - up(&open_lock); + mutex_unlock(&open_lock); return 0; } @@ -3702,7 +3716,7 @@ static int floppy_open(struct inode *inode, struct file *filp) char *tmp; filp->private_data = (void *)0; - down(&open_lock); + mutex_lock(&open_lock); old_dev = UDRS->fd_device; if (opened_bdev[drive] && opened_bdev[drive] != inode->i_bdev) goto out2; @@ -3785,7 +3799,7 @@ static int floppy_open(struct inode *inode, struct file *filp) if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE))) goto out; } - up(&open_lock); + mutex_unlock(&open_lock); return 0; out: if (UDRS->fd_ref < 0) @@ -3796,7 +3810,7 @@ out: opened_bdev[drive] = NULL; floppy_release_irq_and_dma(); out2: - up(&open_lock); + mutex_unlock(&open_lock); return res; } @@ -3810,7 +3824,7 @@ static int check_floppy_change(struct gendisk *disk) if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY)) return 1; - if (UDP->checkfreq < (int)(jiffies - UDRS->last_checked)) { + if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) { if (floppy_grab_irq_and_dma()) { return 1; } @@ -4432,6 +4446,13 @@ static int floppy_grab_irq_and_dma(void) return 0; } spin_unlock_irqrestore(&floppy_usage_lock, flags); + + /* + * We might have scheduled a free_irq(), wait it to + * drain first: + */ + flush_scheduled_work(); + if (fd_request_irq()) { DPRINT("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ); @@ -4521,7 +4542,7 @@ static void floppy_release_irq_and_dma(void) if (irqdma_allocated) { fd_disable_dma(); fd_free_dma(); - fd_free_irq(); + schedule_work(&fd_free_irq_work); irqdma_allocated = 0; } set_dor(0, ~0, 8); @@ -4593,7 +4614,7 @@ static void __init parse_floppy_cfg_string(char *cfg) } } -int init_module(void) +int __init init_module(void) { if (floppy) parse_floppy_cfg_string(floppy); @@ -4632,6 +4653,8 @@ void cleanup_module(void) /* eject disk, if any */ fd_eject(0); + flush_scheduled_work(); /* fd_free_irq() might be pending */ + wait_for_completion(&device_release); } |