[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>
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 840919b..d3ad908 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -250,6 +250,18 @@
 #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);
@@ -4433,6 +4445,13 @@
 		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);
@@ -4522,7 +4541,7 @@
 	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);
@@ -4633,6 +4652,8 @@
 	/* eject disk, if any */
 	fd_eject(0);
 
+	flush_scheduled_work();		/* fd_free_irq() might be pending */
+
 	wait_for_completion(&device_release);
 }