From f7dc93388946dacae5ddf6bdf55822f066798a40 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 30 Jun 2026 09:15:21 -0700 Subject: workqueue: trigger a single-CPU backtrace for stalled pools 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 Reviewed-by: Petr Mladek Signed-off-by: Breno Leitao Signed-off-by: Tejun Heo --- kernel/workqueue.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'kernel/workqueue.c') diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 56edead95aab..a3aea405d773 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -7753,10 +7753,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)) @@ -7784,6 +7787,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) -- cgit v1.2.3