Skip to content

Commit 5a562b8

Browse files
urezkifbq
authored andcommitted
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: 988f569 ("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>
1 parent a6cea39 commit 5a562b8

File tree

2 files changed

+6
-5
lines changed

2 files changed

+6
-5
lines changed

include/linux/rcupdate_wait.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
struct rcu_synchronize {
1717
struct rcu_head head;
1818
struct completion completion;
19+
20+
/* This is for debugging. */
21+
struct rcu_gp_oldstate oldstate;
1922
};
2023
void wakeme_after_rcu(struct rcu_head *head);
2124

kernel/rcu/tree.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,12 +1612,10 @@ static void rcu_sr_normal_complete(struct llist_node *node)
16121612
{
16131613
struct rcu_synchronize *rs = container_of(
16141614
(struct rcu_head *) node, struct rcu_synchronize, head);
1615-
unsigned long oldstate = (unsigned long) rs->head.func;
16161615

16171616
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");
16211619

16221620
/* Finally. */
16231621
complete(&rs->completion);
@@ -3218,7 +3216,7 @@ static void synchronize_rcu_normal(void)
32183216
* snapshot before adding a request.
32193217
*/
32203218
if (IS_ENABLED(CONFIG_PROVE_RCU))
3221-
rs.head.func = (void *) get_state_synchronize_rcu();
3219+
get_state_synchronize_rcu_full(&rs.oldstate);
32223220

32233221
rcu_sr_normal_add_req(&rs);
32243222

0 commit comments

Comments
 (0)