From: Aaron Tomlin <atomlin@atomlin.com>
To: axboe@kernel.dk
Cc: tom.leiming@gmail.com, hare@suse.de, dwagner@suse.de,
frederic@kernel.org, tj@kernel.org, atomlin@atomlin.com,
sean@ashe.io, linux-block@vger.kernel.org,
linux-kernel@vger.kernel.org, stable@vger.kernel.org
Subject: [PATCH v2] blk-mq: dispatch kworker to housekeeping CPU when hctx cpumask is empty
Date: Wed, 14 Oct 2026 22:02:25 -0400 [thread overview]
Message-ID: <20261015020225.422107-1-atomlin@atomlin.com> (raw)
Commit a46c27026da1 ("blk-mq: don't schedule block kworker on isolated
CPUs") excluded isolated CPUs from hctx->cpumask to prevent worker
threads from executing block work on isolated CPUs. When all CPUs mapped
to a hardware queue are isolated (i.e. blk_mq_hctx_empty_cpumask(hctx)
evaluates to true), blk_mq_hctx_next_cpu() returns WORK_CPU_UNBOUND with
the intention of offloading execution.
However, kblockd_workqueue is allocated as a per-CPU workqueue
(WQ_PERCPU). When WORK_CPU_UNBOUND is queued on a per-CPU workqueue, the
workqueue core resolves the target CPU via raw_smp_processor_id().
Consequently, if a task executing on an isolated CPU submits I/O and
triggers an asynchronous queue dispatch with zero delay (e.g. upon
hardware queue congestion, tag/resource exhaustion returning
BLK_STS_RESOURCE, or plugging), &hctx->run_work is queued directly onto
the local isolated CPU's worker pool. This causes the local per-CPU
high-priority kworker (e.g. "kworker/6:1H-kblockd") to be scheduled on
the isolated CPU. In real-time environments, an active SCHED_FIFO workload
will starve this SCHED_NORMAL worker, causing hardware dispatch to stall,
in addition to introducing unwanted latency jitter on nohz_full cores,
thereby defeating the original objective of commit a46c27026da1.
Introduce blk_mq_hctx_unbound_cpu() to select an online housekeeping CPU
via housekeeping_any_cpu(HK_TYPE_TIMER) when executing on an isolated
CPU, and otherwise fall back to WORK_CPU_UNBOUND. Use this helper across
the unbound fallback paths in blk_mq_hctx_next_cpu().
This ensures that:
1. When executing on an isolated CPU, deferred queue work is
cleanly offloaded to an online housekeeping CPU across single-queue
devices, hardware queues with empty cpumasks, and offline CPU
fallback paths.
2. The per-CPU high-priority kworker on the isolated CPU is not
scheduled, avoiding priority inversion and latency jitter.
3. When executing on a non-isolated CPU, WORK_CPU_UNBOUND is
preserved, maintaining optimal local execution with zero CPU
bouncing.
Fixes: a46c27026da1 ("blk-mq: don't schedule block kworker on isolated CPUs")
Cc: Ming Lei <ming.lei@redhat.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: stable@vger.kernel.org
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
---
Changes since v1:
- Introduce the blk_mq_hctx_unbound_cpu() helper to steer deferred work
to an online housekeeping CPU only when executing on an isolated
core, preserving WORK_CPU_UNBOUND and local cache locality for
housekeeping cores
- Apply blk_mq_hctx_unbound_cpu() across all unbound fallback paths in
blk_mq_hctx_next_cpu(), comprehensively covering single-queue devices
(nr_hw_queues == 1), empty hardware queue cpumasks, and the offline
CPU fallback path.
- Elaborate in the commit log on the triggers for asynchronous queue
dispatch (e.g. tag exhaustion, BLK_STS_RESOURCE backpressure, and
plugging) and the SCHED_FIFO worker starvation hazard on isolated
cores
- Link to v1: https://lore.kernel.org/lkml/20261012012905.267920-1-atomlin@atomlin.com/
---
block/blk-mq.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 025a799f35b9..df6103b91e60 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -2241,6 +2241,13 @@ static bool blk_mq_hctx_empty_cpumask(struct blk_mq_hw_ctx *hctx)
return hctx->next_cpu >= nr_cpu_ids;
}
+static inline int blk_mq_hctx_unbound_cpu(void)
+{
+ if (cpu_is_isolated(raw_smp_processor_id()))
+ return housekeeping_any_cpu(HK_TYPE_TIMER);
+ return WORK_CPU_UNBOUND;
+}
+
/*
* It'd be great if the workqueue API had a way to pass
* in a mask and had some smarts for more clever placement.
@@ -2254,7 +2261,7 @@ static int blk_mq_hctx_next_cpu(struct blk_mq_hw_ctx *hctx)
/* Switch to unbound if no allowable CPUs in this hctx */
if (hctx->queue->nr_hw_queues == 1 || blk_mq_hctx_empty_cpumask(hctx))
- return WORK_CPU_UNBOUND;
+ return blk_mq_hctx_unbound_cpu();
if (--hctx->next_cpu_batch <= 0) {
select_cpu:
@@ -2281,7 +2288,7 @@ static int blk_mq_hctx_next_cpu(struct blk_mq_hw_ctx *hctx)
*/
hctx->next_cpu = next_cpu;
hctx->next_cpu_batch = 1;
- return WORK_CPU_UNBOUND;
+ return blk_mq_hctx_unbound_cpu();
}
hctx->next_cpu = next_cpu;
--
2.55.0
next reply other threads:[~2026-10-15 2:02 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-15 2:02 Aaron Tomlin [this message]
2026-10-15 3:13 ` [PATCH v2] blk-mq: dispatch kworker to housekeeping CPU when hctx cpumask is empty Aaron Tomlin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261015020225.422107-1-atomlin@atomlin.com \
--to=atomlin@atomlin.com \
--cc=axboe@kernel.dk \
--cc=dwagner@suse.de \
--cc=frederic@kernel.org \
--cc=hare@suse.de \
--cc=linux-block@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=sean@ashe.io \
--cc=stable@vger.kernel.org \
--cc=tj@kernel.org \
--cc=tom.leiming@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.