[PATCH v2 2/3] workqueue: trigger a single-CPU backtrace for stalled pools

From: Breno Leitao

Date: Tue Jun 30 2026 - 12:21:20 EST


When a CPU pool is stalled with no running worker, the task occupying the
CPU may not be a workqueue worker at all. Trigger a single-CPU backtrace
for the stalled CPU to capture what it is currently executing.

The CPU is snapshotted under pool->lock and the backtrace is triggered
after releasing the lock to avoid any potential issues with NMI delivery.

Skip the backtrace when the CPU is offline. A pool disassociated by CPU
hotplug keeps its pool->cpu, and an NMI to an offline CPU is never acked,
so nmi_trigger_cpumask_backtrace() would busy-wait for its full timeout
in the watchdog's timer context.

Suggested-by: Petr Mladek <pmladek@xxxxxxxx>
Reviewed-by: Petr Mladek <pmladek@xxxxxxxx>
Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx>
---
kernel/workqueue.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index efbac160b7628..7d30e23c84087 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -7720,10 +7720,13 @@ static void show_cpu_pool_busy_workers(struct worker_pool *pool)
bool found_running = false;
struct worker *worker;
unsigned long irq_flags;
- int bkt;
+ int cpu, bkt;

raw_spin_lock_irqsave(&pool->lock, irq_flags);

+ /* Snapshot cpu inside the lock to safely use it after unlock. */
+ cpu = pool->cpu;
+
hash_for_each(pool->busy_hash, bkt, worker, hentry) {
/* Skip workers that are not actively running on the CPU. */
if (!task_is_running(worker->task))
@@ -7751,6 +7754,15 @@ static void show_cpu_pool_busy_workers(struct worker_pool *pool)
show_pool_no_running_worker(pool);

raw_spin_unlock_irqrestore(&pool->lock, irq_flags);
+
+ /*
+ * Trigger a backtrace on the stalled CPU to capture what it is
+ * currently executing. Skip an offline CPU, whose NMI is never acked
+ * and would make the backtrace busy-wait until it times out. Done
+ * after releasing the lock to avoid issues with NMI delivery.
+ */
+ if (!found_running && cpu_online(cpu))
+ trigger_single_cpu_backtrace(cpu);
}

static void show_cpu_pools_busy_workers(void)

--
2.53.0-Meta