diff options
author | Ingo Molnar <mingo@elte.hu> | 2006-03-26 04:36:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-26 11:56:53 -0500 |
commit | 6dc659d813fdd1789e605d69d0b8762d284e8c60 (patch) | |
tree | 3eda05a63e1ed271d8382ca4de3315d1e1c19a24 /drivers | |
parent | 36ddf5bbdea7ba4582abc62f106f0f0e9f0b6b91 (diff) |
[PATCH] drivers/block/floppy.c: dont free_irq() from irq context
free_irq() should not be executed from softirq context.
Found by the lock validator. The fix is to push fd_free_irq() into
keventd. The code validates fine with this patch applied.
(akpm: this is revolting, but so is floppy.c)
[akpm@osdl.org: added flush_scheduled_work()]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/floppy.c | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 840919bba76c..d3ad9081697e 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c | |||
@@ -250,6 +250,18 @@ static int irqdma_allocated; | |||
250 | #include <linux/cdrom.h> /* for the compatibility eject ioctl */ | 250 | #include <linux/cdrom.h> /* for the compatibility eject ioctl */ |
251 | #include <linux/completion.h> | 251 | #include <linux/completion.h> |
252 | 252 | ||
253 | /* | ||
254 | * Interrupt freeing also means /proc VFS work - dont do it | ||
255 | * from interrupt context. We push this work into keventd: | ||
256 | */ | ||
257 | static void fd_free_irq_fn(void *data) | ||
258 | { | ||
259 | fd_free_irq(); | ||
260 | } | ||
261 | |||
262 | static DECLARE_WORK(fd_free_irq_work, fd_free_irq_fn, NULL); | ||
263 | |||
264 | |||
253 | static struct request *current_req; | 265 | static struct request *current_req; |
254 | static struct request_queue *floppy_queue; | 266 | static struct request_queue *floppy_queue; |
255 | static void do_fd_request(request_queue_t * q); | 267 | static void do_fd_request(request_queue_t * q); |
@@ -4433,6 +4445,13 @@ static int floppy_grab_irq_and_dma(void) | |||
4433 | return 0; | 4445 | return 0; |
4434 | } | 4446 | } |
4435 | spin_unlock_irqrestore(&floppy_usage_lock, flags); | 4447 | spin_unlock_irqrestore(&floppy_usage_lock, flags); |
4448 | |||
4449 | /* | ||
4450 | * We might have scheduled a free_irq(), wait it to | ||
4451 | * drain first: | ||
4452 | */ | ||
4453 | flush_scheduled_work(); | ||
4454 | |||
4436 | if (fd_request_irq()) { | 4455 | if (fd_request_irq()) { |
4437 | DPRINT("Unable to grab IRQ%d for the floppy driver\n", | 4456 | DPRINT("Unable to grab IRQ%d for the floppy driver\n", |
4438 | FLOPPY_IRQ); | 4457 | FLOPPY_IRQ); |
@@ -4522,7 +4541,7 @@ static void floppy_release_irq_and_dma(void) | |||
4522 | if (irqdma_allocated) { | 4541 | if (irqdma_allocated) { |
4523 | fd_disable_dma(); | 4542 | fd_disable_dma(); |
4524 | fd_free_dma(); | 4543 | fd_free_dma(); |
4525 | fd_free_irq(); | 4544 | schedule_work(&fd_free_irq_work); |
4526 | irqdma_allocated = 0; | 4545 | irqdma_allocated = 0; |
4527 | } | 4546 | } |
4528 | set_dor(0, ~0, 8); | 4547 | set_dor(0, ~0, 8); |
@@ -4633,6 +4652,8 @@ void cleanup_module(void) | |||
4633 | /* eject disk, if any */ | 4652 | /* eject disk, if any */ |
4634 | fd_eject(0); | 4653 | fd_eject(0); |
4635 | 4654 | ||
4655 | flush_scheduled_work(); /* fd_free_irq() might be pending */ | ||
4656 | |||
4636 | wait_for_completion(&device_release); | 4657 | wait_for_completion(&device_release); |
4637 | } | 4658 | } |
4638 | 4659 | ||