Skip to content

Commit

Permalink
[BLOCK] limit request_fn recursion
Browse files Browse the repository at this point in the history
Don't recurse back into the driver even if the unplug threshold is met,
when the driver asks for a requeue. This is both silly from a logical
point of view (requeues typically happen due to driver/hardware
shortage), and also dangerous since we could hit an endless request_fn
-> requeue -> unplug -> request_fn loop and crash on stack overrun.

Also limit blk_run_queue() to one level of recursion, similar to how
blk_start_queue() works.

This patch fixed a real problem with SLES10 and lpfc, and it could hit
any SCSI lld that returns non-zero from it's ->queuecommand() handler.

Signed-off-by: Jens Axboe <axboe@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Jens Axboe authored and Linus Torvalds committed May 11, 2006
1 parent f358166 commit dac07ec
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 3 deletions.
8 changes: 7 additions & 1 deletion block/elevator.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where)
{
struct list_head *pos;
unsigned ordseq;
int unplug_it = 1;

blk_add_trace_rq(q, rq, BLK_TA_INSERT);

Expand Down Expand Up @@ -399,6 +400,11 @@ void elv_insert(request_queue_t *q, struct request *rq, int where)
}

list_add_tail(&rq->queuelist, pos);
/*
* most requeues happen because of a busy condition, don't
* force unplug of the queue for that case.
*/
unplug_it = 0;
break;

default:
Expand All @@ -407,7 +413,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where)
BUG();
}

if (blk_queue_plugged(q)) {
if (unplug_it && blk_queue_plugged(q)) {
int nrq = q->rq.count[READ] + q->rq.count[WRITE]
- q->in_flight;

Expand Down
17 changes: 15 additions & 2 deletions block/ll_rw_blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1732,8 +1732,21 @@ void blk_run_queue(struct request_queue *q)

spin_lock_irqsave(q->queue_lock, flags);
blk_remove_plug(q);
if (!elv_queue_empty(q))
q->request_fn(q);

/*
* Only recurse once to avoid overrunning the stack, let the unplug
* handling reinvoke the handler shortly if we already got there.
*/
if (!elv_queue_empty(q)) {
if (!test_and_set_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) {
q->request_fn(q);
clear_bit(QUEUE_FLAG_REENTER, &q->queue_flags);
} else {
blk_plug_device(q);
kblockd_schedule_work(&q->unplug_work);
}
}

spin_unlock_irqrestore(q->queue_lock, flags);
}
EXPORT_SYMBOL(blk_run_queue);
Expand Down

0 comments on commit dac07ec

Please sign in to comment.