[PATCH] cciss: fix stall with softirq handling and CFQ
authorJens Axboe <axboe@suse.de>
Tue, 25 Jul 2006 13:02:48 +0000 (15:02 +0200)
committerJens Axboe <axboe@suse.de>
Tue, 25 Jul 2006 13:02:48 +0000 (15:02 +0200)
We need to postpone the queue startup until after the softirq
handler has actually finished some requests, otherwise we could
be racing with cciss_softirq_done() and not actually restart
the queue handling.

Signed-off-by: Jens Axboe <axboe@suse.de>
drivers/block/cciss.c

index 1c4df22..7b0eca7 100644 (file)
@@ -1233,6 +1233,50 @@ static inline void complete_buffers(struct bio *bio, int status)
        }
 }
 
+static void cciss_check_queues(ctlr_info_t *h)
+{
+       int start_queue = h->next_to_run;
+       int i;
+
+       /* check to see if we have maxed out the number of commands that can
+        * be placed on the queue.  If so then exit.  We do this check here
+        * in case the interrupt we serviced was from an ioctl and did not
+        * free any new commands.
+        */
+       if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
+               return;
+
+       /* We have room on the queue for more commands.  Now we need to queue
+        * them up.  We will also keep track of the next queue to run so
+        * that every queue gets a chance to be started first.
+        */
+       for (i = 0; i < h->highest_lun + 1; i++) {
+               int curr_queue = (start_queue + i) % (h->highest_lun + 1);
+               /* make sure the disk has been added and the drive is real
+                * because this can be called from the middle of init_one.
+                */
+               if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
+                       continue;
+               blk_start_queue(h->gendisk[curr_queue]->queue);
+
+               /* check to see if we have maxed out the number of commands
+                * that can be placed on the queue.
+                */
+               if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) {
+                       if (curr_queue == start_queue) {
+                               h->next_to_run =
+                                   (start_queue + 1) % (h->highest_lun + 1);
+                               break;
+                       } else {
+                               h->next_to_run = curr_queue;
+                               break;
+                       }
+               } else {
+                       curr_queue = (curr_queue + 1) % (h->highest_lun + 1);
+               }
+       }
+}
+
 static void cciss_softirq_done(struct request *rq)
 {
        CommandList_struct *cmd = rq->completion_data;
@@ -1264,6 +1308,7 @@ static void cciss_softirq_done(struct request *rq)
        spin_lock_irqsave(&h->lock, flags);
        end_that_request_last(rq, rq->errors);
        cmd_free(h, cmd, 1);
+       cciss_check_queues(h);
        spin_unlock_irqrestore(&h->lock, flags);
 }
 
@@ -2528,8 +2573,6 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
        CommandList_struct *c;
        unsigned long flags;
        __u32 a, a1, a2;
-       int j;
-       int start_queue = h->next_to_run;
 
        if (interrupt_not_for_us(h))
                return IRQ_NONE;
@@ -2588,45 +2631,6 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
                }
        }
 
-       /* check to see if we have maxed out the number of commands that can
-        * be placed on the queue.  If so then exit.  We do this check here
-        * in case the interrupt we serviced was from an ioctl and did not
-        * free any new commands.
-        */
-       if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
-               goto cleanup;
-
-       /* We have room on the queue for more commands.  Now we need to queue
-        * them up.  We will also keep track of the next queue to run so
-        * that every queue gets a chance to be started first.
-        */
-       for (j = 0; j < h->highest_lun + 1; j++) {
-               int curr_queue = (start_queue + j) % (h->highest_lun + 1);
-               /* make sure the disk has been added and the drive is real
-                * because this can be called from the middle of init_one.
-                */
-               if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
-                       continue;
-               blk_start_queue(h->gendisk[curr_queue]->queue);
-
-               /* check to see if we have maxed out the number of commands
-                * that can be placed on the queue.
-                */
-               if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) {
-                       if (curr_queue == start_queue) {
-                               h->next_to_run =
-                                   (start_queue + 1) % (h->highest_lun + 1);
-                               goto cleanup;
-                       } else {
-                               h->next_to_run = curr_queue;
-                               goto cleanup;
-                       }
-               } else {
-                       curr_queue = (curr_queue + 1) % (h->highest_lun + 1);
-               }
-       }
-
-      cleanup:
        spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
        return IRQ_HANDLED;
 }