Skip to content

Commit 22465bb

Browse files
Ming Leiaxboe
Ming Lei
authored andcommitted
blk-mq: move cpuhp callback registering out of q->sysfs_lock
Registering and unregistering cpuhp callback requires global cpu hotplug lock, which is used everywhere. Meantime q->sysfs_lock is used in block layer almost everywhere. It is easy to trigger lockdep warning[1] by connecting the two locks. Fix the warning by moving blk-mq's cpuhp callback registering out of q->sysfs_lock. Add one dedicated global lock for covering registering & unregistering hctx's cpuhp, and it is safe to do so because hctx is guaranteed to be live if our request_queue is live. [1] https://lore.kernel.org/lkml/Z04pz3AlvI4o0Mr8@agluck-desk3/ Cc: Reinette Chatre <[email protected]> Cc: Fenghua Yu <[email protected]> Cc: Peter Newman <[email protected]> Cc: Babu Moger <[email protected]> Reported-by: Luck Tony <[email protected]> Signed-off-by: Ming Lei <[email protected]> Tested-by: Tony Luck <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 4bf485a commit 22465bb

File tree

1 file changed

+92
-11
lines changed

1 file changed

+92
-11
lines changed

block/blk-mq.c

Lines changed: 92 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
static DEFINE_PER_CPU(struct llist_head, blk_cpu_done);
4545
static DEFINE_PER_CPU(call_single_data_t, blk_cpu_csd);
46+
static DEFINE_MUTEX(blk_mq_cpuhp_lock);
4647

4748
static void blk_mq_insert_request(struct request *rq, blk_insert_t flags);
4849
static void blk_mq_request_bypass_insert(struct request *rq,
@@ -3739,13 +3740,91 @@ static int blk_mq_hctx_notify_dead(unsigned int cpu, struct hlist_node *node)
37393740
return 0;
37403741
}
37413742

3742-
static void blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx)
3743+
static void __blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx)
37433744
{
3744-
if (!(hctx->flags & BLK_MQ_F_STACKING))
3745+
lockdep_assert_held(&blk_mq_cpuhp_lock);
3746+
3747+
if (!(hctx->flags & BLK_MQ_F_STACKING) &&
3748+
!hlist_unhashed(&hctx->cpuhp_online)) {
37453749
cpuhp_state_remove_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE,
37463750
&hctx->cpuhp_online);
3747-
cpuhp_state_remove_instance_nocalls(CPUHP_BLK_MQ_DEAD,
3748-
&hctx->cpuhp_dead);
3751+
INIT_HLIST_NODE(&hctx->cpuhp_online);
3752+
}
3753+
3754+
if (!hlist_unhashed(&hctx->cpuhp_dead)) {
3755+
cpuhp_state_remove_instance_nocalls(CPUHP_BLK_MQ_DEAD,
3756+
&hctx->cpuhp_dead);
3757+
INIT_HLIST_NODE(&hctx->cpuhp_dead);
3758+
}
3759+
}
3760+
3761+
static void blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx)
3762+
{
3763+
mutex_lock(&blk_mq_cpuhp_lock);
3764+
__blk_mq_remove_cpuhp(hctx);
3765+
mutex_unlock(&blk_mq_cpuhp_lock);
3766+
}
3767+
3768+
static void __blk_mq_add_cpuhp(struct blk_mq_hw_ctx *hctx)
3769+
{
3770+
lockdep_assert_held(&blk_mq_cpuhp_lock);
3771+
3772+
if (!(hctx->flags & BLK_MQ_F_STACKING) &&
3773+
hlist_unhashed(&hctx->cpuhp_online))
3774+
cpuhp_state_add_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE,
3775+
&hctx->cpuhp_online);
3776+
3777+
if (hlist_unhashed(&hctx->cpuhp_dead))
3778+
cpuhp_state_add_instance_nocalls(CPUHP_BLK_MQ_DEAD,
3779+
&hctx->cpuhp_dead);
3780+
}
3781+
3782+
static void __blk_mq_remove_cpuhp_list(struct list_head *head)
3783+
{
3784+
struct blk_mq_hw_ctx *hctx;
3785+
3786+
lockdep_assert_held(&blk_mq_cpuhp_lock);
3787+
3788+
list_for_each_entry(hctx, head, hctx_list)
3789+
__blk_mq_remove_cpuhp(hctx);
3790+
}
3791+
3792+
/*
3793+
* Unregister cpuhp callbacks from exited hw queues
3794+
*
3795+
* Safe to call if this `request_queue` is live
3796+
*/
3797+
static void blk_mq_remove_hw_queues_cpuhp(struct request_queue *q)
3798+
{
3799+
LIST_HEAD(hctx_list);
3800+
3801+
spin_lock(&q->unused_hctx_lock);
3802+
list_splice_init(&q->unused_hctx_list, &hctx_list);
3803+
spin_unlock(&q->unused_hctx_lock);
3804+
3805+
mutex_lock(&blk_mq_cpuhp_lock);
3806+
__blk_mq_remove_cpuhp_list(&hctx_list);
3807+
mutex_unlock(&blk_mq_cpuhp_lock);
3808+
3809+
spin_lock(&q->unused_hctx_lock);
3810+
list_splice(&hctx_list, &q->unused_hctx_list);
3811+
spin_unlock(&q->unused_hctx_lock);
3812+
}
3813+
3814+
/*
3815+
* Register cpuhp callbacks from all hw queues
3816+
*
3817+
* Safe to call if this `request_queue` is live
3818+
*/
3819+
static void blk_mq_add_hw_queues_cpuhp(struct request_queue *q)
3820+
{
3821+
struct blk_mq_hw_ctx *hctx;
3822+
unsigned long i;
3823+
3824+
mutex_lock(&blk_mq_cpuhp_lock);
3825+
queue_for_each_hw_ctx(q, hctx, i)
3826+
__blk_mq_add_cpuhp(hctx);
3827+
mutex_unlock(&blk_mq_cpuhp_lock);
37493828
}
37503829

