[BLOCK] limit request_fn recursion

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>

authored by

Jens Axboe and committed by
Linus Torvalds
dac07ec1 f358166a

+22 -3
+7 -1
block/elevator.c
··· 333 333 { 334 334 struct list_head *pos; 335 335 unsigned ordseq; 336 + int unplug_it = 1; 336 337 337 338 blk_add_trace_rq(q, rq, BLK_TA_INSERT); 338 339 ··· 400 399 } 401 400 402 401 list_add_tail(&rq->queuelist, pos); 402 + /* 403 + * most requeues happen because of a busy condition, don't 404 + * force unplug of the queue for that case. 405 + */ 406 + unplug_it = 0; 403 407 break; 404 408 405 409 default: ··· 413 407 BUG(); 414 408 } 415 409 416 - if (blk_queue_plugged(q)) { 410 + if (unplug_it && blk_queue_plugged(q)) { 417 411 int nrq = q->rq.count[READ] + q->rq.count[WRITE] 418 412 - q->in_flight; 419 413
+15 -2
block/ll_rw_blk.c
··· 1732 1732 1733 1733 spin_lock_irqsave(q->queue_lock, flags); 1734 1734 blk_remove_plug(q); 1735 - if (!elv_queue_empty(q)) 1736 - q->request_fn(q); 1735 + 1736 + /* 1737 + * Only recurse once to avoid overrunning the stack, let the unplug 1738 + * handling reinvoke the handler shortly if we already got there. 1739 + */ 1740 + if (!elv_queue_empty(q)) { 1741 + if (!test_and_set_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) { 1742 + q->request_fn(q); 1743 + clear_bit(QUEUE_FLAG_REENTER, &q->queue_flags); 1744 + } else { 1745 + blk_plug_device(q); 1746 + kblockd_schedule_work(&q->unplug_work); 1747 + } 1748 + } 1749 + 1737 1750 spin_unlock_irqrestore(q->queue_lock, flags); 1738 1751 } 1739 1752 EXPORT_SYMBOL(blk_run_queue);