From 045cbfc369f5929ed473f7c200dc2e8146569ce5 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 28 Oct 2026 10:41:37 -0600 Subject: [PATCH] block: don't enter reclaim under rq_qos_mutex ioc_qos_write() and the wbt_lat_usec writers take rq_qos_mutex with the queue frozen, blkcg_deactivate_policy() does the same with blkcg_mutex, so nothing holding either may wait for IO. blkg_conf_prep() got GFP_NOIO for the blkg in commit 5d726c4dbeed, but the radix_tree_preload() right after it, the policy init functions and the GFP_KERNEL fallback in blkcg_activate_policy() can still enter reclaim there. lockdep reports the cycle on the first write to io.max. Use GFP_NOIO for all of them. Fixes: 9730763f4756 ("block: correct locking order for protecting blk-wbt parameters") Fixes: 5d726c4dbeed ("blk-cgroup: fix possible deadlock while configuring policy") Cc: Tejun Heo Signed-off-by: Josef Bacik Acked-by: Tejun Heo Link: https://patch.msgid.link/20261028164415.1262013-35-axboe@kernel.dk Signed-off-by: Jens Axboe --- block/blk-cgroup.c | 13 +++++++++---- block/blk-iocost.c | 5 +++-- block/blk-iolatency.c | 3 ++- block/blk-throttle.c | 3 ++- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 00da55c6ec43..5b7a32293dc6 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -884,7 +884,11 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, parent = blkcg_parent(parent); } - /* Drop locks to do new blkg allocation with GFP_KERNEL. */ + /* + * Drop the spinlock to allocate the new blkg. rq_qos_mutex and + * blkcg_mutex stay held, and both are taken with the queue + * frozen elsewhere: GFP_NOIO. + */ spin_unlock_irq(&q->queue_lock); new_blkg = blkg_alloc(pos, disk, GFP_NOIO); @@ -893,7 +897,7 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, goto fail_exit; } - if (radix_tree_preload(GFP_KERNEL)) { + if (radix_tree_preload(GFP_NOIO)) { blkg_free(new_blkg); ret = -ENOMEM; goto fail_exit; @@ -1648,7 +1652,8 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol) if (!pd) { /* * GFP_NOWAIT failed. Free the existing one and - * prealloc for @blkg w/ GFP_KERNEL. + * prealloc for @blkg w/ GFP_NOIO: blkcg_mutex is held, + * and a bio based queue has not been frozen above. */ if (pinned_blkg) blkg_put(pinned_blkg); @@ -1660,7 +1665,7 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol) if (pd_prealloc) pol->pd_free_fn(pd_prealloc); pd_prealloc = pol->pd_alloc_fn(disk, blkg->blkcg, - GFP_KERNEL); + GFP_NOIO); if (pd_prealloc) goto retry; else diff --git a/block/blk-iocost.c b/block/blk-iocost.c index 7b5d865d8c14..47bea7f31408 100644 --- a/block/blk-iocost.c +++ b/block/blk-iocost.c @@ -2938,11 +2938,12 @@ static int blk_iocost_init(struct gendisk *disk) struct ioc *ioc; int i, cpu, ret; - ioc = kzalloc_obj(*ioc); + /* The caller holds rq_qos_mutex, which is taken with the queue frozen */ + ioc = kzalloc_obj(*ioc, GFP_NOIO); if (!ioc) return -ENOMEM; - ioc->pcpu_stat = alloc_percpu(struct ioc_pcpu_stat); + ioc->pcpu_stat = alloc_percpu_gfp(struct ioc_pcpu_stat, GFP_NOIO); if (!ioc->pcpu_stat) { kfree(ioc); return -ENOMEM; diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c index c15b1aba606c..a3bd153c67be 100644 --- a/block/blk-iolatency.c +++ b/block/blk-iolatency.c @@ -761,7 +761,8 @@ static int blk_iolatency_init(struct gendisk *disk) struct blk_iolatency *blkiolat; int ret; - blkiolat = kzalloc_obj(*blkiolat); + /* The caller holds rq_qos_mutex, which is taken with the queue frozen */ + blkiolat = kzalloc_obj(*blkiolat, GFP_NOIO); if (!blkiolat) return -ENOMEM; diff --git a/block/blk-throttle.c b/block/blk-throttle.c index c46807a0faab..c5e26551956a 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -1322,7 +1322,8 @@ static int blk_throtl_init(struct gendisk *disk) unsigned int memflags; int ret; - td = kzalloc_node(sizeof(*td), GFP_KERNEL, q->node); + /* The caller holds rq_qos_mutex, which is taken with the queue frozen */ + td = kzalloc_node(sizeof(*td), GFP_NOIO, q->node); if (!td) return -ENOMEM;