mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
blk-mq: quiesce a queue that joins a quiesced tag set
blk_mq_quiesce_tagset() only quiesces the queues on the list at that moment. A queue added before blk_mq_unquiesce_tagset() runs unquiesced, and then gets unquiesced without ever having been quiesced, which trips the warning in blk_mq_unquiesce_queue(). NVMe gets there when a controller fails while its namespaces are being scanned. Count the quiesce calls in the tag set and quiesce a joining queue that many times, under a spinlock that also serializes the two functions. It can't be tag_list_lock, see commit59e25ef2b4. Fixes:414dd48e88("blk-mq: add tagset quiesce interface") Signed-off-by: Josef Bacik <josef@toxicpanda.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Link: https://patch.msgid.link/20261028164415.1262013-37-axboe@kernel.dk Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
035236c9e1
commit
71ec3c7d6d
|
|
@ -336,12 +336,15 @@ void blk_mq_quiesce_tagset(struct blk_mq_tag_set *set)
|
|||
{
|
||||
struct request_queue *q;
|
||||
|
||||
spin_lock(&set->quiesce_lock);
|
||||
set->quiesce_depth++;
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(q, &set->tag_list, tag_set_list) {
|
||||
if (!blk_queue_skip_tagset_quiesce(q))
|
||||
blk_mq_quiesce_queue_nowait(q);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
spin_unlock(&set->quiesce_lock);
|
||||
|
||||
blk_mq_wait_quiesce_done(set);
|
||||
}
|
||||
|
|
@ -351,12 +354,16 @@ void blk_mq_unquiesce_tagset(struct blk_mq_tag_set *set)
|
|||
{
|
||||
struct request_queue *q;
|
||||
|
||||
spin_lock(&set->quiesce_lock);
|
||||
if (set->quiesce_depth)
|
||||
set->quiesce_depth--;
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(q, &set->tag_list, tag_set_list) {
|
||||
if (!blk_queue_skip_tagset_quiesce(q))
|
||||
blk_mq_unquiesce_queue(q);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
spin_unlock(&set->quiesce_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blk_mq_unquiesce_tagset);
|
||||
|
||||
|
|
@ -4345,6 +4352,8 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q)
|
|||
static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set,
|
||||
struct request_queue *q)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
mutex_lock(&set->tag_list_lock);
|
||||
|
||||
/*
|
||||
|
|
@ -4358,7 +4367,18 @@ static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set,
|
|||
}
|
||||
if (set->flags & BLK_MQ_F_TAG_QUEUE_SHARED)
|
||||
queue_set_hctx_shared(q, true);
|
||||
|
||||
/*
|
||||
* A queue that joins a quiesced tag set is quiesced like the others,
|
||||
* and blk_mq_unquiesce_tagset() finds what it is going to undo.
|
||||
*/
|
||||
spin_lock(&set->quiesce_lock);
|
||||
list_add_tail_rcu(&q->tag_set_list, &set->tag_list);
|
||||
if (!blk_queue_skip_tagset_quiesce(q)) {
|
||||
for (i = 0; i < set->quiesce_depth; i++)
|
||||
blk_mq_quiesce_queue_nowait(q);
|
||||
}
|
||||
spin_unlock(&set->quiesce_lock);
|
||||
|
||||
mutex_unlock(&set->tag_list_lock);
|
||||
}
|
||||
|
|
@ -4927,6 +4947,8 @@ int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
|
|||
|
||||
mutex_init(&set->tag_list_lock);
|
||||
INIT_LIST_HEAD(&set->tag_list);
|
||||
spin_lock_init(&set->quiesce_lock);
|
||||
set->quiesce_depth = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -523,6 +523,10 @@ enum hctx_type {
|
|||
* @tag_list_lock: Serializes tag_list accesses.
|
||||
* @tag_list: List of the request queues that use this tag set. See also
|
||||
* request_queue.tag_set_list.
|
||||
* @quiesce_lock: Serializes blk_mq_[un]quiesce_tagset() against each other
|
||||
* and against a request queue being added to @tag_list.
|
||||
* @quiesce_depth: How often blk_mq_quiesce_tagset() has been called without
|
||||
* blk_mq_unquiesce_tagset().
|
||||
* @srcu: Use as lock when type of the request queue is blocking
|
||||
* (BLK_MQ_F_BLOCKING).
|
||||
* @update_nr_hwq_lock:
|
||||
|
|
@ -548,6 +552,8 @@ struct blk_mq_tag_set {
|
|||
|
||||
struct mutex tag_list_lock;
|
||||
struct list_head tag_list;
|
||||
spinlock_t quiesce_lock;
|
||||
unsigned int quiesce_depth;
|
||||
struct srcu_struct *srcu;
|
||||
|
||||
struct rw_semaphore update_nr_hwq_lock;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user