aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2014-02-26 06:01:41 -0500
committerJens Axboe <axboe@fb.com>2014-03-13 16:56:38 -0400
commit7b8a3d22ba93682a542a445ef43d03f495cdf3d6 (patch)
treea4eb23f8700166ded319f7e7352ae527fdf234a7
parent9c552e1ddd3658944787d75d90a42e1a2b74b7ea (diff)
ataflop: fix sleep_on races
sleep_on() is inherently racy, and has been deprecated for a long time. This fixes two instances in the atari floppy driver: * fdc_wait/fdc_busy becomes an open-coded mutex. We cannot use the regular mutex since it gets released in interrupt context. The open-coded version using wait_event() and cmpxchg() is equivalent to the existing code but does the checks atomically, and we can now safely check the condition with irqs enabled. * format_wait becomes a completion, which is the natural structure here. The format ioctl waits for the background task to either complete or abort. This does not attempt to fix the preexisting bug of calling schedule with local interrupts disabled. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Cc: Jens Axboe <axboe@kernel.dk> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Michael Schmitz <schmitz@biophys.uni-duesseldorf.de> Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--drivers/block/ataflop.c16
1 files changed, 8 insertions, 8 deletions
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 0e30c6e5492a..96b629e1f0c9 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -68,6 +68,8 @@
68#include <linux/init.h> 68#include <linux/init.h>
69#include <linux/blkdev.h> 69#include <linux/blkdev.h>
70#include <linux/mutex.h> 70#include <linux/mutex.h>
71#include <linux/completion.h>
72#include <linux/wait.h>
71 73
72#include <asm/atafd.h> 74#include <asm/atafd.h>
73#include <asm/atafdreg.h> 75#include <asm/atafdreg.h>
@@ -301,7 +303,7 @@ module_param_array(UserSteprate, int, NULL, 0);
301/* Synchronization of FDC access. */ 303/* Synchronization of FDC access. */
302static volatile int fdc_busy = 0; 304static volatile int fdc_busy = 0;
303static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); 305static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
304static DECLARE_WAIT_QUEUE_HEAD(format_wait); 306static DECLARE_COMPLETION(format_wait);
305 307
306static unsigned long changed_floppies = 0xff, fake_change = 0; 308static unsigned long changed_floppies = 0xff, fake_change = 0;
307#define CHECK_CHANGE_DELAY HZ/2 309#define CHECK_CHANGE_DELAY HZ/2
@@ -608,7 +610,7 @@ static void fd_error( void )
608 if (IsFormatting) { 610 if (IsFormatting) {
609 IsFormatting = 0; 611 IsFormatting = 0;
610 FormatError = 1; 612 FormatError = 1;
611 wake_up( &format_wait ); 613 complete(&format_wait);
612 return; 614 return;
613 } 615 }
614 616
@@ -650,9 +652,8 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
650 DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n", 652 DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n",
651 drive, desc->track, desc->head, desc->sect_offset )); 653 drive, desc->track, desc->head, desc->sect_offset ));
652 654
655 wait_event(fdc_wait, cmpxchg(&fdc_busy, 0, 1) == 0);
653 local_irq_save(flags); 656 local_irq_save(flags);
654 while( fdc_busy ) sleep_on( &fdc_wait );
655 fdc_busy = 1;
656 stdma_lock(floppy_irq, NULL); 657 stdma_lock(floppy_irq, NULL);
657 atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */ 658 atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */
658 local_irq_restore(flags); 659 local_irq_restore(flags);
@@ -706,7 +707,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc)
706 ReqSide = desc->head; 707 ReqSide = desc->head;
707 do_fd_action( drive ); 708 do_fd_action( drive );
708 709
709 sleep_on( &format_wait ); 710 wait_for_completion(&format_wait);
710 711
711 redo_fd_request(); 712 redo_fd_request();
712 return( FormatError ? -EIO : 0 ); 713 return( FormatError ? -EIO : 0 );
@@ -1229,7 +1230,7 @@ static void fd_writetrack_done( int status )
1229 goto err_end; 1230 goto err_end;
1230 } 1231 }
1231 1232
1232 wake_up( &format_wait ); 1233 complete(&format_wait);
1233 return; 1234 return;
1234 1235
1235 err_end: 1236 err_end:
@@ -1497,8 +1498,7 @@ repeat:
1497void do_fd_request(struct request_queue * q) 1498void do_fd_request(struct request_queue * q)
1498{ 1499{
1499 DPRINT(("do_fd_request for pid %d\n",current->pid)); 1500 DPRINT(("do_fd_request for pid %d\n",current->pid));
1500 while( fdc_busy ) sleep_on( &fdc_wait ); 1501 wait_event(fdc_wait, cmpxchg(&fdc_busy, 0, 1) == 0);
1501 fdc_busy = 1;
1502 stdma_lock(floppy_irq, NULL); 1502 stdma_lock(floppy_irq, NULL);
1503 1503
1504 atari_disable_irq( IRQ_MFP_FDC ); 1504 atari_disable_irq( IRQ_MFP_FDC );