Commit 3e541a4a authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] lockdep: floppy.c irq release fix

The lock validator triggered a number of bugs in the floppy driver, all
related to the floppy driver allocating and freeing irq and dma resources from
interrupt context.  The initial solution was to use schedule_work() to push
this into process context, but this caused further problems: for example the
current floppy driver in -mm2 is totally broken and all floppy commands time
out with an error.  (as reported by Barry K.  Nathan)

This patch tries another solution: simply get rid of all that dynamic IRQ and
DMA allocation/freeing.  I doubt it made much sense back in the heydays of
floppies (if two devices raced for DMA or IRQ resources then we didnt handle
those cases too gracefully anyway), and today it makes near zero sense.

So the new code does the simplest and most straightforward thing: allocate IRQ
and DMA resources at module init time, and free them at module removal time.
Dont try to release while the driver is operational.  This, besides making the
floppy driver functional again has an added bonus, floppy IRQ stats are
finally persistent and visible in /proc/interrupts:

  6: 63 XT-PIC-level floppy

Besides normal floppy IO i have also tested IO error handling, motor-off
timeouts, etc.  - and everything seems to be working fine.
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarArjan van de Ven <arjan@linux.intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 5863aa65
...@@ -249,18 +249,6 @@ static int irqdma_allocated; ...@@ -249,18 +249,6 @@ static int irqdma_allocated;
#include <linux/cdrom.h> /* for the compatibility eject ioctl */ #include <linux/cdrom.h> /* for the compatibility eject ioctl */
#include <linux/completion.h> #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 *current_req;
static struct request_queue *floppy_queue; static struct request_queue *floppy_queue;
static void do_fd_request(request_queue_t * q); static void do_fd_request(request_queue_t * q);
...@@ -826,15 +814,6 @@ static int set_dor(int fdc, char mask, char data) ...@@ -826,15 +814,6 @@ static int set_dor(int fdc, char mask, char data)
UDRS->select_date = jiffies; UDRS->select_date = jiffies;
} }
} }
/*
* We should propagate failures to grab the resources back
* nicely from here. Actually we ought to rewrite the fd
* driver some day too.
*/
if (newdor & FLOPPY_MOTOR_MASK)
floppy_grab_irq_and_dma();
if (olddor & FLOPPY_MOTOR_MASK)
floppy_release_irq_and_dma();
return olddor; return olddor;
} }
...@@ -892,8 +871,6 @@ static int _lock_fdc(int drive, int interruptible, int line) ...@@ -892,8 +871,6 @@ static int _lock_fdc(int drive, int interruptible, int line)
line); line);
return -1; return -1;
} }
if (floppy_grab_irq_and_dma() == -1)
return -EBUSY;
if (test_and_set_bit(0, &fdc_busy)) { if (test_and_set_bit(0, &fdc_busy)) {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
...@@ -915,6 +892,8 @@ static int _lock_fdc(int drive, int interruptible, int line) ...@@ -915,6 +892,8 @@ static int _lock_fdc(int drive, int interruptible, int line)
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
remove_wait_queue(&fdc_wait, &wait); remove_wait_queue(&fdc_wait, &wait);
flush_scheduled_work();
} }
command_status = FD_COMMAND_NONE; command_status = FD_COMMAND_NONE;
...@@ -948,7 +927,6 @@ static inline void unlock_fdc(void) ...@@ -948,7 +927,6 @@ static inline void unlock_fdc(void)
if (elv_next_request(floppy_queue)) if (elv_next_request(floppy_queue))
do_fd_request(floppy_queue); do_fd_request(floppy_queue);
spin_unlock_irqrestore(&floppy_lock, flags); spin_unlock_irqrestore(&floppy_lock, flags);
floppy_release_irq_and_dma();
wake_up(&fdc_wait); wake_up(&fdc_wait);
} }
...@@ -3694,8 +3672,8 @@ static int floppy_release(struct inode *inode, struct file *filp) ...@@ -3694,8 +3672,8 @@ static int floppy_release(struct inode *inode, struct file *filp)
} }
if (!UDRS->fd_ref) if (!UDRS->fd_ref)
opened_bdev[drive] = NULL; opened_bdev[drive] = NULL;
floppy_release_irq_and_dma();
mutex_unlock(&open_lock); mutex_unlock(&open_lock);
return 0; return 0;
} }
...@@ -3726,9 +3704,6 @@ static int floppy_open(struct inode *inode, struct file *filp) ...@@ -3726,9 +3704,6 @@ static int floppy_open(struct inode *inode, struct file *filp)
if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (filp->f_flags & O_EXCL))) if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
goto out2; goto out2;
if (floppy_grab_irq_and_dma())
goto out2;
if (filp->f_flags & O_EXCL) if (filp->f_flags & O_EXCL)
UDRS->fd_ref = -1; UDRS->fd_ref = -1;
else else
...@@ -3805,7 +3780,6 @@ out: ...@@ -3805,7 +3780,6 @@ out:
UDRS->fd_ref--; UDRS->fd_ref--;
if (!UDRS->fd_ref) if (!UDRS->fd_ref)
opened_bdev[drive] = NULL; opened_bdev[drive] = NULL;
floppy_release_irq_and_dma();
out2: out2:
mutex_unlock(&open_lock); mutex_unlock(&open_lock);
return res; return res;
...@@ -3822,14 +3796,9 @@ static int check_floppy_change(struct gendisk *disk) ...@@ -3822,14 +3796,9 @@ static int check_floppy_change(struct gendisk *disk)
return 1; return 1;
if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) { if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
if (floppy_grab_irq_and_dma()) {
return 1;
}
lock_fdc(drive, 0); lock_fdc(drive, 0);
poll_drive(0, 0); poll_drive(0, 0);
process_fd_request(); process_fd_request();
floppy_release_irq_and_dma();
} }
if (UTESTF(FD_DISK_CHANGED) || if (UTESTF(FD_DISK_CHANGED) ||
...@@ -4346,7 +4315,6 @@ static int __init floppy_init(void) ...@@ -4346,7 +4315,6 @@ static int __init floppy_init(void)
fdc = 0; fdc = 0;
del_timer(&fd_timeout); del_timer(&fd_timeout);
current_drive = 0; current_drive = 0;
floppy_release_irq_and_dma();
initialising = 0; initialising = 0;
if (have_no_fdc) { if (have_no_fdc) {
DPRINT("no floppy controllers found\n"); DPRINT("no floppy controllers found\n");
...@@ -4504,7 +4472,7 @@ static void floppy_release_irq_and_dma(void) ...@@ -4504,7 +4472,7 @@ static void floppy_release_irq_and_dma(void)
if (irqdma_allocated) { if (irqdma_allocated) {
fd_disable_dma(); fd_disable_dma();
fd_free_dma(); fd_free_dma();
schedule_work(&fd_free_irq_work); fd_free_irq();
irqdma_allocated = 0; irqdma_allocated = 0;
} }
set_dor(0, ~0, 8); set_dor(0, ~0, 8);
...@@ -4600,8 +4568,6 @@ void cleanup_module(void) ...@@ -4600,8 +4568,6 @@ void cleanup_module(void)
/* eject disk, if any */ /* eject disk, if any */
fd_eject(0); fd_eject(0);
flush_scheduled_work(); /* fd_free_irq() might be pending */
wait_for_completion(&device_release); wait_for_completion(&device_release);
} }
......
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