blk-mq: fix a memory ordering bug in blk_mq_queue_enter()
authorTejun Heo <tj@kernel.org>
Wed, 18 Jun 2014 15:21:08 +0000 (11:21 -0400)
committerJens Axboe <axboe@fb.com>
Tue, 1 Jul 2014 16:27:06 +0000 (10:27 -0600)
blk-mq uses a percpu_counter to keep track of how many usages are in
flight.  The percpu_counter is drained while freezing to ensure that
no usage is left in-flight after freezing is complete.

blk_mq_queue_enter/exit() and blk_mq_[un]freeze_queue() implement this
per-cpu gating mechanism; unfortunately, it contains a subtle bug -
smp_wmb() in blk_mq_queue_enter() doesn't prevent prevent the cpu from
fetching @q->bypass_depth before incrementing @q->mq_usage_counter and
if freezing happens inbetween the caller can slip through and freezing
can be complete while there are active users.

Use smp_mb() instead so that bypass_depth and mq_usage_counter
modifications and tests are properly interlocked.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
block/blk-mq.c

index ad69ef6..9541f51 100644 (file)
@@ -81,7 +81,7 @@ static int blk_mq_queue_enter(struct request_queue *q)
        int ret;
 
        __percpu_counter_add(&q->mq_usage_counter, 1, 1000000);
-       smp_wmb();
+       smp_mb();
 
        /* we have problems freezing the queue if it's initializing */
        if (!blk_queue_dying(q) &&