Commit b855b04a authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe

block: blk-throttle should be drained regardless of q->elevator

Currently, blk_cleanup_queue() doesn't call elv_drain_elevator() if
q->elevator doesn't exist; however, bio based drivers don't have
elevator initialized but can still use blk-throttle.  This patch moves
q->elevator test inside blk_drain_queue() such that only
elv_drain_elevator() is skipped if !q->elevator.

-v2: loop can have registered queue which has NULL request_fn.  Make
     sure we don't call into __blk_run_queue() in such cases.
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Reported-by: default avatarVivek Goyal <vgoyal@redhat.com>

Fold in bug fix from Vivek.
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent ea5f4db8
...@@ -365,17 +365,24 @@ void blk_drain_queue(struct request_queue *q, bool drain_all) ...@@ -365,17 +365,24 @@ void blk_drain_queue(struct request_queue *q, bool drain_all)
spin_lock_irq(q->queue_lock); spin_lock_irq(q->queue_lock);
elv_drain_elevator(q); /*
* The caller might be trying to drain @q before its
* elevator is initialized.
*/
if (q->elevator)
elv_drain_elevator(q);
if (drain_all) if (drain_all)
blk_throtl_drain(q); blk_throtl_drain(q);
/* /*
* This function might be called on a queue which failed * This function might be called on a queue which failed
* driver init after queue creation. Some drivers * driver init after queue creation or is not yet fully
* (e.g. fd) get unhappy in such cases. Kick queue iff * active yet. Some drivers (e.g. fd and loop) get unhappy
* dispatch queue has something on it. * in such cases. Kick queue iff dispatch queue has
* something on it and @q has request_fn set.
*/ */
if (!list_empty(&q->queue_head)) if (!list_empty(&q->queue_head) && q->request_fn)
__blk_run_queue(q); __blk_run_queue(q);
drain |= q->rq.elvpriv; drain |= q->rq.elvpriv;
...@@ -428,13 +435,8 @@ void blk_cleanup_queue(struct request_queue *q) ...@@ -428,13 +435,8 @@ void blk_cleanup_queue(struct request_queue *q)
spin_unlock_irq(lock); spin_unlock_irq(lock);
mutex_unlock(&q->sysfs_lock); mutex_unlock(&q->sysfs_lock);
/* /* drain all requests queued before DEAD marking */
* Drain all requests queued before DEAD marking. The caller might blk_drain_queue(q, true);
* be trying to tear down @q before its elevator is initialized, in
* which case we don't want to call into draining.
*/
if (q->elevator)
blk_drain_queue(q, true);
/* @q won't process any more request, flush async actions */ /* @q won't process any more request, flush async actions */
del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer); del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);
...@@ -504,6 +506,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) ...@@ -504,6 +506,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
setup_timer(&q->backing_dev_info.laptop_mode_wb_timer, setup_timer(&q->backing_dev_info.laptop_mode_wb_timer,
laptop_mode_timer_fn, (unsigned long) q); laptop_mode_timer_fn, (unsigned long) q);
setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
INIT_LIST_HEAD(&q->queue_head);
INIT_LIST_HEAD(&q->timeout_list); INIT_LIST_HEAD(&q->timeout_list);
INIT_LIST_HEAD(&q->icq_list); INIT_LIST_HEAD(&q->icq_list);
INIT_LIST_HEAD(&q->flush_queue[0]); INIT_LIST_HEAD(&q->flush_queue[0]);
......
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