History

workqueue: only show running workers in stall diagnostics

show_cpu_pool_busy_workers() dumps every in-flight worker in the pool's busy_hash, including workers that are not currently running on the CPU. Restore the task_is_running() filter so only running workers are dumped. When no running worker is found the pool may be stuck, unable to wake an idle worker to process pending work, and the watchdog would otherwise give no feedback. Add show_pool_no_running_worker() to report the pool id, CPU, idle state, and worker counts in that case. The pool info message is printed inside pool->lock using printk_deferred_enter/exit, the same pattern used by the existing busy-worker loop, to avoid deadlocks with console drivers that queue work while holding locks also taken in their write paths. This has been running on the Meta fleet for a while and caught some real issues, for instance EFI stalls stalling the workqueue [1].

Breno Leitao committed 4 months ago

Commit 7ddfa241 parent f5047061 file · +34 −4Browse files

Showing the changes to kernel/workqueue.c (1 of 1 file). Show all

Unified · Split

kernel/workqueue.c+34−4
@@ -7726,13 +7726,31 @@ module_param_named(panic_on_stall_time, wq_panic_on_stall_time, uint, 0644); · 7725 unmodified lines
77267726 MODULE_PARM_DESC(panic_on_stall_time, "Panic if stall exceeds this many seconds (0=disabled)");
77277727
77287728 /*
7729− * Show workers that might prevent the processing of pending work items.
7730− * A busy worker that is not running on the CPU (e.g. sleeping in
7731− * wait_event_idle() with PF_WQ_WORKER cleared) can stall the pool just as
7732− * effectively as a CPU-bound one, so dump every in-flight worker.
7729+ * Report that a pool has no worker in running state, which is a sign that the
7730+ * pool may be stuck. Print pool info. Must be called with pool->lock held and
7731+ * inside a printk_deferred_enter/exit region.
7732+ */
7733+static void show_pool_no_running_worker(struct worker_pool *pool)
7734+{
7735+ lockdep_assert_held(&pool->lock);
7736+
7737+ printk_deferred_enter();
7738+ pr_info("pool %d: no worker in running state, cpu=%d is %s (nr_workers=%d nr_idle=%d)\n",
7739+ pool->id, pool->cpu,
7740+ idle_cpu(pool->cpu) ? "idle" : "busy",
7741+ pool->nr_workers, pool->nr_idle);
7742+ pr_info("The pool might have trouble waking an idle worker.\n");
7743+ printk_deferred_exit();
7744+}
7745+
7746+/*
7747+ * Show running workers that might prevent the processing of pending work items.
7748+ * If no running worker is found, the pool may be stuck waiting for an idle
7749+ * worker to be woken, so report the pool state.
77337750 */
77347751 static void show_cpu_pool_busy_workers(struct worker_pool *pool)
77357752 {
7753+ bool found_running = false;
77367754 struct worker *worker;
77377755 unsigned long irq_flags;
77387756 int bkt;
@@ -7740,6 +7758,11 @@ static void show_cpu_pool_busy_workers(struct worker_pool *pool) · 1 unmodified line
77407758 raw_spin_lock_irqsave(&pool->lock, irq_flags);
77417759
77427760 hash_for_each(pool->busy_hash, bkt, worker, hentry) {
7761+ /* Skip workers that are not actively running on the CPU. */
7762+ if (!task_is_running(worker->task))
7763+ continue;
7764+
7765+ found_running = true;
77437766 /*
77447767 * Defer printing to avoid deadlocks in console
77457768 * drivers that queue work while holding locks
@@ -7753,6 +7776,13 @@ static void show_cpu_pool_busy_workers(struct worker_pool *pool) · 7 unmodified lines
77537776 printk_deferred_exit();
77547777 }
77557778
7779+ /*
7780+ * If no running worker was found, the pool is likely stuck. Print pool
7781+ * state.
7782+ */
7783+ if (!found_running)
7784+ show_pool_no_running_worker(pool);
7785+
77567786 raw_spin_unlock_irqrestore(&pool->lock, irq_flags);
77577787 }
77587788