Re: [PATCH v4 2/8] rcu: clear defer_qs_pending when notifying GP changes

"Paul E. McKenney" <[email protected]> Wed, 15 Jul 2026 13:45:56 -0700
Newsgroups org.kernel.vger.rcu,org.kernel.vger.linux-kernel
Message-ID <b4a72949-d816-447f-9c9e-93b33ddf6aae@paulmck-laptop>
On Thu, Jun 25, 2026 at 08:42:55PM -0400, Joel Fernandes wrote:
> Prior to this commit, defer_qs_pending was an unbalanced flag:
> rcu_read_unlock_special() set it to PENDING whenever a deferred-QS
> mechanism was scheduled, but the clear paths did not cover every
> up-tree quiescent-state reporting site. In those cases the flag stays
> PENDING after the QS is reported, and rcu_read_unlock_special()'s
> pending-gate then silently rejects all future arming attempts.
> 
> A test patch confirms TREE03 can have get into the problematic stuck
> state very quickly (< 5 minutes).
> 
> Clear the flag in __note_gp_changes(), right after the nothing-to-do
> early return.  This is the natural per-CPU "GP transitioned, sync local
> state" hook, called from the GP-kthread's rcu_gp_init()/rcu_gp_cleanup()
> paths, and other GP advancement paths.
> 
> For dynticks-idle CPUs, they do not call __note_gp_changes(), but they
> also do not arm new PENDING work (no readers running), and on wake-up,
> note_gp_changes() is called before any new reader runs.
> 
> Signed-off-by: Joel Fernandes <[email protected]>

This looks plausible, but suppose we have the following:

	rcu_read_lock();
	// expedited GP plus preemption.
	preempt_disable();
	rcu_read_unlock(); // Sets ->defer_qs_pending
	// CPU takes unrelated interrupt, softirq handled, kicks
	// scheduler, and clears ->defer_qs_pending. Note that preemption
	// is disabled, so rcu_core() does set_need_resched_current()
	local_irq_disable();
	preempt_enable(); // Cannot reschedule here.
	local_irq_enable();

When do quiescent states get reported?

							Thanx, Paul

> ---
>  kernel/rcu/tree.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> index e86a8c0d7b4c..c4352d0c3876 100644
> --- a/kernel/rcu/tree.c
> +++ b/kernel/rcu/tree.c
> @@ -1281,6 +1281,8 @@ static bool __note_gp_changes(struct rcu_node *rnp, struct rcu_data *rdp)
>  	if (rdp->gp_seq == rnp->gp_seq)
>  		return false; /* Nothing to do. */
>  
> +	rcu_defer_qs_clear(rdp);
> +
>  	/* Handle the ends of any preceding grace periods first. */
>  	if (rcu_seq_completed_gp(rdp->gp_seq, rnp->gp_seq) ||
>  	    unlikely(rdp->gpwrap)) {
> -- 
> 2.34.1
>