[tip: locking/core] locking/percpu-rwsem: Annotate intentional data race in readers_active_check()

tip-bot2 for Sun Shaojie posted 1 patch 2 months ago
kernel/locking/percpu-rwsem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
[tip: locking/core] locking/percpu-rwsem: Annotate intentional data race in readers_active_check()
Posted by tip-bot2 for Sun Shaojie 2 months ago
The following commit has been merged into the locking/core branch of tip:

Commit-ID:     c9c8578ad58e66a64ca887731e2b6ebf9d71174b
Gitweb:        https://git.kernel.org/tip/c9c8578ad58e66a64ca887731e2b6ebf9d71174b
Author:        Sun Shaojie <sunshaojie@kylinos.cn>
AuthorDate:    Tue, 23 Jun 2026 18:41:32 +08:00
Committer:     Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 31 Jul 2026 10:32:25 +02:00

locking/percpu-rwsem: Annotate intentional data race in readers_active_check()

KCSAN reports a data race between readers_active_check() and a
concurrently executing reader:

  BUG: KCSAN: data-race in readers_active_check / percpu_down_write

  race at unknown origin, with read to 0xffff9f3eb5bf5f30 of 4 bytes
  by task 1271 on cpu 14:
   readers_active_check+0x...
   percpu_down_write+0x152/0x1f0

  value changed: 0xfffffff9 -> 0xfffffff8

readers_active_check() calls per_cpu_sum(*sem->read_count), which
iterates over all CPUs and reads each CPU's per-CPU read_count
variable.  Concurrently, a reader on a remote CPU is modifying its own
CPU's read_count via this_cpu_inc() / this_cpu_dec() as it enters and
exits the critical section.  These are plain reads and writes to the
same per-CPU storage, hence KCSAN flags a data race.

This race is benign.  readers_active_check() is called from the
percpu_down_write() wait loop (rcuwait_wait_event) after sem->block is
already set.  At this point:

  - New readers must immediately back out (they see block set, decrement
    their counter, and wake the writer), so counters can only decrease.

  - If the sum catches a reader's increment before its decrement,
    readers_active_check() sees a non-zero sum and returns false.  The
    writer merely iterates the wait loop again -- a harmless retry.

  - A false zero (observing sum == 0 while a reader is still active)
    cannot happen: per_cpu_sum() reads each CPU's counter, and each
    per-CPU int read is atomic on all architectures, so an active
    reader's counter is always seen as non-zero.

Annotate the read with data_race() to suppress the KCSAN warning and
document the intentional nature of this unlocked access.

Signed-off-by: Sun Shaojie <sunshaojie@kylinos.cn>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260623104132.505117-1-sunshaojie@kylinos.cn
---
 kernel/locking/percpu-rwsem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/locking/percpu-rwsem.c b/kernel/locking/percpu-rwsem.c
index f7e152c..6c78961 100644
--- a/kernel/locking/percpu-rwsem.c
+++ b/kernel/locking/percpu-rwsem.c
@@ -211,7 +211,7 @@ EXPORT_SYMBOL_GPL(percpu_is_read_locked);
  */
 static bool readers_active_check(struct percpu_rw_semaphore *sem)
 {
-	if (per_cpu_sum(*sem->read_count) != 0)
+	if (data_race(per_cpu_sum(*sem->read_count)) != 0)
 		return false;
 
 	/*