[PATCH] floppy smp (and misc) fixes

From: Jens Axboe (axboe@suse.de)
Date: Wed Jun 04 2003 - 08:10:12 EST


Hi,

There are several smp races in the 2.4.21-rc floppy driver that can
cause a process writing/reading to the drive to stall forever. Basically
it quits out of request handling with requests pending. I verified that
these requests were not seen by the floppy driver yet. It went to unlock
the drive in a bad state.

Additionally, I put a smaller limit on requests sizes. It doesn't make
any sense to have 128 * 255 sectors pending in the write queue (about
16MiB of data) and it just causes huge latencies when someone wants to
stop a dd, for instance.

With this patch I cannot reproduce any more floppy hangs on a 4-way.

--- drivers/block/floppy.c~ 2003-06-04 14:58:50.000000000 +0200
+++ drivers/block/floppy.c 2003-06-04 14:59:33.000000000 +0200
@@ -482,6 +482,7 @@
 
 static int floppy_sizes[256];
 static int floppy_blocksizes[256];
+static int floppy_maxsectors[256];
 
 /*
  * The driver is trying to determine the correct media format
@@ -622,7 +623,8 @@
 static void is_alive(const char *message)
 {
         /* this routine checks whether the floppy driver is "alive" */
- if (fdc_busy && command_status < 2 && !timer_pending(&fd_timeout)){
+ if (test_bit(0, &fdc_busy) && command_status < 2
+ && !timer_pending(&fd_timeout)){
                 DPRINT("timeout handler died: %s\n",message);
         }
 }
@@ -650,7 +652,7 @@
 #define CURRENTD -1
 #define MAXTIMEOUT -2
 
-static void reschedule_timeout(int drive, const char *message, int marg)
+static void __reschedule_timeout(int drive, const char *message, int marg)
 {
         if (drive == CURRENTD)
                 drive = current_drive;
@@ -669,6 +671,16 @@
         timeout_message = message;
 }
 
+
+static void reschedule_timeout(int drive, const char *message, int marg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ __reschedule_timeout(drive, message, marg);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
 static int maximum(int a, int b)
 {
         if (a > b)
@@ -897,7 +909,7 @@
         }
         command_status = FD_COMMAND_NONE;
 
- reschedule_timeout(drive, "lock fdc", 0);
+ __reschedule_timeout(drive, "lock fdc", 0);
         set_fdc(drive);
         return 0;
 }
@@ -911,17 +923,23 @@
 /* unlocks the driver */
 static inline void unlock_fdc(void)
 {
+ unsigned long flags;
+
         raw_cmd = 0;
- if (!fdc_busy)
+ if (!test_bit(0, &fdc_busy))
                 DPRINT("FDC access conflict!\n");
 
         if (DEVICE_INTR)
                 DPRINT("device interrupt still active at FDC release: %p!\n",
                         DEVICE_INTR);
         command_status = FD_COMMAND_NONE;
+ spin_lock_irqsave(&io_request_lock, flags);
         del_timer(&fd_timeout);
         cont = NULL;
         clear_bit(0, &fdc_busy);
+ if (!QUEUE_EMPTY)
+ do_fd_request(BLK_DEFAULT_QUEUE(MAJOR_NR));
+ spin_unlock_irqrestore(&io_request_lock, flags);
         floppy_release_irq_and_dma();
         wake_up(&fdc_wait);
 }
@@ -1000,9 +1018,13 @@
 
 static void cancel_activity(void)
 {
+ unsigned long flags;
+
+ spin_lock_irqsave(&io_request_lock, flags);
         CLEAR_INTR;
         floppy_tq.routine = (void *)(void *) empty;
         del_timer(&fd_timer);
+ spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 /* this function makes sure that the disk stays in the drive during the
@@ -2986,7 +3008,7 @@
                 printk("sect=%ld cmd=%d\n", CURRENT->sector, CURRENT->cmd);
                 return;
         }
- if (fdc_busy){
+ if (test_bit(0, &fdc_busy)) {
                 /* fdc busy, this new request will be treated when the
                    current one is done */
                 is_alive("do fd request, old request running");
@@ -3878,7 +3900,7 @@
                         /* auto-sensing */
                         int size = floppy_blocksizes[MINOR(dev)];
                         if (!size)
- size = 1024;
+ size = 512;
                         if (!(bh = getblk(dev,0,size))){
                                 process_fd_request();
                                 return -ENXIO;
@@ -4170,14 +4192,19 @@
                 return -EBUSY;
         }
 
- for (i=0; i<256; i++)
+ for (i=0; i<256; i++) {
                 if (ITYPE(i))
                         floppy_sizes[i] = (floppy_type[ITYPE(i)].size+1) >> 1;
                 else
                         floppy_sizes[i] = MAX_DISK_SIZE;
 
+ floppy_blocksizes[i] = 512;
+ floppy_maxsectors[i] = 64;
+ }
+
         blk_size[MAJOR_NR] = floppy_sizes;
         blksize_size[MAJOR_NR] = floppy_blocksizes;
+ max_sectors[MAJOR_NR] = floppy_maxsectors;
         blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
         reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
         config_types();

-- 
Jens Axboe

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Jun 07 2003 - 22:00:23 EST