diff options
| author | Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com> | 2026-10-14 22:43:41 +0700 |
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2026-10-14 07:03:54 -1000 |
| commit | bda345b3fc59f2899c50379c64a0734a3e720683 (patch) | |
| tree | bf494e8707e818ad9c5b69ab15c920e50bc1c7af /kernel/workqueue.c | |
| parent | 9d4815c14f7faf789aeaa63515024168daf0390c (diff) | |
workqueue: mark pool->nr_running as __data_racy
wq_worker_running() increments pool->nr_running with only preemption
disabled, while kick_pool_pick() reads it via need_more_worker() under
pool->lock, so the two can run concurrently on different CPUs. KCSAN
reports:
BUG: KCSAN: data-race in kick_pool_pick / wq_worker_running
write to 0xffff888059c2af24 of 4 bytes by task 3007 on cpu 0:
wq_worker_running+0x114/0x130
schedule_timeout+0x16e/0x180
io_schedule_timeout+0x4c/0x70
submit_bio_wait+0xd7/0x110
blkdev_issue_flush+0x4c/0x70
ext4_sync_file+0x60d/0x6c0
aio_fsync_work+0x7f/0x270
process_one_work+0x4ae/0xa00
read to 0xffff888059c2af24 of 4 bytes by task 3001 on cpu 1:
kick_pool_pick+0x7a/0x3a0
__queue_work+0x72d/0xcf0
queue_work_on+0x9d/0xb0
schedule_on_each_cpu+0x11a/0x2d0
vmstat_refresh+0x23/0x140
proc_sys_call_handler+0x2b9/0x4f0
The race is benign. The increment in wq_worker_running() is the only
lockless write to nr_running; decrements and the reset are done under
pool->lock, so a reader holding the lock sees either the old or the new
count. A stale 0 costs at most a spurious wakeup of an idle worker. A
nonzero count is correct because the incrementing worker is running and
re-checks the worklist under pool->lock before it stops counting. The
increment can also go 1 -> 2, e.g. when a worker sleeping in a work item
wakes up after kick_pool() woke another worker.
The lockless increment is part of how nr_running is designed to work,
as the comment above the field documents. Mark the field __data_racy
so that every reader is covered, not just need_more_worker().
Reported-by: syzbot+8922e6b8343f70be92e8@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=8922e6b8343f70be92e8
Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'kernel/workqueue.c')
| -rw-r--r-- | kernel/workqueue.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index e618108c6127..41754f4126a6 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -212,7 +212,7 @@ struct worker_pool { * but w/ pool->lock held. The readers grab pool->lock and are * guaranteed to see if the counter reached zero. */ - int nr_running; + int __data_racy nr_running; struct list_head worklist; /* L: list of pending works */ |
