Commit 255bb490 authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe

block: blk-flush shouldn't call directly into q->request_fn() __blk_run_queue()

blk-flush decomposes a flush into sequence of multiple requests.  On
completion of a request, the next one is queued; however, block layer
must not implicitly call into q->request_fn() directly from completion
path.  This makes the queue behave unexpectedly when seen from the
drivers and violates the assumption that q->request_fn() is called
with process context + queue_lock.

This patch makes blk-flush the following two changes to make sure
q->request_fn() is not called directly from request completion path.

- blk_flush_complete_seq_end_io() now asks __blk_run_queue() to always
  use kblockd instead of calling directly into q->request_fn().

- queue_next_fseq() uses ELEVATOR_INSERT_REQUEUE instead of
  ELEVATOR_INSERT_FRONT so that elv_insert() doesn't try to unplug the
  request queue directly.

Reported by Jan in the following threads.

 http://thread.gmane.org/gmane.linux.ide/48778
 http://thread.gmane.org/gmane.linux.ide/48786

stable: applicable to v2.6.37.
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Reported-by: default avatarJan Beulich <JBeulich@novell.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: stable@kernel.org
Signed-off-by: default avatarJens Axboe <jaxboe@fusionio.com>
parent 1654e741
...@@ -66,10 +66,12 @@ static void blk_flush_complete_seq_end_io(struct request_queue *q, ...@@ -66,10 +66,12 @@ static void blk_flush_complete_seq_end_io(struct request_queue *q,
/* /*
* Moving a request silently to empty queue_head may stall the * Moving a request silently to empty queue_head may stall the
* queue. Kick the queue in those cases. * queue. Kick the queue in those cases. This function is called
* from request completion path and calling directly into
* request_fn may confuse the driver. Always use kblockd.
*/ */
if (was_empty && next_rq) if (was_empty && next_rq)
__blk_run_queue(q, false); __blk_run_queue(q, true);
} }
static void pre_flush_end_io(struct request *rq, int error) static void pre_flush_end_io(struct request *rq, int error)
...@@ -130,7 +132,7 @@ static struct request *queue_next_fseq(struct request_queue *q) ...@@ -130,7 +132,7 @@ static struct request *queue_next_fseq(struct request_queue *q)
BUG(); BUG();
} }
elv_insert(q, rq, ELEVATOR_INSERT_FRONT); elv_insert(q, rq, ELEVATOR_INSERT_REQUEUE);
return rq; return rq;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment