[PATCH] cciss: fix stall with softirq handling and CFQ
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>
This commit is contained in:
Родитель
b4e54de8d3
Коммит
7b30f09245
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче