diff options
author | Arnd Bergmann <arnd@arndb.de> | 2014-02-26 06:01:44 -0500 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2014-03-13 16:56:38 -0400 |
commit | 106fd892bc714a9b7c28daba98a3623a41c32f1a (patch) | |
tree | aaa08a49fe4c4bcb6ae342649cde84cbd879521e | |
parent | 7b8a3d22ba93682a542a445ef43d03f495cdf3d6 (diff) |
swim3: fix interruptible_sleep_on race
interruptible_sleep_on is racy and going away. This replaces the one
caller in the swim3 driver with the equivalent race-free
wait_event_interruptible call. Since we're here already, this
also fixes the case where we get interrupted from atomic context,
which used to just spin in the loop.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r-- | drivers/block/swim3.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index 20e061c3e023..c74f7b56e7c4 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/mutex.h> | 30 | #include <linux/mutex.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/spinlock.h> | 32 | #include <linux/spinlock.h> |
33 | #include <linux/wait.h> | ||
33 | #include <asm/io.h> | 34 | #include <asm/io.h> |
34 | #include <asm/dbdma.h> | 35 | #include <asm/dbdma.h> |
35 | #include <asm/prom.h> | 36 | #include <asm/prom.h> |
@@ -840,14 +841,17 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state, | |||
840 | spin_lock_irqsave(&swim3_lock, flags); | 841 | spin_lock_irqsave(&swim3_lock, flags); |
841 | if (fs->state != idle && fs->state != available) { | 842 | if (fs->state != idle && fs->state != available) { |
842 | ++fs->wanted; | 843 | ++fs->wanted; |
843 | while (fs->state != available) { | 844 | /* this will enable irqs in order to sleep */ |
845 | if (!interruptible) | ||
846 | wait_event_lock_irq(fs->wait, | ||
847 | fs->state == available, | ||
848 | swim3_lock); | ||
849 | else if (wait_event_interruptible_lock_irq(fs->wait, | ||
850 | fs->state == available, | ||
851 | swim3_lock)) { | ||
852 | --fs->wanted; | ||
844 | spin_unlock_irqrestore(&swim3_lock, flags); | 853 | spin_unlock_irqrestore(&swim3_lock, flags); |
845 | if (interruptible && signal_pending(current)) { | 854 | return -EINTR; |
846 | --fs->wanted; | ||
847 | return -EINTR; | ||
848 | } | ||
849 | interruptible_sleep_on(&fs->wait); | ||
850 | spin_lock_irqsave(&swim3_lock, flags); | ||
851 | } | 855 | } |
852 | --fs->wanted; | 856 | --fs->wanted; |
853 | } | 857 | } |