summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorBreno Leitao <leitao@debian.org>2026-06-30 09:15:21 -0700
committerTejun Heo <tj@kernel.org>2026-06-30 06:36:53 -1000
commitf7dc93388946dacae5ddf6bdf55822f066798a40 (patch)
tree3c1eb08a2818525035044620d03e65bdfe381077 /kernel
parent7ddfa24d3f12ab9f3ac0e0b4e8e573ff45574d86 (diff)
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 <pmladek@suse.com> Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Breno Leitao <leitao@debian.org> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/workqueue.c14
1 files changed, 13 insertions, 1 deletions
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)