From d070f2916ae918c4dddadce6160576c070efcd3e Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 26 Jun 2026 02:57:54 -0700 Subject: workqueue: defer the worker wakeup outside pool->lock in __queue_work() __queue_work() is the enqueue hot path: it inserts the work item and calls kick_pool() while holding pool->lock. kick_pool() ends in a wakeup, which takes the target task's rq->lock, so rq->lock nests under pool->lock on every enqueue that wakes a worker on a contended unbound pool. Use kick_pool_pick() to select and claim the worker under pool->lock and issue the wakeup with wake_up_process() right after dropping the lock. Signed-off-by: Breno Leitao Signed-off-by: Tejun Heo --- kernel/workqueue.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'kernel/workqueue.c') diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 49770093e785..2d41000c918f 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -2302,6 +2302,7 @@ static void __queue_work(int cpu, struct workqueue_struct *wq, { struct pool_workqueue *pwq; struct worker_pool *last_pool, *pool; + struct task_struct *wake_task = NULL; unsigned int work_flags; unsigned int req_cpu = cpu; @@ -2424,7 +2425,7 @@ retry: trace_workqueue_activate_work(work); insert_work(pwq, work, &pool->worklist, work_flags); - kick_pool(pool); + kick_pool_pick(pool, &wake_task); } else { work_flags |= WORK_STRUCT_INACTIVE; insert_work(pwq, work, &pwq->inactive_works, work_flags); @@ -2432,6 +2433,8 @@ retry: out: raw_spin_unlock(&pool->lock); + if (wake_task) + wake_up_process(wake_task); rcu_read_unlock(); } -- cgit v1.2.3