summaryrefslogtreecommitdiff
path: root/include/linux/compiler.h
diff options
context:
space:
mode:
authorQi Xi <xiqi2@huawei.com>2025-09-09 19:29:10 +0800
committerArnd Bergmann <arnd@arndb.de>2025-09-25 08:01:16 +0200
commitedcc8a38b5ac1a3dbd05e113a38a25b937ebefe5 (patch)
treecbf70fa68f768c18cf95048496a6b38cc8f8c2a5 /include/linux/compiler.h
parent8327bd4fcb6c1dab01ce5c6ff00b42496836dcd2 (diff)
once: fix race by moving DO_ONCE to separate section
The commit c2c60ea37e5b ("once: use __section(".data.once")") moved DO_ONCE's ___done variable to .data.once section, which conflicts with DO_ONCE_LITE() that also uses the same section. This creates a race condition when clear_warn_once is used: Thread 1 (DO_ONCE) Thread 2 (DO_ONCE) __do_once_start read ___done (false) acquire once_lock execute func __do_once_done write ___done (true) __do_once_start release once_lock // Thread 3 clear_warn_once reset ___done read ___done (false) acquire once_lock execute func schedule once_work __do_once_done once_deferred: OK write ___done (true) static_branch_disable release once_lock schedule once_work once_deferred: BUG_ON(!static_key_enabled) DO_ONCE_LITE() in once_lite.h is used by WARN_ON_ONCE() and other warning macros. Keep its ___done flag in the .data..once section and allow resetting by clear_warn_once, as originally intended. In contrast, DO_ONCE() is used for functions like get_random_once() and relies on its ___done flag for internal synchronization. We should not reset DO_ONCE() by clear_warn_once. Fix it by isolating DO_ONCE's ___done into a separate .data..do_once section, shielding it from clear_warn_once. Fixes: c2c60ea37e5b ("once: use __section(".data.once")") Reported-by: Hulk Robot <hulkci@huawei.com> Signed-off-by: Qi Xi <xiqi2@huawei.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'include/linux/compiler.h')
0 files changed, 0 insertions, 0 deletions