Skip to content

Commit c1291ea

Browse files
Ming Leigregkh
Ming Lei
authored andcommitted
blk-mq: move cpuhp callback registering out of q->sysfs_lock
[ Upstream commit 22465bb ] 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]> Stable-dep-of: be26ba9 ("block: Fix potential deadlock while freezing queue and acquiring sysfs_lock") Signed-off-by: Sasha Levin <[email protected]>
1 parent 7ccd621 commit c1291ea

File tree

1 file changed

+92
-6
lines changed

1 file changed

+92
-6
lines changed

block/blk-mq.c

Lines changed: 92 additions & 6 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,
@@ -3740,13 +3741,91 @@ static int blk_mq_hctx_notify_dead(unsigned int cpu, struct hlist_node *node)
37403741
return 0;
37413742
}
37423743

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

37523831
/*
@@ -3797,8 +3876,6 @@ static void blk_mq_exit_hctx(struct request_queue *q,
37973876
if (set->ops->exit_hctx)
37983877
set->ops->exit_hctx(hctx, hctx_idx);
37993878

3800-
blk_mq_remove_cpuhp(hctx);
3801-
38023879
xa_erase(&q->hctx_table, hctx_idx);
38033880

38043881
spin_lock(&q->unused_hctx_lock);
@@ -3815,6 +3892,7 @@ static void blk_mq_exit_hw_queues(struct request_queue *q,
38153892
queue_for_each_hw_ctx(q, hctx, i) {
38163893
if (i == nr_queue)
38173894
break;
3895+
blk_mq_remove_cpuhp(hctx);
38183896
blk_mq_exit_hctx(q, set, hctx, i);
38193897
}
38203898
}
@@ -3878,6 +3956,8 @@ blk_mq_alloc_hctx(struct request_queue *q, struct blk_mq_tag_set *set,
38783956
INIT_DELAYED_WORK(&hctx->run_work, blk_mq_run_work_fn);
38793957
spin_lock_init(&hctx->lock);
38803958
INIT_LIST_HEAD(&hctx->dispatch);
3959+
INIT_HLIST_NODE(&hctx->cpuhp_dead);
3960+
INIT_HLIST_NODE(&hctx->cpuhp_online);
38813961
hctx->queue = q;
38823962
hctx->flags = set->flags & ~BLK_MQ_F_TAG_QUEUE_SHARED;
38833963

@@ -4416,6 +4496,12 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
44164496
xa_for_each_start(&q->hctx_table, j, hctx, j)
44174497
blk_mq_exit_hctx(q, set, hctx, j);
44184498
mutex_unlock(&q->sysfs_lock);
4499+
4500+
/* unregister cpuhp callbacks for exited hctxs */
4501+
blk_mq_remove_hw_queues_cpuhp(q);
4502+
4503+
/* register cpuhp for new initialized hctxs */
4504+
blk_mq_add_hw_queues_cpuhp(q);
44194505
}
44204506

44214507
int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,

0 commit comments

Comments
 (0)