diff options
author | Tejun Heo <tj@kernel.org> | 2014-08-16 08:02:24 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2014-08-21 21:37:51 -0400 |
commit | cddd5d17642cc6881352732693c2ae6930e9ce65 (patch) | |
tree | 5fad9444dbe5b3d2347d43c2bfe77383573b9031 /block | |
parent | a68aafa5b297d99c2d0c38689089a752126e9e79 (diff) |
blk-mq: blk_mq_freeze_queue() should allow nesting
While converting to percpu_ref for freezing, add703fda981 ("blk-mq:
use percpu_ref for mq usage count") incorrectly made
blk_mq_freeze_queue() misbehave when freezing is nested due to
percpu_ref_kill() being invoked on an already killed ref.
Fix it by making blk_mq_freeze_queue() kill and kick the queue only
for the outermost freeze attempt. All the nested ones can simply wait
for the ref to reach zero.
While at it, remove unnecessary @wake initialization from
blk_mq_unfreeze_queue().
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/blk-mq.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/block/blk-mq.c b/block/blk-mq.c index a0565bb20fd5..7950f8d7c1bb 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c | |||
@@ -112,18 +112,22 @@ static void blk_mq_usage_counter_release(struct percpu_ref *ref) | |||
112 | */ | 112 | */ |
113 | void blk_mq_freeze_queue(struct request_queue *q) | 113 | void blk_mq_freeze_queue(struct request_queue *q) |
114 | { | 114 | { |
115 | bool freeze; | ||
116 | |||
115 | spin_lock_irq(q->queue_lock); | 117 | spin_lock_irq(q->queue_lock); |
116 | q->mq_freeze_depth++; | 118 | freeze = !q->mq_freeze_depth++; |
117 | spin_unlock_irq(q->queue_lock); | 119 | spin_unlock_irq(q->queue_lock); |
118 | 120 | ||
119 | percpu_ref_kill(&q->mq_usage_counter); | 121 | if (freeze) { |
120 | blk_mq_run_queues(q, false); | 122 | percpu_ref_kill(&q->mq_usage_counter); |
123 | blk_mq_run_queues(q, false); | ||
124 | } | ||
121 | wait_event(q->mq_freeze_wq, percpu_ref_is_zero(&q->mq_usage_counter)); | 125 | wait_event(q->mq_freeze_wq, percpu_ref_is_zero(&q->mq_usage_counter)); |
122 | } | 126 | } |
123 | 127 | ||
124 | static void blk_mq_unfreeze_queue(struct request_queue *q) | 128 | static void blk_mq_unfreeze_queue(struct request_queue *q) |
125 | { | 129 | { |
126 | bool wake = false; | 130 | bool wake; |
127 | 131 | ||
128 | spin_lock_irq(q->queue_lock); | 132 | spin_lock_irq(q->queue_lock); |
129 | wake = !--q->mq_freeze_depth; | 133 | wake = !--q->mq_freeze_depth; |