]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
swim3: fix interruptible_sleep_on race
authorArnd Bergmann <arnd@arndb.de>
Wed, 26 Feb 2014 11:01:44 +0000 (12:01 +0100)
committerJens Axboe <axboe@fb.com>
Thu, 13 Mar 2014 20:56:38 +0000 (14:56 -0600)
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>
drivers/block/swim3.c

index 20e061c3e02329c0662b4ce8fac0ad2b82d9c8ce..c74f7b56e7c40106ddd5ebde357d161cf7929361 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/wait.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
 #include <asm/prom.h>
@@ -840,14 +841,17 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
        spin_lock_irqsave(&swim3_lock, flags);
        if (fs->state != idle && fs->state != available) {
                ++fs->wanted;
-               while (fs->state != available) {
+               /* this will enable irqs in order to sleep */
+               if (!interruptible)
+                       wait_event_lock_irq(fs->wait,
+                                        fs->state == available,
+                                        swim3_lock);
+               else if (wait_event_interruptible_lock_irq(fs->wait,
+                                       fs->state == available,
+                                       swim3_lock)) {
+                       --fs->wanted;
                        spin_unlock_irqrestore(&swim3_lock, flags);
-                       if (interruptible && signal_pending(current)) {
-                               --fs->wanted;
-                               return -EINTR;
-                       }
-                       interruptible_sleep_on(&fs->wait);
-                       spin_lock_irqsave(&swim3_lock, flags);
+                       return -EINTR;
                }
                --fs->wanted;
        }