Skip to content

blk-mq: fix possible deadlocks#549

Open
blktests-ci[bot] wants to merge 9 commits intolinus-master_basefrom
series/1049630=>linus-master
Open

blk-mq: fix possible deadlocks#549
blktests-ci[bot] wants to merge 9 commits intolinus-master_basefrom
series/1049630=>linus-master

Conversation

@blktests-ci
Copy link

@blktests-ci blktests-ci bot commented Feb 8, 2026

Pull request for series with
subject: blk-mq: fix possible deadlocks
version: 9
url: https://patchwork.kernel.org/project/linux-block/list/?series=1049630

@blktests-ci
Copy link
Author

blktests-ci bot commented Feb 8, 2026

Upstream branch: e7aa572
series: https://patchwork.kernel.org/project/linux-block/list/?series=1049630
version: 9

@blktests-ci blktests-ci bot force-pushed the linus-master_base branch from eb49f7b to 30e5c22 Compare February 9, 2026 04:29
To move implementation details inside blk-wbt.c, prepare to fix possible
deadlock to call wbt_init() while queue is frozen in the next patch.

Reviewed-by: Ming Lei <[email protected]>
Reviewed-by: Nilay Shroff <[email protected]>
Signed-off-by: Yu Kuai <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
…_counter

If wbt is disabled by default and user configures wbt by sysfs, queue
will be frozen first and then pcpu_alloc_mutex will be held in
blk_stat_alloc_callback().

Fix this problem by allocating memory first before queue frozen.

Signed-off-by: Yu Kuai <[email protected]>
Reviewed-by: Nilay Shroff <[email protected]>
Reviewed-by: Ming Lei <[email protected]>
There is already a helper blk_mq_debugfs_register_rqos() to register
one rqos, however this helper is called synchronously when the rqos is
created with queue frozen.

Prepare to fix possible deadlock to create blk-mq debugfs entries while
queue is still frozen.

Reviewed-by: Ming Lei <[email protected]>
Reviewed-by: Nilay Shroff <[email protected]>
Signed-off-by: Yu Kuai <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
Currently rq-qos debugfs entries are created from rq_qos_add(), while
rq_qos_add() can be called while queue is still frozen. This can
deadlock because creating new entries can trigger fs reclaim.

Fix this problem by delaying creating rq-qos debugfs entries after queue
is unfrozen.

- For wbt, 1) it can be initialized by default, fix it by calling new
  helper after wbt_init() from wbt_init_enable_default(); 2) it can be
  initialized by sysfs, fix it by calling new helper after queue is
  unfrozen from wbt_set_lat().
- For iocost and iolatency, they can only be initialized by blkcg
  configuration, however, they don't have debugfs entries for now, hence
  they are not handled yet.

Signed-off-by: Yu Kuai <[email protected]>
Reviewed-by: Nilay Shroff <[email protected]>
Reviewed-by: Ming Lei <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
@blktests-ci
Copy link
Author

blktests-ci bot commented Feb 9, 2026

Upstream branch: 05f7e89
series: https://patchwork.kernel.org/project/linux-block/list/?series=1049630
version: 9

Because it's only used inside blk-mq-debugfs.c now.

Reviewed-by: Nilay Shroff <[email protected]>
Signed-off-by: Yu Kuai <[email protected]>
Reviewed-by: Ming Lei <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
Because this helper is only used by iocost and iolatency, while they
don't have debugfs entries.

Signed-off-by: Yu Kuai <[email protected]>
Reviewed-by: Nilay Shroff <[email protected]>
Reviewed-by: Ming Lei <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
…hctxs()

In blk_mq_update_nr_hw_queues(), debugfs_mutex is not held while
creating debugfs entries for hctxs. Hence add debugfs_mutex there,
it's safe because queue is not frozen.

Signed-off-by: Yu Kuai <[email protected]>
Reviewed-by: Nilay Shroff <[email protected]>
Reviewed-by: Ming Lei <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
Creating new debugfs entries can trigger fs reclaim, hence we can't do
this with queue frozen, meanwhile, other locks that can be held while
queue is frozen should not be held as well.

Signed-off-by: Yu Kuai <[email protected]>
Reviewed-by: Nilay Shroff <[email protected]>
Reviewed-by: Ming Lei <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
@blktests-ci blktests-ci bot force-pushed the series/1049630=>linus-master branch from 2d286a0 to b82666b Compare February 9, 2026 04:31
@blktests-ci blktests-ci bot force-pushed the linus-master_base branch from 30e5c22 to 519f160 Compare February 12, 2026 00:34
@blktests-ci
Copy link
Author

blktests-ci bot commented Feb 12, 2026

Upstream branch: c22e26b
series: https://patchwork.kernel.org/project/linux-block/list/?series=1049630
version: 9

Pull request is NOT updated. Failed to apply https://patchwork.kernel.org/project/linux-block/list/?series=1049630
error message:

Cmd('git') failed due to: exit code(128)
  cmdline: git am --3way
  stdout: 'Applying: blk-wbt: factor out a helper wbt_set_lat()
Using index info to reconstruct a base tree...
M	block/blk-sysfs.c
M	block/blk-wbt.c
M	block/blk-wbt.h
Falling back to patching base and 3-way merge...
Auto-merging block/blk-wbt.c
CONFLICT (content): Merge conflict in block/blk-wbt.c
Auto-merging block/blk-sysfs.c
Patch failed at 0001 blk-wbt: factor out a helper wbt_set_lat()'
  stderr: 'error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"'

conflict:

