diff options
| author | Breno Leitao <leitao@debian.org> | 2026-07-02 09:28:00 -0700 |
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2026-07-02 07:54:10 -1000 |
| commit | ecf5aad9a4417fece80890f27a9899db90c9c457 (patch) | |
| tree | 6c53bb5fe5298a6c613f040b51fd8d9f56cc5931 | |
| parent | e73c290bd75338ab514b0c0f0e1431005a8467d7 (diff) | |
| download | linux-next-ecf5aad9a4417fece80890f27a9899db90c9c457.tar.gz linux-next-ecf5aad9a4417fece80890f27a9899db90c9c457.zip | |
workqueue: annotate racy PWQ_STAT_CPU_TIME update in wq_worker_tick()
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.
Annotate the update with data_race().
Signed-off-by: Breno Leitao <leitao@debian.org>
Signed-off-by: Tejun Heo <tj@kernel.org>
| -rw-r--r-- | kernel/workqueue.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 86b6e43d41b5..f8b5598f7272 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1535,7 +1535,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; |
