[PATCH v16 7/9] blk-mq: prevent offlining hk CPUs with associated online isolated CPUs
From: Aaron Tomlin
Date: Thu Sep 10 2026 - 12:52:08 EST
From: Daniel Wagner <wagi@xxxxxxxxxx>
When isolcpus=managed_irq_strict is enabled and the last housekeeping CPU
for a given hctx goes offline, no CPU would be left to handle I/O.
To prevent I/O stalls, disallow offlining housekeeping CPUs that are
still serving isolated CPUs.
Signed-off-by: Daniel Wagner <wagi@xxxxxxxxxx>
Reviewed-by: Hannes Reinecke <hare@xxxxxxx>
Co-developed-by: Aaron Tomlin <atomlin@xxxxxxxxxxx>
Signed-off-by: Aaron Tomlin <atomlin@xxxxxxxxxxx>
---
block/blk-mq.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/block/blk-mq.c b/block/blk-mq.c
index a26a11c73ee3..6e903e1310e9 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -3690,6 +3690,64 @@ static bool blk_mq_hctx_has_requests(struct blk_mq_hw_ctx *hctx)
return data.has_rq;
}
+static bool blk_mq_hctx_can_offline_hk_cpu(struct blk_mq_hw_ctx *hctx,
+ unsigned int this_cpu)
+{
+ const struct cpumask *hk_mask = housekeeping_cpumask(HK_TYPE_MANAGED_IRQ_STRICT);
+ int cpu, fallback_isolated_cpu = -1;
+
+ /*
+ * During system suspend or hibernation, tasks are frozen and all
+ * CPUs are being taken offline. Allow offlining to proceed so
+ * suspend is not aborted.
+ */
+ if (cpuhp_tasks_frozen)
+ return true;
+
+ /*
+ * If the CPU being offlined is not a housekeeping CPU,
+ * offlining it will not strand isolated CPUs. Allow it.
+ */
+ if (!cpumask_test_cpu(this_cpu, hk_mask))
+ return true;
+ /*
+ * If this CPU is not mapped to this specific hardware context,
+ * offlining it will not affect the context's I/O routing. Allow it.
+ */
+ if (blk_mq_map_queue_type(hctx->queue, hctx->type, this_cpu) != hctx)
+ return true;
+ /*
+ * Iterate over all online CPUs and manually check their mapping.
+ * We cannot use hctx->cpumask here because blk_mq_map_swqueue()
+ * intentionally strips isolated CPUs from it to prevent kworker
+ * routing.
+ */
+ for_each_online_cpu(cpu) {
+ struct blk_mq_hw_ctx *h;
+
+ if (cpu == this_cpu)
+ continue;
+
+ h = blk_mq_map_queue_type(hctx->queue, hctx->type, cpu);
+ if (h != hctx)
+ continue;
+
+ if (cpumask_test_cpu(cpu, hk_mask))
+ return true;
+
+ if (fallback_isolated_cpu == -1)
+ fallback_isolated_cpu = cpu;
+ }
+
+ if (fallback_isolated_cpu != -1) {
+ pr_warn("blk-mq: cannot offline CPU %u: online isolated CPU %d is still mapped to hctx%u\n",
+ this_cpu, fallback_isolated_cpu, hctx->queue_num);
+ return false;
+ }
+
+ return true;
+}
+
static bool blk_mq_hctx_has_online_cpu(struct blk_mq_hw_ctx *hctx,
unsigned int this_cpu)
{
@@ -3722,6 +3780,11 @@ static int blk_mq_hctx_notify_offline(unsigned int cpu, struct hlist_node *node)
struct blk_mq_hw_ctx, cpuhp_online);
int ret = 0;
+ if (housekeeping_enabled(HK_TYPE_MANAGED_IRQ_STRICT)) {
+ if (!blk_mq_hctx_can_offline_hk_cpu(hctx, cpu))
+ return -EINVAL;
+ }
+
if (!hctx->nr_ctx || blk_mq_hctx_has_online_cpu(hctx, cpu))
return 0;
--
2.55.0