From f504706a25eb3462cc00c76340feb6751f9e37f9 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 26 Jun 2026 02:57:55 -0700 Subject: workqueue: defer the worker wakeup outside pool->lock in process_one_work() Use kick_pool_pick() to select and claim the worker under pool->lock and issue the wakeup with wake_up_process() after the lock is dropped. Unlike __queue_work(), this path has no surrounding RCU section, so take rcu_read_lock() before dropping pool->lock to keep the picked worker's task_struct valid across the wakeup. Signed-off-by: Breno Leitao Tested-by: Krishna Magar Signed-off-by: Tejun Heo --- kernel/workqueue.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'kernel/workqueue.c') diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 2d41000c918f..c647031d5bd7 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -3251,6 +3251,7 @@ __acquires(&pool->lock) { struct pool_workqueue *pwq = get_work_pwq(work); struct worker_pool *pool = worker->pool; + struct task_struct *wake_task = NULL; unsigned long work_data; int lockdep_start_depth, rcu_start_depth; bool bh_draining = pool->flags & POOL_BH_DRAINING; @@ -3304,8 +3305,11 @@ __acquires(&pool->lock) * since nr_running would always be >= 1 at this point. This is used to * chain execution of the pending work items for WORKER_NOT_RUNNING * workers such as the UNBOUND and CPU_INTENSIVE ones. + * + * Select the worker under pool->lock; the wakeup is deferred until + * after the lock is dropped, guarded by the rcu_read_lock() below. */ - kick_pool(pool); + kick_pool_pick(pool, &wake_task); /* * Record the last pool and clear PENDING which should be the last @@ -3316,7 +3320,12 @@ __acquires(&pool->lock) set_work_pool_and_clear_pending(work, pool->id, pool_offq_flags(pool)); pwq->stats[PWQ_STAT_STARTED]++; + + rcu_read_lock(); raw_spin_unlock_irq(&pool->lock); + if (wake_task) + wake_up_process(wake_task); + rcu_read_unlock(); rcu_start_depth = rcu_preempt_depth(); lockdep_start_depth = lockdep_depth(current); -- cgit v1.2.3