diff --cc block/blk-wbt.c
index 1415f2bf8611,0a37d97bda75..000000000000
--- a/block/blk-wbt.c
+++ b/block/blk-wbt.c
@@@ -93,7 -93,7 +93,11 @@@ struct rq_wb 
  	struct rq_depth rq_depth;
  };
  
++<<<<<<< HEAD
 +static int wbt_init(struct gendisk *disk, struct rq_wb *rwb);
++=======
+ static int wbt_init(struct gendisk *disk);
++>>>>>>> blk-wbt: factor out a helper wbt_set_lat()
  
  static inline struct rq_wb *RQWB(struct rq_qos *rqos)
  {
@@@ -940,11 -903,22 +944,15 @@@ static const struct rq_qos_ops wbt_rqos
  #endif
  };
  
++<<<<<<< HEAD
 +static int wbt_init(struct gendisk *disk, struct rq_wb *rwb)
++=======
+ static int wbt_init(struct gendisk *disk)
++>>>>>>> blk-wbt: factor out a helper wbt_set_lat()
  {
  	struct request_queue *q = disk->queue;
 -	struct rq_wb *rwb;
 -	int i;
  	int ret;
 -
 -	rwb = kzalloc(sizeof(*rwb), GFP_KERNEL);
 -	if (!rwb)
 -		return -ENOMEM;
 -
 -	rwb->cb = blk_stat_alloc_callback(wb_timer_fn, wbt_data_dir, 2, rwb);
 -	if (!rwb->cb) {
 -		kfree(rwb);
 -		return -ENOMEM;
 -	}
 +	int i;
  
  	for (i = 0; i < WBT_NUM_RWQ; i++)
  		rq_wait_init(&rwb->rq_wait[i]);
@@@ -964,60 -938,57 +972,102 @@@
  	ret = rq_qos_add(&rwb->rqos, disk, RQ_QOS_WBT, &wbt_rqos_ops);
  	mutex_unlock(&q->rq_qos_mutex);
  	if (ret)
 -		goto err_free;
 +		return ret;
  
  	blk_stat_add_callback(q, rwb->cb);
 -
  	return 0;
 +}
  
 -err_free:
 -	blk_stat_free_callback(rwb->cb);
 -	kfree(rwb);
 -	return ret;
 +int wbt_set_lat(struct gendisk *disk, s64 val)
 +{
 +	struct request_queue *q = disk->queue;
 +	struct rq_qos *rqos = wbt_rq_qos(q);
 +	struct rq_wb *rwb = NULL;
 +	unsigned int memflags;
 +	int ret = 0;
 +
 +	if (!rqos) {
 +		rwb = wbt_alloc();
 +		if (!rwb)
 +			return -ENOMEM;
 +	}
 +
 +	/*
 +	 * Ensure that the queue is idled, in case the latency update
 +	 * ends up either enabling or disabling wbt completely. We can't
 +	 * have IO inflight if that happens.
 +	 */
 +	memflags = blk_mq_freeze_queue(q);
 +	if (!rqos) {
 +		ret = wbt_init(disk, rwb);
 +		if (ret) {
 +			wbt_free(rwb);
 +			goto out;
 +		}
 +	}
  
 +	if (val == -1)
 +		val = wbt_default_latency_nsec(q);
 +	else if (val >= 0)
 +		val *= 1000ULL;
 +
 +	if (wbt_get_min_lat(q) == val)
 +		goto out;
 +
 +	blk_mq_quiesce_queue(q);
 +
 +	mutex_lock(&disk->rqos_state_mutex);
 +	wbt_set_min_lat(q, val);
 +	mutex_unlock(&disk->rqos_state_mutex);
 +
 +	blk_mq_unquiesce_queue(q);
 +out:
 +	blk_mq_unfreeze_queue(q, memflags);
 +	mutex_lock(&q->debugfs_mutex);
 +	blk_mq_debugfs_register_rq_qos(q);
 +	mutex_unlock(&q->debugfs_mutex);
 +
 +	return ret;
  }
+ 
+ int wbt_set_lat(struct gendisk *disk, s64 val)
+ {
+ 	struct request_queue *q = disk->queue;
+ 	unsigned int memflags;
+ 	struct rq_qos *rqos;
+ 	int ret = 0;
+ 
+ 	/*
+ 	 * Ensure that the queue is idled, in case the latency update
+ 	 * ends up either enabling or disabling wbt completely. We can't
+ 	 * have IO inflight if that happens.
+ 	 */
+ 	memflags = blk_mq_freeze_queue(q);
+ 
+ 	rqos = wbt_rq_qos(q);
+ 	if (!rqos) {
+ 		ret = wbt_init(disk);
+ 		if (ret)
+ 			goto out;
+ 	}
+ 
+ 	if (val == -1)
+ 		val = wbt_default_latency_nsec(q);
+ 	else if (val >= 0)
+ 		val *= 1000ULL;
+ 
+ 	if (wbt_get_min_lat(q) == val)
+ 		goto out;
+ 
+ 	blk_mq_quiesce_queue(q);
+ 
+ 	mutex_lock(&disk->rqos_state_mutex);
+ 	wbt_set_min_lat(q, val);
+ 	mutex_unlock(&disk->rqos_state_mutex);
+ 
+ 	blk_mq_unquiesce_queue(q);
+ out:
+ 	blk_mq_unfreeze_queue(q, memflags);
+ 
+ 	return ret;
+ }

@blktests-ci blktests-ci bot force-pushed the linus-master_base branch 9 times, most recently from e1fefe2 to f714aad Compare February 18, 2026 05:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments