Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 530ca2c9 authored by Keith Busch's avatar Keith Busch Committed by Jens Axboe
Browse files

blk-mq: Allow blocking queue tag iter callbacks



A recent commit runs tag iterator callbacks under the rcu read lock,
but existing callbacks do not satisfy the non-blocking requirement.
The commit intended to prevent an iterator from accessing a queue that's
being modified. This patch fixes the original issue by taking a queue
reference instead of reading it, which allows callbacks to make blocking
calls.

Fixes: f5bbbbe4 ("blk-mq: sync the update nr_hw_queues with blk_mq_queue_tag_busy_iter")
Acked-by: default avatarJianchao Wang <jianchao.w.wang@oracle.com>
Signed-off-by: default avatarKeith Busch <keith.busch@intel.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent b57e99b4
Loading
Loading
Loading
Loading
+4 −9
Original line number Original line Diff line number Diff line
@@ -322,16 +322,11 @@ void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn,


	/*
	/*
	 * __blk_mq_update_nr_hw_queues will update the nr_hw_queues and
	 * __blk_mq_update_nr_hw_queues will update the nr_hw_queues and
	 * queue_hw_ctx after freeze the queue. So we could use q_usage_counter
	 * queue_hw_ctx after freeze the queue, so we use q_usage_counter
	 * to avoid race with it. __blk_mq_update_nr_hw_queues will users
	 * to avoid race with it.
	 * synchronize_rcu to ensure all of the users go out of the critical
	 * section below and see zeroed q_usage_counter.
	 */
	 */
	rcu_read_lock();
	if (!percpu_ref_tryget(&q->q_usage_counter))
	if (percpu_ref_is_zero(&q->q_usage_counter)) {
		rcu_read_unlock();
		return;
		return;
	}


	queue_for_each_hw_ctx(q, hctx, i) {
	queue_for_each_hw_ctx(q, hctx, i) {
		struct blk_mq_tags *tags = hctx->tags;
		struct blk_mq_tags *tags = hctx->tags;
@@ -347,7 +342,7 @@ void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn,
			bt_for_each(hctx, &tags->breserved_tags, fn, priv, true);
			bt_for_each(hctx, &tags->breserved_tags, fn, priv, true);
		bt_for_each(hctx, &tags->bitmap_tags, fn, priv, false);
		bt_for_each(hctx, &tags->bitmap_tags, fn, priv, false);
	}
	}
	rcu_read_unlock();
	blk_queue_exit(q);
}
}


static int bt_alloc(struct sbitmap_queue *bt, unsigned int depth,
static int bt_alloc(struct sbitmap_queue *bt, unsigned int depth,