workqueue: annotate racy p->wake_cpu accesses in kick_pool_pick()

kick_pool_pick() reads and writes p->wake_cpu while the scheduler can
update it concurrently. KCSAN reports:

  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

The race is harmless. wake_cpu is a best-effort placement hint: every
writer stores a valid CPU id and the wakeup path validates it through
select_task_rq(), so a stale value only affects which CPU the worker
wakes up on.

Mark both accesses with READ_ONCE() and WRITE_ONCE() to document that
they are intentionally racy and to stop the compiler from reloading or
tearing them.

Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Bradley Morgan <include@grrlz.net>
Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
Breno Leitao 2026-08-13 06:12:12 -07:00 committed by Tejun Heo
parent 4e0ee51cc2
commit 20a80e7f6b

View File

@ -1309,13 +1309,14 @@ static bool kick_pool_pick(struct worker_pool *pool, struct task_struct **wakep)
* its affinity scope. Repatriate.
*/
if (!pool->attrs->affn_strict &&
!cpumask_test_cpu(p->wake_cpu, pool->attrs->__pod_cpumask)) {
!cpumask_test_cpu(READ_ONCE(p->wake_cpu),
pool->attrs->__pod_cpumask)) {
struct work_struct *work = list_first_entry(&pool->worklist,
struct work_struct, entry);
int wake_cpu = cpumask_any_and_distribute(pool->attrs->__pod_cpumask,
cpu_online_mask);
if (wake_cpu < nr_cpu_ids) {
p->wake_cpu = wake_cpu;
WRITE_ONCE(p->wake_cpu, wake_cpu);
get_work_pwq(work)->stats[PWQ_STAT_REPATRIATED]++;
}
}