Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rcu: Use _full() API to debug synchronize_rcu()

Switch for using of get_state_synchronize_rcu_full() and
poll_state_synchronize_rcu_full() pair to debug a normal
synchronize_rcu() call.

Just using "not" full APIs to identify if a grace period is
passed or not might lead to a false-positive kernel splat.

It can happen, because get_state_synchronize_rcu() compresses
both normal and expedited states into one single unsigned long
value, so a poll_state_synchronize_rcu() can miss GP-completion
when synchronize_rcu()/synchronize_rcu_expedited() concurrently
run.

To address this, switch to poll_state_synchronize_rcu_full() and
get_state_synchronize_rcu_full() APIs, which use separate variables
for expedited and normal states.

Reported-by: cheung wall <zzqq0103.hey@gmail.com>
Closes: https://lore.kernel.org/lkml/Z5ikQeVmVdsWQrdD@pc636/T/
Fixes: 988f569ae041 ("rcu: Reduce synchronize_rcu() latency")
Signed-off-by: Uladzislau Rezki (Sony) <urezki@gmail.com>
Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
Link: https://lore.kernel.org/r/20250227131613.52683-3-urezki@gmail.com
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>

authored by

Uladzislau Rezki (Sony) and committed by
Boqun Feng
5a562b8b a6cea395

+6 -5
+3
include/linux/rcupdate_wait.h
··· 16 16 struct rcu_synchronize { 17 17 struct rcu_head head; 18 18 struct completion completion; 19 + 20 + /* This is for debugging. */ 21 + struct rcu_gp_oldstate oldstate; 19 22 }; 20 23 void wakeme_after_rcu(struct rcu_head *head); 21 24
+3 -5
kernel/rcu/tree.c
··· 1612 1612 { 1613 1613 struct rcu_synchronize *rs = container_of( 1614 1614 (struct rcu_head *) node, struct rcu_synchronize, head); 1615 - unsigned long oldstate = (unsigned long) rs->head.func; 1616 1615 1617 1616 WARN_ONCE(IS_ENABLED(CONFIG_PROVE_RCU) && 1618 - !poll_state_synchronize_rcu(oldstate), 1619 - "A full grace period is not passed yet: %lu", 1620 - rcu_seq_diff(get_state_synchronize_rcu(), oldstate)); 1617 + !poll_state_synchronize_rcu_full(&rs->oldstate), 1618 + "A full grace period is not passed yet!\n"); 1621 1619 1622 1620 /* Finally. */ 1623 1621 complete(&rs->completion); ··· 3216 3218 * snapshot before adding a request. 3217 3219 */ 3218 3220 if (IS_ENABLED(CONFIG_PROVE_RCU)) 3219 - rs.head.func = (void *) get_state_synchronize_rcu(); 3221 + get_state_synchronize_rcu_full(&rs.oldstate); 3220 3222 3221 3223 rcu_sr_normal_add_req(&rs); 3222 3224