[PATCH] workqueue: read p->wake_cpu once in kick_pool_pick()

From: Breno Leitao

Date: Wed Aug 05 2026 - 07:33:16 EST


kick_pool_pick() reads p->wake_cpu in a racy way with scheduler. This
gets the following message in KCSAN

BUG: KCSAN: data-race in kick_pool_pick+0xf8/0x2d8

race at unknown origin, with read to 0xffff000663229da4 of 4 bytes by
task 1817002 on cpu 40:
kick_pool_pick+0xf8/0x2d8
process_scheduled_works+0x2bc/0x888
worker_thread+0x394/0x548
kthread+0x1b8/0x1f0
ret_from_fork+0x10/0x20

value changed: 0x0000002b -> 0x0000002f

Mark p->wake_cpu's read as READ_ONCE(p->wake_cpu), in order to a) avoid
torn down reads, b) acknowledge this racy read, and c) silent KCSAN.

Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx>
---
kernel/workqueue.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 26d5680c751c6..333752ac38298 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1308,8 +1308,10 @@ static bool kick_pool_pick(struct worker_pool *pool, struct task_struct **wakep)
* If @pool has non-strict affinity, @worker might have ended up outside
* its affinity scope. Repatriate.
*/
- if (!pool->attrs->affn_strict &&
- !cpumask_test_cpu(p->wake_cpu, pool->attrs->__pod_cpumask)) {
+ bool wake_cpu_in_pod = cpumask_test_cpu(READ_ONCE(p->wake_cpu),
+ pool->attrs->__pod_cpumask);
+
+ if (!pool->attrs->affn_strict && !wake_cpu_in_pod) {
struct work_struct *work = list_first_entry(&pool->worklist,
struct work_struct, entry);
int wake_cpu = cpumask_any_and_distribute(pool->attrs->__pod_cpumask,

---
base-commit: 0f6da28aab51b16762ed82e8fdeaa5042da45b08
change-id: 20260805-wq_race_kick-d7ae5c14258d

Best regards,
--
Breno Leitao <leitao@xxxxxxxxxx>