37513830
/*
@@ -3796,8 +3875,6 @@ static void blk_mq_exit_hctx(struct request_queue *q,
37963875
if (set->ops->exit_hctx)
37973876
set->ops->exit_hctx(hctx, hctx_idx);
37983877

3799-
blk_mq_remove_cpuhp(hctx);
3800-
38013878
xa_erase(&q->hctx_table, hctx_idx);
38023879

38033880
spin_lock(&q->unused_hctx_lock);
@@ -3814,6 +3891,7 @@ static void blk_mq_exit_hw_queues(struct request_queue *q,
38143891
queue_for_each_hw_ctx(q, hctx, i) {
38153892
if (i == nr_queue)
38163893
break;
3894+
blk_mq_remove_cpuhp(hctx);
38173895
blk_mq_exit_hctx(q, set, hctx, i);
38183896
}
38193897
}
@@ -3837,11 +3915,6 @@ static int blk_mq_init_hctx(struct request_queue *q,
38373915
if (xa_insert(&q->hctx_table, hctx_idx, hctx, GFP_KERNEL))
38383916
goto exit_flush_rq;
38393917

3840-
if (!(hctx->flags & BLK_MQ_F_STACKING))
3841-
cpuhp_state_add_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE,
3842-
&hctx->cpuhp_online);
3843-
cpuhp_state_add_instance_nocalls(CPUHP_BLK_MQ_DEAD, &hctx->cpuhp_dead);
3844-
38453918
return 0;
38463919

38473920
exit_flush_rq:
@@ -3876,6 +3949,8 @@ blk_mq_alloc_hctx(struct request_queue *q, struct blk_mq_tag_set *set,
38763949
INIT_DELAYED_WORK(&hctx->run_work, blk_mq_run_work_fn);
38773950
spin_lock_init(&hctx->lock);
38783951
INIT_LIST_HEAD(&hctx->dispatch);
3952+
INIT_HLIST_NODE(&hctx->cpuhp_dead);
3953+
INIT_HLIST_NODE(&hctx->cpuhp_online);
38793954
hctx->queue = q;
38803955
hctx->flags = set->flags & ~BLK_MQ_F_TAG_QUEUE_SHARED;
38813956

@@ -4414,6 +4489,12 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
44144489
xa_for_each_start(&q->hctx_table, j, hctx, j)
44154490
blk_mq_exit_hctx(q, set, hctx, j);
44164491
mutex_unlock(&q->sysfs_lock);
4492+
4493+
/* unregister cpuhp callbacks for exited hctxs */
4494+
blk_mq_remove_hw_queues_cpuhp(q);
4495+
4496+
/* register cpuhp for new initialized hctxs */
4497+
blk_mq_add_hw_queues_cpuhp(q);
44174498
}
44184499

44194500
int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,

0 commit comments

Comments
 (0)