Even when rcu_pending() triggers rcu_core(), the normal callback
advancement path through note_gp_changes() -> __note_gp_changes() bails
out when rdp->gp_seq == rnp->gp_seq (no normal GP change). Since
expedited GPs do not update rnp->gp_seq, rcu_advance_cbs() is never
called and callbacks remain stuck in RCU_WAIT_TAIL.

Add a direct callback advancement block in rcu_core() that checks for GP
completion via rcu_segcblist_nextgp() combined with
poll_state_synchronize_rcu_full(). When detected, trylock rnp and call
rcu_advance_cbs() to move completed callbacks to RCU_DONE_TAIL. Wake the
GP kthread if rcu_advance_cbs() requests a new grace period.

Uses trylock to avoid adding contention on rnp->lock. If the lock is
contended, callbacks will be advanced on the next tick.

Reviewed-by: Paul E. McKenney <[email protected]>
Signed-off-by: Puranjay Mohan <[email protected]>
---
 kernel/rcu/tree.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 309273a37b0a..1a92b6105de5 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -2853,6 +2853,22 @@ static __latent_entropy void rcu_core(void)
        /* Update RCU state based on any recent quiescent states. */
        rcu_check_quiescent_state(rdp);
 
+       /* Advance callbacks if an expedited GP has completed. */
+       if (!rcu_rdp_is_offloaded(rdp) &&
+           rcu_segcblist_is_enabled(&rdp->cblist)) {
+               struct rcu_gp_oldstate gp_state;
+
+               if (rcu_segcblist_nextgp(&rdp->cblist, &gp_state) &&
+                   poll_state_synchronize_rcu_full(&gp_state)) {
+                       guard(irqsave)();
+                       if (raw_spin_trylock_rcu_node(rnp)) {
+                               if (rcu_advance_cbs(rnp, rdp))
+                                       rcu_gp_kthread_wake();
+                               raw_spin_unlock_rcu_node(rnp);
+                       }
+               }
+       }
+
        /* No grace period and unregistered callbacks? */
        if (!rcu_gp_in_progress() &&
            rcu_segcblist_is_enabled(&rdp->cblist) && 
!rcu_rdp_is_offloaded(rdp)) {
-- 
2.52.0


Reply via email to