To identify the task most likely responsible for a stall, add last_woken_worker (L: pool->lock) to worker_pool and record it in kick_pool() just before wake_up_process(). This captures the idle worker that was kicked to take over when the last running worker went to sleep; if the pool is now stuck with no running worker, that task is the prime suspect and its backtrace is dumped by show_pool_no_running_worker(). Using struct worker * rather than struct task_struct * avoids any lifetime concern: workers are only destroyed via set_worker_dying() which requires pool->lock, and set_worker_dying() clears last_woken_worker when the dying worker matches. show_cpu_pool_busy_workers() holds pool->lock while calling sched_show_task(), so last_woken_worker is either NULL or points to a live worker with a valid task. More precisely, set_worker_dying() clears last_woken_worker before setting WORKER_DIE, so a non-NULL last_woken_worker means the kthread has not yet exited and worker->task is still alive.
Showing the changes to kernel/workqueue.c (1 of 1 file). Show all
Unified · Split
| @@ -226,6 +226,8 @@ struct worker_pool { · 225 unmodified lines | ||
| 226 | 226 | /* L: hash of busy workers */ |
| 227 | 227 | |
| 228 | 228 | struct worker *manager; /* L: purely informational */ |
| 229 | + /* L: last worker woken by kick_pool() */ | |
| 230 | + struct worker *last_woken_worker; | |
| 229 | 231 | struct list_head workers; /* A: attached workers */ |
| 230 | 232 | |
| 231 | 233 | struct ida worker_ida; /* worker IDs for task name */ |
| @@ -1318,6 +1320,9 @@ static bool kick_pool_pick(struct worker_pool *pool, struct task_struct **wakep) · 1086 unmodified lines | ||
| 1318 | 1320 | } |
| 1319 | 1321 | } |
| 1320 | 1322 | #endif |
| 1323 | + /* Track the last idle worker woken, used for stall diagnostics. */ | |
| 1324 | + pool->last_woken_worker = worker; | |
| 1325 | + | |
| 1321 | 1326 | *wakep = p; |
| 1322 | 1327 | return true; |
| 1323 | 1328 | } |
| @@ -2976,6 +2981,13 @@ static void set_worker_dying(struct worker *worker, struct list_head *list) · 1652 unmodified lines | ||
| 2976 | 2981 | pool->nr_workers--; |
| 2977 | 2982 | pool->nr_idle--; |
| 2978 | 2983 | |
| 2984 | + /* | |
| 2985 | + * Clear last_woken_worker if it points to this worker, so that | |
| 2986 | + * show_cpu_pool_busy_workers() cannot dereference a freed worker. | |
| 2987 | + */ | |
| 2988 | + if (pool->last_woken_worker == worker) | |
| 2989 | + pool->last_woken_worker = NULL; | |
| 2990 | + | |
| 2979 | 2991 | worker->flags |= WORKER_DIE; |
| 2980 | 2992 | |
| 2981 | 2993 | list_move(&worker->entry, list); |
| @@ -7740,13 +7752,25 @@ static void show_pool_no_running_worker(struct worker_pool *pool) · 4758 unmodified lines | ||
| 7740 | 7752 | idle_cpu(pool->cpu) ? "idle" : "busy", |
| 7741 | 7753 | pool->nr_workers, pool->nr_idle); |
| 7742 | 7754 | pr_info("The pool might have trouble waking an idle worker.\n"); |
| 7755 | + /* | |
| 7756 | + * last_woken_worker and its task are valid here: set_worker_dying() | |
| 7757 | + * clears it under pool->lock before setting WORKER_DIE, so if | |
| 7758 | + * last_woken_worker is non-NULL the kthread has not yet exited and | |
| 7759 | + * worker->task is still alive. | |
| 7760 | + */ | |
| 7761 | + if (pool->last_woken_worker) { | |
| 7762 | + pr_info("Backtrace of last woken worker:\n"); | |
| 7763 | + sched_show_task(pool->last_woken_worker->task); | |
| 7764 | + } else { | |
| 7765 | + pr_info("Last woken worker empty\n"); | |
| 7766 | + } | |
| 7743 | 7767 | printk_deferred_exit(); |
| 7744 | 7768 | } |
| 7745 | 7769 | |
| 7746 | 7770 | /* |
| 7747 | 7771 | * Show running workers that might prevent the processing of pending work items. |
| 7748 | 7772 | * 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. | |
| 7773 | + * worker to be woken, so report the pool state and the last woken worker. | |
| 7750 | 7774 | */ |
| 7751 | 7775 | static void show_cpu_pool_busy_workers(struct worker_pool *pool) |
| 7752 | 7776 | { |
| @@ -7781,7 +7805,8 @@ static void show_cpu_pool_busy_workers(struct worker_pool *pool) · 28 unmodified lines | ||
| 7781 | 7805 | |
| 7782 | 7806 | /* |
| 7783 | 7807 | * If no running worker was found, the pool is likely stuck. Print pool |
| 7784 | − * state. | |
| 7808 | + * state and the backtrace of the last woken worker, which is the prime | |
| 7809 | + * suspect for the stall. | |
| 7785 | 7810 | */ |
| 7786 | 7811 | if (!found_running) |
| 7787 | 7812 | show_pool_no_running_worker(pool); |