* [PATCH] workqueue: annotate racy PWQ_STAT_CPU_TIME update in wq_worker_tick()
@ 2026-07-02 16:28 Breno Leitao
2026-07-02 17:58 ` Tejun Heo
0 siblings, 1 reply; 3+ messages in thread
From: Breno Leitao @ 2026-07-02 16:28 UTC (permalink / raw)
To: Tejun Heo, Lai Jiangshan
Cc: linux-kernel, kernel-team, marco.crivellari, Breno Leitao
wq_worker_tick() bumps pwq->stats[PWQ_STAT_CPU_TIME] on every scheduler
tick before pool->lock is taken. For unbound workqueues the
pool_workqueue is shared by all workers of the pool across CPUs, so
concurrent ticks on different CPUs perform an unsynchronized 64-bit
read-modify-write on the same counter. KCSAN reports this as a
data-race:
BUG: KCSAN: data-race in wq_worker_tick / wq_worker_tick
read-write to 0xffff0004d6989500 of 8 bytes by interrupt on cpu 29:
wq_worker_tick+0x70/0x418
sched_tick+0x248/0x3a0
update_process_times+0x200/0x260
tick_nohz_handler+0x230/0x2f8
__hrtimer_run_queues+0x1ec/0x6c8
hrtimer_interrupt+0x174/0x4b8
...
read-write to 0xffff0004d6989500 of 8 bytes by interrupt on cpu 24:
wq_worker_tick+0x70/0x418
sched_tick+0x248/0x3a0
...
value changed: 0x000000000010a1d0 -> 0x000000000010a9a0
The counter is purely advisory, so an occasional lost update is
harmless, and every other stats[] update already runs under pool->lock.
Options I've considered:
1) Lock, but it will add contention to the tick fast path for no
functional benefit
2) WRITE_ONCE() would solve the problem as well, but slightly more
intrusive
3) data_race() just to silently tell KCSAN this is fine.
Signed-off-by: Breno Leitao <leitao@debian.org>
---
kernel/workqueue.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index a5fa5d8d3ef92..bbcbc52d84c4b 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1530,7 +1530,11 @@ void wq_worker_tick(struct task_struct *task)
if (!pwq)
return;
- pwq->stats[PWQ_STAT_CPU_TIME] += TICK_USEC;
+ /*
+ * @pwq is shared across CPUs for unbound wqs and this advisory stat is
+ * bumped outside pool->lock, so the update is intentionally racy.
+ */
+ data_race(pwq->stats[PWQ_STAT_CPU_TIME] += TICK_USEC);
if (!wq_cpu_intensive_thresh_us)
return;
---
base-commit: 4f441960e691d37c880d2cc004de06bb5b6bd5e4
change-id: 20260702-wq-cpu-time-data-race-6424e01c5090
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-03 8:14 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-02 16:28 [PATCH] workqueue: annotate racy PWQ_STAT_CPU_TIME update in wq_worker_tick() Breno Leitao
2026-07-02 17:58 ` Tejun Heo
2026-07-03 8:14 ` Breno Leitao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox