Re: [PATCH] blk-mq: dispatch kworker to housekeeping CPU when hctx cpumask is empty
From: Aaron Tomlin
Date: Tue Oct 13 2026 - 14:58:10 EST
On Tue, Oct 13, 2026 at 09:07:46AM -0500, Ming Lei wrote:
> Any user visible effect? Both are a piece of code running on isolated CPU,
> the choice is in application. If they want to run IO on isolated CPU, we
> do it in same way. Otherwise, we won't schedule work on isolated CPU for
> respecting the kernel interface.
That assertion is directly contradicted by how blk-mq is implemented today.
blk-mq already actively shields isolated CPUs from running kworkers even
when I/O is initiated on an isolated CPU.
Consider a multi-queue device where an hctx maps CPU 0 (housekeeping) and
CPU 4 (isolated):
1. In blk_mq_map_swqueue(), commit a46c27026da1 explicitly stripped
isolated CPUs from hctx->cpumask. Thus, hctx->cpumask contains
solely CPU 0.
2. When a thread executing on isolated CPU 4 submits I/O and calls
blk_mq_run_hw_queue(), blk-mq checks:
if (async || !cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask)) {
blk_mq_delay_run_hw_queue(hctx, 0);
return;
}
Because CPU 4 is not in hctx->cpumask, blk-mq refuses inline
dispatch on CPU 4 and offloads via blk_mq_delay_run_hw_queue().
3. blk_mq_delay_run_hw_queue() calls blk_mq_hctx_next_cpu(), which
iterates over hctx->cpumask and selects CPU 0 (the housekeeping
CPU).
4. kblockd_mod_delayed_work_on() queues the delayed work onto CPU 0.
Therefore, for any hardware queue with at least one housekeeping CPU,
blk-mq already offloads the kworker to a housekeeping CPU, completely
sparing the isolated CPU that initiated the I/O.
The only scenario where this offload breaks down today is when all CPUs
mapped to that hardware queue are isolated (blk_mq_hctx_empty_cpumask(hctx)
is true). In that case, commit a46c27026da1 added:
/* 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;
The comment and intention were unambiguous. However, because
kblockd_workqueue is allocated as WQ_PERCPU, WORK_CPU_UNBOUND inadvertently
resolves to raw_smp_processor_id(), dropping the kworker straight back onto
isolated CPU 4.
Hence, blk-mq's established policy is already to steer kworkers away from
isolated CPUs regardless of where I/O was submitted. This patch merely
ensures that the empty-mask fallback honours that existing contract rather
than accidentally violating it. I will send the next iteration for review.
Kind regards,
--
Aaron Tomlin