* [PATCH v4 1/8] rcu: introduce rcu_defer_qs_clear() helper
2026-06-26 0:42 [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
@ 2026-06-26 0:42 ` Joel Fernandes
2026-07-15 20:43 ` Paul E. McKenney
2026-06-26 0:42 ` [PATCH v4 2/8] rcu: clear defer_qs_pending when notifying GP changes Joel Fernandes
` (8 subsequent siblings)
9 siblings, 1 reply; 19+ messages in thread
From: Joel Fernandes @ 2026-06-26 0:42 UTC (permalink / raw)
To: linux-kernel
Cc: Paul E . McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu,
Joel Fernandes
Currently rdp->defer_qs_pending transitions from DEFER_QS_PENDING to
DEFER_QS_IDLE at two sites: rcu_preempt_deferred_qs_irqrestore() and
rcu_preempt_deferred_qs_handler() (depth>0 reset). Both write the
IDLE value directly.
Introduce a single inline helper rcu_defer_qs_clear() in tree.h and
route both sites through it. This becomes the single
PENDING->IDLE transition point for upcoming work.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
kernel/rcu/tree.h | 5 +++++
kernel/rcu/tree_plugin.h | 4 ++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index 750b98f0c6bc..dc03231b2d46 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -311,6 +311,11 @@ struct rcu_data {
int cpu;
};
+static inline void rcu_defer_qs_clear(struct rcu_data *rdp)
+{
+ WRITE_ONCE(rdp->defer_qs_pending, DEFER_QS_IDLE);
+}
+
/* Values for nocb_defer_wakeup field in struct rcu_data. */
#define RCU_NOCB_WAKE_NOT 0
#define RCU_NOCB_WAKE_BYPASS 1
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index c22f033e0136..7555022bf38a 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -582,7 +582,7 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
rdp = this_cpu_ptr(&rcu_data);
if (rdp->defer_qs_pending == DEFER_QS_PENDING)
- rdp->defer_qs_pending = DEFER_QS_IDLE;
+ rcu_defer_qs_clear(rdp);
/*
* If RCU core is waiting for this CPU to exit its critical section,
@@ -725,7 +725,7 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp)
* 5. Deferred QS reporting does not happen.
*/
if (rcu_preempt_depth() > 0)
- WRITE_ONCE(rdp->defer_qs_pending, DEFER_QS_IDLE);
+ rcu_defer_qs_clear(rdp);
}
/*
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH v4 1/8] rcu: introduce rcu_defer_qs_clear() helper
2026-06-26 0:42 ` [PATCH v4 1/8] rcu: introduce rcu_defer_qs_clear() helper Joel Fernandes
@ 2026-07-15 20:43 ` Paul E. McKenney
0 siblings, 0 replies; 19+ messages in thread
From: Paul E. McKenney @ 2026-07-15 20:43 UTC (permalink / raw)
To: Joel Fernandes
Cc: linux-kernel, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu
On Thu, Jun 25, 2026 at 08:42:54PM -0400, Joel Fernandes wrote:
> Currently rdp->defer_qs_pending transitions from DEFER_QS_PENDING to
> DEFER_QS_IDLE at two sites: rcu_preempt_deferred_qs_irqrestore() and
> rcu_preempt_deferred_qs_handler() (depth>0 reset). Both write the
> IDLE value directly.
>
> Introduce a single inline helper rcu_defer_qs_clear() in tree.h and
> route both sites through it. This becomes the single
> PENDING->IDLE transition point for upcoming work.
>
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
No argument here, and I have pulled this in for further review and
testing. I don't see any reason why thing cannot go into the upcoming
merge window.
Thanx, Paul
> ---
> kernel/rcu/tree.h | 5 +++++
> kernel/rcu/tree_plugin.h | 4 ++--
> 2 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
> index 750b98f0c6bc..dc03231b2d46 100644
> --- a/kernel/rcu/tree.h
> +++ b/kernel/rcu/tree.h
> @@ -311,6 +311,11 @@ struct rcu_data {
> int cpu;
> };
>
> +static inline void rcu_defer_qs_clear(struct rcu_data *rdp)
> +{
> + WRITE_ONCE(rdp->defer_qs_pending, DEFER_QS_IDLE);
> +}
> +
> /* Values for nocb_defer_wakeup field in struct rcu_data. */
> #define RCU_NOCB_WAKE_NOT 0
> #define RCU_NOCB_WAKE_BYPASS 1
> diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
> index c22f033e0136..7555022bf38a 100644
> --- a/kernel/rcu/tree_plugin.h
> +++ b/kernel/rcu/tree_plugin.h
> @@ -582,7 +582,7 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
>
> rdp = this_cpu_ptr(&rcu_data);
> if (rdp->defer_qs_pending == DEFER_QS_PENDING)
> - rdp->defer_qs_pending = DEFER_QS_IDLE;
> + rcu_defer_qs_clear(rdp);
>
> /*
> * If RCU core is waiting for this CPU to exit its critical section,
> @@ -725,7 +725,7 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp)
> * 5. Deferred QS reporting does not happen.
> */
> if (rcu_preempt_depth() > 0)
> - WRITE_ONCE(rdp->defer_qs_pending, DEFER_QS_IDLE);
> + rcu_defer_qs_clear(rdp);
> }
>
> /*
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v4 2/8] rcu: clear defer_qs_pending when notifying GP changes
2026-06-26 0:42 [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
2026-06-26 0:42 ` [PATCH v4 1/8] rcu: introduce rcu_defer_qs_clear() helper Joel Fernandes
@ 2026-06-26 0:42 ` Joel Fernandes
2026-07-15 20:45 ` Paul E. McKenney
2026-06-26 0:42 ` [PATCH v4 3/8] rcu: clear defer_qs_pending in handler for compounded sections Joel Fernandes
` (7 subsequent siblings)
9 siblings, 1 reply; 19+ messages in thread
From: Joel Fernandes @ 2026-06-26 0:42 UTC (permalink / raw)
To: linux-kernel
Cc: Paul E . McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu,
Joel Fernandes
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 <joelagnelf@nvidia.com>
---
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
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH v4 2/8] rcu: clear defer_qs_pending when notifying GP changes
2026-06-26 0:42 ` [PATCH v4 2/8] rcu: clear defer_qs_pending when notifying GP changes Joel Fernandes
@ 2026-07-15 20:45 ` Paul E. McKenney
0 siblings, 0 replies; 19+ messages in thread
From: Paul E. McKenney @ 2026-07-15 20:45 UTC (permalink / raw)
To: Joel Fernandes
Cc: linux-kernel, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu
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 <joelagnelf@nvidia.com>
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
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v4 3/8] rcu: clear defer_qs_pending in handler for compounded sections
2026-06-26 0:42 [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
2026-06-26 0:42 ` [PATCH v4 1/8] rcu: introduce rcu_defer_qs_clear() helper Joel Fernandes
2026-06-26 0:42 ` [PATCH v4 2/8] rcu: clear defer_qs_pending when notifying GP changes Joel Fernandes
@ 2026-06-26 0:42 ` Joel Fernandes
2026-07-15 20:50 ` Paul E. McKenney
2026-06-26 0:42 ` [PATCH v4 4/8] rcu: drop redundant defer_qs_pending clear in irqrestore handler Joel Fernandes
` (6 subsequent siblings)
9 siblings, 1 reply; 19+ messages in thread
From: Joel Fernandes @ 2026-06-26 0:42 UTC (permalink / raw)
To: linux-kernel
Cc: Paul E . McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu,
Joel Fernandes
The deferred-QS irq-work handler previously cleared defer_qs_pending
only when the handler ran inside an active rcu_read_lock() critical
section (rcu_preempt_depth() > 0). Paul McKenney pointed out a common
multi-segment compound pattern where the handler fires between
segments and segment N+1's arming attempt is silently suppressed by
the rcu_read_unlock_special() pending-gate:
rcu_read_lock(); // segment 1 starts
// may be preempted/boosted here
local_irq_disable();
rcu_read_unlock(); // segment 1 ends; arms defer_qs_pending
preempt_disable();
local_irq_enable(); // handler MAY fire here: depth==0, but
// but preempt is disabled, so it cant
// nudge.
rcu_read_lock(); // segment 2 starts
preempt_enable();
local_irq_disable();
rcu_read_unlock(); // arming attempt suppressed incorrectly -- (1)
local_irq_enable();
Waiting for the next __note_gp_changes() clear is too slow for the
compound case, we need the deferred QS report sooner.
Therefore, make the irq_work handler clear defer_qs_pending whenever
rcu_in_compounded_section() is true so that (1) can do the arming.
In addition, introduce rcu_preempt_deferred_qs_try_report(), a small
helper that reports the deferred QS (and releases any RCU priority
boost) directly, but only from a clean, non-reader/compound context.
When the handler lands in such a clean context it now reports the QS
directly instead of merely nudging the scheduler: this makes the
irq_work robust under preempt=none / voluntary, where a
set_need_resched() nudge would not enter __schedule() at IRQ exit and
the QS would otherwise wait for the next tick. When still compounded,
the handler falls back to clearing defer_qs_pending as before. The
bounded-delay rescue hrtimer added in a later patch reuses this same
helper.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
kernel/rcu/tree_plugin.h | 46 ++++++++++++++++++++++++++++------------
1 file changed, 33 insertions(+), 13 deletions(-)
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 7555022bf38a..7768a40677a4 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -702,7 +702,32 @@ notrace void rcu_preempt_deferred_qs(struct task_struct *t)
}
/*
- * Minimal handler to give the scheduler a chance to re-evaluate.
+ * Report a deferred quiescent state but only from a safe context.
+ *
+ * Both callers (the irq_work handler and the bounded-delay rescue hrtimer)
+ * run in hardirq context, so preempt_count() always has the HARDIRQ bit set;
+ * the compound-section check below deliberately inspects only the
+ * PREEMPT_MASK | SOFTIRQ_MASK bits, which reflect the INTERRUPTED caller's
+ * state, not ours.
+ */
+static bool rcu_preempt_deferred_qs_try_report(struct task_struct *t)
+{
+ unsigned long flags;
+
+ if (rcu_preempt_depth() > 0 ||
+ (preempt_count() & (PREEMPT_MASK | SOFTIRQ_MASK)))
+ return false;
+
+ if (rcu_preempt_need_deferred_qs(t)) {
+ local_irq_save(flags);
+ rcu_preempt_deferred_qs_irqrestore(t, flags);
+ }
+ return true;
+}
+
+/*
+ * Minimal handler to give the scheduler a chance to re-evaluate, and to
+ * report the deferred QS directly when the handler lands in a clean context.
*/
static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp)
{
@@ -712,19 +737,14 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp)
rdp = container_of(iwp, struct rcu_data, defer_qs_iw);
/*
- * If the IRQ work handler happens to run in the middle of RCU read-side
- * critical section, it could be ineffective in getting the scheduler's
- * attention to report a deferred quiescent state (the whole point of the
- * IRQ work). For this reason, requeue the IRQ work.
- *
- * Basically, we want to avoid following situation:
- * 1. rcu_read_unlock() queues IRQ work (state -> DEFER_QS_PENDING)
- * 2. CPU enters new rcu_read_lock()
- * 3. IRQ work runs but cannot report QS due to rcu_preempt_depth() > 0
- * 4. rcu_read_unlock() does not re-queue work (state still PENDING)
- * 5. Deferred QS reporting does not happen.
+ * If the handler fired in a clean context, report the deferred QS
+ * directly. This makes the irq_work robust under preempt=none /
+ * voluntary, where the set_need_resched() nudge would not enter
+ * __schedule() at IRQ exit. Otherwise we are still inside a reader /
+ * compound section: just clear defer_qs_pending so the next
+ * rcu_read_unlock() can rearm.
*/
- if (rcu_preempt_depth() > 0)
+ if (!rcu_preempt_deferred_qs_try_report(current))
rcu_defer_qs_clear(rdp);
}
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH v4 3/8] rcu: clear defer_qs_pending in handler for compounded sections
2026-06-26 0:42 ` [PATCH v4 3/8] rcu: clear defer_qs_pending in handler for compounded sections Joel Fernandes
@ 2026-07-15 20:50 ` Paul E. McKenney
0 siblings, 0 replies; 19+ messages in thread
From: Paul E. McKenney @ 2026-07-15 20:50 UTC (permalink / raw)
To: Joel Fernandes
Cc: linux-kernel, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu
On Thu, Jun 25, 2026 at 08:42:56PM -0400, Joel Fernandes wrote:
> The deferred-QS irq-work handler previously cleared defer_qs_pending
> only when the handler ran inside an active rcu_read_lock() critical
> section (rcu_preempt_depth() > 0). Paul McKenney pointed out a common
> multi-segment compound pattern where the handler fires between
> segments and segment N+1's arming attempt is silently suppressed by
> the rcu_read_unlock_special() pending-gate:
>
> rcu_read_lock(); // segment 1 starts
> // may be preempted/boosted here
> local_irq_disable();
> rcu_read_unlock(); // segment 1 ends; arms defer_qs_pending
> preempt_disable();
> local_irq_enable(); // handler MAY fire here: depth==0, but
> // but preempt is disabled, so it cant
> // nudge.
>
> rcu_read_lock(); // segment 2 starts
> preempt_enable();
> local_irq_disable();
> rcu_read_unlock(); // arming attempt suppressed incorrectly -- (1)
> local_irq_enable();
>
> Waiting for the next __note_gp_changes() clear is too slow for the
> compound case, we need the deferred QS report sooner.
>
> Therefore, make the irq_work handler clear defer_qs_pending whenever
> rcu_in_compounded_section() is true so that (1) can do the arming.
>
> In addition, introduce rcu_preempt_deferred_qs_try_report(), a small
> helper that reports the deferred QS (and releases any RCU priority
> boost) directly, but only from a clean, non-reader/compound context.
> When the handler lands in such a clean context it now reports the QS
> directly instead of merely nudging the scheduler: this makes the
> irq_work robust under preempt=none / voluntary, where a
> set_need_resched() nudge would not enter __schedule() at IRQ exit and
> the QS would otherwise wait for the next tick. When still compounded,
> the handler falls back to clearing defer_qs_pending as before. The
> bounded-delay rescue hrtimer added in a later patch reuses this same
> helper.
The patch generally looks like an unambiguous improvement, but just to
make sure that I understand...
None of the code below is even built if CONFIG_PREEMPT_NONE=y. So is
the text above referring to kernels built with CONFIG_PREEMPT_DYNAMIC=y
and booted with either preempt=none or preempt=voluntary? If so, we
need to explicitly state that.
Thanx, Paul
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> ---
> kernel/rcu/tree_plugin.h | 46 ++++++++++++++++++++++++++++------------
> 1 file changed, 33 insertions(+), 13 deletions(-)
>
> diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
> index 7555022bf38a..7768a40677a4 100644
> --- a/kernel/rcu/tree_plugin.h
> +++ b/kernel/rcu/tree_plugin.h
> @@ -702,7 +702,32 @@ notrace void rcu_preempt_deferred_qs(struct task_struct *t)
> }
>
> /*
> - * Minimal handler to give the scheduler a chance to re-evaluate.
> + * Report a deferred quiescent state but only from a safe context.
> + *
> + * Both callers (the irq_work handler and the bounded-delay rescue hrtimer)
> + * run in hardirq context, so preempt_count() always has the HARDIRQ bit set;
> + * the compound-section check below deliberately inspects only the
> + * PREEMPT_MASK | SOFTIRQ_MASK bits, which reflect the INTERRUPTED caller's
> + * state, not ours.
> + */
> +static bool rcu_preempt_deferred_qs_try_report(struct task_struct *t)
> +{
> + unsigned long flags;
> +
> + if (rcu_preempt_depth() > 0 ||
> + (preempt_count() & (PREEMPT_MASK | SOFTIRQ_MASK)))
> + return false;
> +
> + if (rcu_preempt_need_deferred_qs(t)) {
> + local_irq_save(flags);
> + rcu_preempt_deferred_qs_irqrestore(t, flags);
> + }
> + return true;
> +}
> +
> +/*
> + * Minimal handler to give the scheduler a chance to re-evaluate, and to
> + * report the deferred QS directly when the handler lands in a clean context.
> */
> static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp)
> {
> @@ -712,19 +737,14 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp)
> rdp = container_of(iwp, struct rcu_data, defer_qs_iw);
>
> /*
> - * If the IRQ work handler happens to run in the middle of RCU read-side
> - * critical section, it could be ineffective in getting the scheduler's
> - * attention to report a deferred quiescent state (the whole point of the
> - * IRQ work). For this reason, requeue the IRQ work.
> - *
> - * Basically, we want to avoid following situation:
> - * 1. rcu_read_unlock() queues IRQ work (state -> DEFER_QS_PENDING)
> - * 2. CPU enters new rcu_read_lock()
> - * 3. IRQ work runs but cannot report QS due to rcu_preempt_depth() > 0
> - * 4. rcu_read_unlock() does not re-queue work (state still PENDING)
> - * 5. Deferred QS reporting does not happen.
> + * If the handler fired in a clean context, report the deferred QS
> + * directly. This makes the irq_work robust under preempt=none /
> + * voluntary, where the set_need_resched() nudge would not enter
> + * __schedule() at IRQ exit. Otherwise we are still inside a reader /
> + * compound section: just clear defer_qs_pending so the next
> + * rcu_read_unlock() can rearm.
> */
> - if (rcu_preempt_depth() > 0)
> + if (!rcu_preempt_deferred_qs_try_report(current))
> rcu_defer_qs_clear(rdp);
> }
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v4 4/8] rcu: drop redundant defer_qs_pending clear in irqrestore handler
2026-06-26 0:42 [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
` (2 preceding siblings ...)
2026-06-26 0:42 ` [PATCH v4 3/8] rcu: clear defer_qs_pending in handler for compounded sections Joel Fernandes
@ 2026-06-26 0:42 ` Joel Fernandes
2026-07-15 20:58 ` Paul E. McKenney
2026-06-26 0:42 ` [PATCH v4 5/8] rcu: clear defer_qs_pending at expedited IPI entry Joel Fernandes
` (5 subsequent siblings)
9 siblings, 1 reply; 19+ messages in thread
From: Joel Fernandes @ 2026-06-26 0:42 UTC (permalink / raw)
To: linux-kernel
Cc: Paul E . McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu,
Joel Fernandes
With __note_gp_changes() now clearing defer_qs_pending at every
per-CPU GP advance, the per-irqrestore clear is redundant. Remove it.
Effect: PENDING now stays set from arming until the next per-CPU GP
advance, future arming attempts on the same CPU within the same GP are
gated by the rcu_read_unlock_special().
This serves both as an optimization (should not need new irq_work again
this GP - for the compounded section case, we detect and clear it there),
and reduces risks of recursion due to clearing too aggressively.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
kernel/rcu/tree_plugin.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 7768a40677a4..c37d8cfeb714 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -581,8 +581,6 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
union rcu_special special;
rdp = this_cpu_ptr(&rcu_data);
- if (rdp->defer_qs_pending == DEFER_QS_PENDING)
- rcu_defer_qs_clear(rdp);
/*
* If RCU core is waiting for this CPU to exit its critical section,
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH v4 4/8] rcu: drop redundant defer_qs_pending clear in irqrestore handler
2026-06-26 0:42 ` [PATCH v4 4/8] rcu: drop redundant defer_qs_pending clear in irqrestore handler Joel Fernandes
@ 2026-07-15 20:58 ` Paul E. McKenney
0 siblings, 0 replies; 19+ messages in thread
From: Paul E. McKenney @ 2026-07-15 20:58 UTC (permalink / raw)
To: Joel Fernandes
Cc: linux-kernel, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu
On Thu, Jun 25, 2026 at 08:42:57PM -0400, Joel Fernandes wrote:
> With __note_gp_changes() now clearing defer_qs_pending at every
> per-CPU GP advance, the per-irqrestore clear is redundant. Remove it.
Wait...
Given your patch 2/8 of this series, isn't __note_gp_changes() now
clearing ->defer_qs_pending on any new-to-this-CPU grace period start
or end? If that was a new-to-this-CPU grace period start, is that really
a one-to-once correspondence to the need for a quiescent state?
Thanx, Paul
> Effect: PENDING now stays set from arming until the next per-CPU GP
> advance, future arming attempts on the same CPU within the same GP are
> gated by the rcu_read_unlock_special().
>
> This serves both as an optimization (should not need new irq_work again
> this GP - for the compounded section case, we detect and clear it there),
> and reduces risks of recursion due to clearing too aggressively.
>
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> ---
> kernel/rcu/tree_plugin.h | 2 --
> 1 file changed, 2 deletions(-)
>
> diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
> index 7768a40677a4..c37d8cfeb714 100644
> --- a/kernel/rcu/tree_plugin.h
> +++ b/kernel/rcu/tree_plugin.h
> @@ -581,8 +581,6 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
> union rcu_special special;
>
> rdp = this_cpu_ptr(&rcu_data);
> - if (rdp->defer_qs_pending == DEFER_QS_PENDING)
> - rcu_defer_qs_clear(rdp);
>
> /*
> * If RCU core is waiting for this CPU to exit its critical section,
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v4 5/8] rcu: clear defer_qs_pending at expedited IPI entry
2026-06-26 0:42 [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
` (3 preceding siblings ...)
2026-06-26 0:42 ` [PATCH v4 4/8] rcu: drop redundant defer_qs_pending clear in irqrestore handler Joel Fernandes
@ 2026-06-26 0:42 ` Joel Fernandes
2026-07-15 21:01 ` Paul E. McKenney
2026-06-26 0:42 ` [PATCH v4 6/8] rcu: set need_resched on softirq deferred-QS arming path Joel Fernandes
` (4 subsequent siblings)
9 siblings, 1 reply; 19+ messages in thread
From: Joel Fernandes @ 2026-06-26 0:42 UTC (permalink / raw)
To: linux-kernel
Cc: Paul E . McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu,
Joel Fernandes
The per-CPU clear in __note_gp_changes() (from an earlier commit)
runs only when the local CPU notices a normal-GP advance. When an
expedited GP arrives at a CPU whose defer_qs_pending is already
PENDING, rcu_read_unlock_special() may skip irq_work queuing due to the
pending gate.
Clear defer_qs_pending on the IPI target right in rcu_exp_handler().
This makes it possible for any arming attempt that follows
the IPI within the current GP to be able to queue irq_work again,
allowing completion expedited GPs quickly than waiting for one scheduler
tick.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
kernel/rcu/tree_exp.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h
index a43469da3926..5be80d255d6a 100644
--- a/kernel/rcu/tree_exp.h
+++ b/kernel/rcu/tree_exp.h
@@ -763,6 +763,12 @@ static void rcu_exp_handler(void *unused)
READ_ONCE(rdp->cpu_no_qs.b.exp)))
return;
+ /*
+ * Clear defer_qs_pending so arming attempts following this IPI
+ * within the current GP can queue irq_work again.
+ */
+ rcu_defer_qs_clear(rdp);
+
/*
* Second, the common case of not being in an RCU read-side
* critical section. If also enabled or idle, immediately
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH v4 5/8] rcu: clear defer_qs_pending at expedited IPI entry
2026-06-26 0:42 ` [PATCH v4 5/8] rcu: clear defer_qs_pending at expedited IPI entry Joel Fernandes
@ 2026-07-15 21:01 ` Paul E. McKenney
0 siblings, 0 replies; 19+ messages in thread
From: Paul E. McKenney @ 2026-07-15 21:01 UTC (permalink / raw)
To: Joel Fernandes
Cc: linux-kernel, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu
On Thu, Jun 25, 2026 at 08:42:58PM -0400, Joel Fernandes wrote:
> The per-CPU clear in __note_gp_changes() (from an earlier commit)
> runs only when the local CPU notices a normal-GP advance. When an
> expedited GP arrives at a CPU whose defer_qs_pending is already
> PENDING, rcu_read_unlock_special() may skip irq_work queuing due to the
> pending gate.
>
> Clear defer_qs_pending on the IPI target right in rcu_exp_handler().
> This makes it possible for any arming attempt that follows
> the IPI within the current GP to be able to queue irq_work again,
> allowing completion expedited GPs quickly than waiting for one scheduler
> tick.
>
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> ---
> kernel/rcu/tree_exp.h | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/kernel/rcu/tree_exp.h b/kernel/rcu/tree_exp.h
> index a43469da3926..5be80d255d6a 100644
> --- a/kernel/rcu/tree_exp.h
> +++ b/kernel/rcu/tree_exp.h
> @@ -763,6 +763,12 @@ static void rcu_exp_handler(void *unused)
> READ_ONCE(rdp->cpu_no_qs.b.exp)))
> return;
>
> + /*
> + * Clear defer_qs_pending so arming attempts following this IPI
> + * within the current GP can queue irq_work again.
> + */
> + rcu_defer_qs_clear(rdp);
Suppose that there is also a normal grace period pending. Will clearing
this cause extra unnecessary activity with respect to that normal
grace period? If so, why is that OK? If not, what prevents it?
Thanx, Paul
> +
> /*
> * Second, the common case of not being in an RCU read-side
> * critical section. If also enabled or idle, immediately
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v4 6/8] rcu: set need_resched on softirq deferred-QS arming path
2026-06-26 0:42 [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
` (4 preceding siblings ...)
2026-06-26 0:42 ` [PATCH v4 5/8] rcu: clear defer_qs_pending at expedited IPI entry Joel Fernandes
@ 2026-06-26 0:42 ` Joel Fernandes
2026-07-15 21:12 ` Paul E. McKenney
2026-06-26 0:43 ` [PATCH v4 7/8] rcu: clear defer_qs_pending in deferred-QS bail when nesting > 0 Joel Fernandes
` (3 subsequent siblings)
9 siblings, 1 reply; 19+ messages in thread
From: Joel Fernandes @ 2026-06-26 0:42 UTC (permalink / raw)
To: linux-kernel
Cc: Paul E . McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu,
Joel Fernandes
The arming code in rcu_read_unlock_special() has two paths for
deferring QS reporting: a softirq raise and an irq_work/set_need_resched
combination.
The irq_work path always calls set_need_resched_current() before
queuing irq_work. The softirq path does not, relying solely on the
softirq firing to do the rightthing.
This results in a problem as follows:
Consider 2 rcu_read_lock/unlock segments:
rcu_read_lock(); // segment 1 starts
// needs_exp becomes true
preempt_disable();
rcu_read_unlock(); // segment 1 ends; IRQs on, preempt
// off, needs_exp=true =>
// raise_softirq(RCU_SOFTIRQ);
// arms defer_qs_pending.
// Before this fix: no
// set_need_resched_current().
local_irq_disable();
preempt_enable(); // softirq pending but IRQs disabled
// hold it off.
rcu_read_lock(); // segment 2 starts
local_irq_enable(); // softirq fires: rcu_core runs, but
// we are inside a reader (depth>0)
// so no QS report; on softirq-exit
// preempt-check finds no
// need_resched -- still no nudge.
preempt_disable();
rcu_read_unlock(); // arming attempt suppressed
// incorrectly: defer_qs_pending
// already PENDING. Without this
// fix, no fresh
// set_need_resched_current() on
// this path either.
preempt_enable();
Therefore, add set_need_resched_current() to the softirq deferral path to
avoid long latencies in situations where GP needs to end sooner.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
kernel/rcu/tree_plugin.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index c37d8cfeb714..f58ae29acdef 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -846,6 +846,7 @@ static void rcu_read_unlock_special(struct task_struct *t)
// Using softirq, safe to awaken, and either the
// wakeup is free or there is either an expedited
// GP in flight or a potential need to deboost.
+ set_need_resched_current();
if (rdp->defer_qs_pending != DEFER_QS_PENDING) {
rdp->defer_qs_pending = DEFER_QS_PENDING;
raise_softirq_irqoff(RCU_SOFTIRQ);
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH v4 6/8] rcu: set need_resched on softirq deferred-QS arming path
2026-06-26 0:42 ` [PATCH v4 6/8] rcu: set need_resched on softirq deferred-QS arming path Joel Fernandes
@ 2026-07-15 21:12 ` Paul E. McKenney
0 siblings, 0 replies; 19+ messages in thread
From: Paul E. McKenney @ 2026-07-15 21:12 UTC (permalink / raw)
To: Joel Fernandes
Cc: linux-kernel, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu
On Thu, Jun 25, 2026 at 08:42:59PM -0400, Joel Fernandes wrote:
> The arming code in rcu_read_unlock_special() has two paths for
> deferring QS reporting: a softirq raise and an irq_work/set_need_resched
> combination.
>
> The irq_work path always calls set_need_resched_current() before
> queuing irq_work. The softirq path does not, relying solely on the
> softirq firing to do the rightthing.
>
> This results in a problem as follows:
>
> Consider 2 rcu_read_lock/unlock segments:
>
> rcu_read_lock(); // segment 1 starts
> // needs_exp becomes true
> preempt_disable();
> rcu_read_unlock(); // segment 1 ends; IRQs on, preempt
> // off, needs_exp=true =>
> // raise_softirq(RCU_SOFTIRQ);
> // arms defer_qs_pending.
> // Before this fix: no
> // set_need_resched_current().
> local_irq_disable();
> preempt_enable(); // softirq pending but IRQs disabled
> // hold it off.
> rcu_read_lock(); // segment 2 starts
> local_irq_enable(); // softirq fires: rcu_core runs, but
> // we are inside a reader (depth>0)
> // so no QS report; on softirq-exit
> // preempt-check finds no
> // need_resched -- still no nudge.
> preempt_disable();
> rcu_read_unlock(); // arming attempt suppressed
> // incorrectly: defer_qs_pending
> // already PENDING. Without this
> // fix, no fresh
> // set_need_resched_current() on
> // this path either.
> preempt_enable();
>
> Therefore, add set_need_resched_current() to the softirq deferral path to
> avoid long latencies in situations where GP needs to end sooner.
Hmmm... Doesn't this make some of the prior changes unnecessary?
Also, how often is this giving us unecessary context switches?
Finally, what exactly does (->defer_qs_pending == DEFER_QS_PENDING)
mean at this point?
Thanx, Paul
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> ---
> kernel/rcu/tree_plugin.h | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
> index c37d8cfeb714..f58ae29acdef 100644
> --- a/kernel/rcu/tree_plugin.h
> +++ b/kernel/rcu/tree_plugin.h
> @@ -846,6 +846,7 @@ static void rcu_read_unlock_special(struct task_struct *t)
> // Using softirq, safe to awaken, and either the
> // wakeup is free or there is either an expedited
> // GP in flight or a potential need to deboost.
> + set_need_resched_current();
> if (rdp->defer_qs_pending != DEFER_QS_PENDING) {
> rdp->defer_qs_pending = DEFER_QS_PENDING;
> raise_softirq_irqoff(RCU_SOFTIRQ);
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v4 7/8] rcu: clear defer_qs_pending in deferred-QS bail when nesting > 0
2026-06-26 0:42 [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
` (5 preceding siblings ...)
2026-06-26 0:42 ` [PATCH v4 6/8] rcu: set need_resched on softirq deferred-QS arming path Joel Fernandes
@ 2026-06-26 0:43 ` Joel Fernandes
2026-07-15 21:30 ` Paul E. McKenney
2026-06-26 0:43 ` [PATCH v4 8/8] rcu: add per-CPU rescue hrtimer for deferred-QS reporting Joel Fernandes
` (2 subsequent siblings)
9 siblings, 1 reply; 19+ messages in thread
From: Joel Fernandes @ 2026-06-26 0:43 UTC (permalink / raw)
To: linux-kernel
Cc: Paul E . McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu,
Joel Fernandes
Paul McKenney noted that a softirq (or irq_work) handler arming for a
deferred QS can fire and find rcu_preempt_depth() > 0 -- the task is
still inside its outer reader, so rcu_preempt_need_deferred_qs() bails
without reporting the QS. At that point the queued mechanism has been
consumed but ->defer_qs_pending stays in DEFER_QS_PENDING.
In the meantime, the only remaining path back to a quiescent state on
this CPU may be a local_irq_disable()/_enable() pair that does not
call preempt_check_resched() (it is just `sti`/`cli`). patch 6's
unconditional set_need_resched_current() makes need_resched true, but
without an irq_work being raised the next outer rcu_read_unlock_special()
hits the P-gate at the arming code:
if (rdp->defer_qs_pending != DEFER_QS_PENDING) {
rdp->defer_qs_pending = DEFER_QS_PENDING;
irq_work_queue_on(...); // <-- skipped
}
so no irq_work is queued for the hardirq-exit preempt_schedule_irq()
path either. The deferred QS now waits until the next timer tick (or
similar preempt-safe boundary), needlessly extending expedited grace
period latency.
Clear ->defer_qs_pending in the bail-out path of rcu_preempt_deferred_qs()
when rcu_preempt_depth() > 0. The recursion guard semantics introduced
by commit b41642c87716 ("rcu: Fix rcu_read_unlock() deadloop due to IRQ
work").
The clear is also safe against fresh recursion at this exact program
point: rcu_preempt_depth() > 0 guarantees we are still inside an outer
reader, so any inner rcu_read_unlock() from tracing infrastructure
brings nesting back to outer (>0), never to 0. The slow path of
rcu_read_unlock_special() is structurally unreachable under that
condition, so no recursive raise_softirq_irqoff()/irq_work_queue_on()
can be triggered by the clear. Essentially, the mechanism will work to
prevent the following recursion which Xiongfeng had previously reported:
irq_exit() -> __irq_exit_rcu()
-> tick_irq_exit() -> tick_nohz_irq_exit() -> tick_nohz_stop_sched_tick()
-> trace_tick_stop() // BPF prog hooked here
-> rcu_read_unlock_special()
-> irq_work_queue_on(&rdp->defer_qs_iw, rdp->cpu) // self-IPI re-enters irq_exit
Reported-by: Paul E. McKenney <paulmck@kernel.org>
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
kernel/rcu/tree_plugin.h | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index f58ae29acdef..6f5d31e3f1a3 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -692,9 +692,35 @@ static notrace bool rcu_preempt_need_deferred_qs(struct task_struct *t)
notrace void rcu_preempt_deferred_qs(struct task_struct *t)
{
unsigned long flags;
+ struct rcu_data *rdp;
- if (!rcu_preempt_need_deferred_qs(t))
+ if (!rcu_preempt_need_deferred_qs(t)) {
+ /*
+ * If we got here from a softirq/irq_work that fired while
+ * rcu_preempt_depth() > 0, the deferred-QS mechanism has been
+ * consumed without doing any work: rcu_preempt_need_deferred_qs()
+ * just returned false because the task is still in a reader, so
+ * the actual QS report has to wait for the next
+ * rcu_read_unlock().
+ *
+ * Clear ->defer_qs_pending here so the next outer
+ * rcu_read_unlock_special() can re-arm a fresh mechanism (in
+ * particular the irq_work path, which the local_irq_enable()
+ * recovery boundary cannot itself reschedule from).
+ *
+ * Recursion safety: rcu_preempt_depth() > 0 means we are inside
+ * an outer reader, so any inner rcu_read_unlock() reached via
+ * tracing (bpf programs attached to trace points) brings
+ * nesting to outer (> 0), never to 0, so no recursive
+ * raise_softirq_irqoff()/irq_work_queue_on() can be triggered
+ * by this clear.
+ */
+ if (rcu_preempt_depth() > 0) {
+ rdp = this_cpu_ptr(&rcu_data);
+ rcu_defer_qs_clear(rdp);
+ }
return;
+ }
local_irq_save(flags);
rcu_preempt_deferred_qs_irqrestore(t, flags);
}
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH v4 7/8] rcu: clear defer_qs_pending in deferred-QS bail when nesting > 0
2026-06-26 0:43 ` [PATCH v4 7/8] rcu: clear defer_qs_pending in deferred-QS bail when nesting > 0 Joel Fernandes
@ 2026-07-15 21:30 ` Paul E. McKenney
0 siblings, 0 replies; 19+ messages in thread
From: Paul E. McKenney @ 2026-07-15 21:30 UTC (permalink / raw)
To: Joel Fernandes
Cc: linux-kernel, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu
On Thu, Jun 25, 2026 at 08:43:00PM -0400, Joel Fernandes wrote:
> Paul McKenney noted that a softirq (or irq_work) handler arming for a
> deferred QS can fire and find rcu_preempt_depth() > 0 -- the task is
> still inside its outer reader, so rcu_preempt_need_deferred_qs() bails
> without reporting the QS. At that point the queued mechanism has been
> consumed but ->defer_qs_pending stays in DEFER_QS_PENDING.
>
> In the meantime, the only remaining path back to a quiescent state on
> this CPU may be a local_irq_disable()/_enable() pair that does not
> call preempt_check_resched() (it is just `sti`/`cli`). patch 6's
> unconditional set_need_resched_current() makes need_resched true, but
> without an irq_work being raised the next outer rcu_read_unlock_special()
> hits the P-gate at the arming code:
>
> if (rdp->defer_qs_pending != DEFER_QS_PENDING) {
> rdp->defer_qs_pending = DEFER_QS_PENDING;
> irq_work_queue_on(...); // <-- skipped
> }
>
> so no irq_work is queued for the hardirq-exit preempt_schedule_irq()
> path either. The deferred QS now waits until the next timer tick (or
> similar preempt-safe boundary), needlessly extending expedited grace
> period latency.
>
> Clear ->defer_qs_pending in the bail-out path of rcu_preempt_deferred_qs()
> when rcu_preempt_depth() > 0. The recursion guard semantics introduced
> by commit b41642c87716 ("rcu: Fix rcu_read_unlock() deadloop due to IRQ
> work").
>
> The clear is also safe against fresh recursion at this exact program
> point: rcu_preempt_depth() > 0 guarantees we are still inside an outer
> reader, so any inner rcu_read_unlock() from tracing infrastructure
> brings nesting back to outer (>0), never to 0. The slow path of
> rcu_read_unlock_special() is structurally unreachable under that
> condition, so no recursive raise_softirq_irqoff()/irq_work_queue_on()
> can be triggered by the clear. Essentially, the mechanism will work to
> prevent the following recursion which Xiongfeng had previously reported:
>
> irq_exit() -> __irq_exit_rcu()
> -> tick_irq_exit() -> tick_nohz_irq_exit() -> tick_nohz_stop_sched_tick()
> -> trace_tick_stop() // BPF prog hooked here
> -> rcu_read_unlock_special()
> -> irq_work_queue_on(&rdp->defer_qs_iw, rdp->cpu) // self-IPI re-enters irq_exit
>
> Reported-by: Paul E. McKenney <paulmck@kernel.org>
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
I am a bit concerned about this one. We are clearing ->defer_qs_pending,
but there might still be something that will attempt to complete the
deferred quiescent state.
I am nevertheless tentatively pulling it in for further review and
testing.
Thanx, Paul
> ---
> kernel/rcu/tree_plugin.h | 28 +++++++++++++++++++++++++++-
> 1 file changed, 27 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
> index f58ae29acdef..6f5d31e3f1a3 100644
> --- a/kernel/rcu/tree_plugin.h
> +++ b/kernel/rcu/tree_plugin.h
> @@ -692,9 +692,35 @@ static notrace bool rcu_preempt_need_deferred_qs(struct task_struct *t)
> notrace void rcu_preempt_deferred_qs(struct task_struct *t)
> {
> unsigned long flags;
> + struct rcu_data *rdp;
>
> - if (!rcu_preempt_need_deferred_qs(t))
> + if (!rcu_preempt_need_deferred_qs(t)) {
> + /*
> + * If we got here from a softirq/irq_work that fired while
> + * rcu_preempt_depth() > 0, the deferred-QS mechanism has been
> + * consumed without doing any work: rcu_preempt_need_deferred_qs()
> + * just returned false because the task is still in a reader, so
> + * the actual QS report has to wait for the next
> + * rcu_read_unlock().
> + *
> + * Clear ->defer_qs_pending here so the next outer
> + * rcu_read_unlock_special() can re-arm a fresh mechanism (in
> + * particular the irq_work path, which the local_irq_enable()
> + * recovery boundary cannot itself reschedule from).
> + *
> + * Recursion safety: rcu_preempt_depth() > 0 means we are inside
> + * an outer reader, so any inner rcu_read_unlock() reached via
> + * tracing (bpf programs attached to trace points) brings
> + * nesting to outer (> 0), never to 0, so no recursive
> + * raise_softirq_irqoff()/irq_work_queue_on() can be triggered
> + * by this clear.
> + */
> + if (rcu_preempt_depth() > 0) {
> + rdp = this_cpu_ptr(&rcu_data);
> + rcu_defer_qs_clear(rdp);
> + }
> return;
> + }
> local_irq_save(flags);
> rcu_preempt_deferred_qs_irqrestore(t, flags);
> }
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v4 8/8] rcu: add per-CPU rescue hrtimer for deferred-QS reporting
2026-06-26 0:42 [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
` (6 preceding siblings ...)
2026-06-26 0:43 ` [PATCH v4 7/8] rcu: clear defer_qs_pending in deferred-QS bail when nesting > 0 Joel Fernandes
@ 2026-06-26 0:43 ` Joel Fernandes
2026-07-15 21:35 ` Paul E. McKenney
2026-06-26 0:44 ` [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
2026-06-26 14:56 ` Joel Fernandes
9 siblings, 1 reply; 19+ messages in thread
From: Joel Fernandes @ 2026-06-26 0:43 UTC (permalink / raw)
To: linux-kernel
Cc: Paul E . McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu,
Joel Fernandes
The compound branch of rcu_read_unlock_special() arms one of the
scheduler, RCU_SOFTIRQ (raise_softirq_irqoff()) or irq_work_queue_on()
in order to report a deferred quiescent state at a later time.
However, that is not enough in scenarios where an interrupts-disabled
section spans the preempt_enable() of a preempt-disabled section:
rcu_read_lock();
// receive IPI for expedited GP
preempt_disable();
rcu_read_unlock(); // sets the need-resched flag
local_irq_disable();
preempt_enable(); // cannot reschedule: IRQs are off
local_irq_enable();
// now outside the compound RCU read-side critical section, but the
// expedited GP is still held up
Introduce a per-CPU bounded-delay rescue hrtimer, armed from the compound
branch when an expedited GP needs this CPU's quiescent state, that reports
the deferred QS via rcu_preempt_deferred_qs_try_report() once a clean
(non-reader, non-compound) context is reached.
To keep the rescue from firing once one of the normal mechanisms has
already reported the quiescent state, cancel it from
rcu_preempt_deferred_qs_irqrestore() -- the common path through which the
deferred QS is reported. Without this the timer keeps firing (and
re-arming) only to find the work already done; cancelling on the natural
report path avoids the great majority of those fires (observed as a ~90%
reduction in rescue-timer fires under rcutorture TREE03 with
rcutorture.gp_exp=1).
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
kernel/rcu/tree.c | 1 +
kernel/rcu/tree.h | 1 +
kernel/rcu/tree_plugin.h | 70 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 72 insertions(+)
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index c4352d0c3876..0cacbe642235 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -27,6 +27,7 @@
#include <linux/sched.h>
#include <linux/sched/debug.h>
#include <linux/nmi.h>
+#include <linux/hrtimer.h>
#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/export.h>
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index dc03231b2d46..58b120bf0b7b 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -218,6 +218,7 @@ struct rcu_data {
/* during and after the last grace */
/* period it is aware of. */
struct irq_work defer_qs_iw; /* Obtain later scheduler attention. */
+ struct hrtimer defer_qs_iw_rescue;/* Rescue timer for deferred-QS. */
int defer_qs_pending; /* irqwork or softirq pending? */
struct work_struct strict_work; /* Schedule readers for strict GPs. */
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 6f5d31e3f1a3..324d08c7a91a 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -592,6 +592,18 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
local_irq_restore(flags);
return;
}
+
+ /*
+ * A natural report path reached the deferred quiescent state before
+ * the bounded-delay rescue hrtimer fired. Cancel any pending rescue
+ * on this CPU so it does not fire only to find the quiescent state
+ * already reported. Use hrtimer_try_to_cancel() rather than
+ * hrtimer_cancel(): interrupts are disabled here and the timer is
+ * HARD/PINNED, so a callback that is already running must not be
+ * waited on (in that case this is a harmless no-op).
+ */
+ hrtimer_try_to_cancel(&rdp->defer_qs_iw_rescue);
+
t->rcu_read_unlock_special.s = 0;
if (special.b.need_qs) {
if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD)) {
@@ -772,6 +784,54 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp)
rcu_defer_qs_clear(rdp);
}
+/*
+ * Bounded-delay rescue timeout for the deferred-QS reporting.
+ *
+ * The compound branch of rcu_read_unlock_special() arms either the
+ * scheduler, RCU_SOFTIRQ (raise_softirq_irqoff) or irq_work_queue_on() in order
+ * to report a deferred QS at a later time.
+ *
+ * However, that is not enough as in scenarios where local_irq_disable()d
+ * sections span the preempt_enable() call of a preempt-disabled section:
+ *
+ * rcu_read_lock();
+ * // receive IPI for exp GP
+ * preempt_disable();
+ * rcu_read_unlock(); // Set the "need reschedule" flag.
+ * local_irq_disable();
+ * preempt_enable(); // Cannot reschedule as IRQs are off.
+ * local_irq_enable();
+ * // Now outside the compound RCU read-side critical section
+ * // however, the expedited GP is still held up.
+ *
+ * Introduce a rescue timer, firing every 50 micro seconds after the last
+ * rcu_read_unlock() call, to fix this.
+ */
+static int defer_qs_rescue_delay_us = 50;
+module_param(defer_qs_rescue_delay_us, int, 0644);
+MODULE_PARM_DESC(defer_qs_rescue_delay_us,
+ "Microseconds before the rescue timer fires a deferred-QS report.");
+
+static enum hrtimer_restart
+rcu_preempt_deferred_qs_rescue(struct hrtimer *hrtp)
+{
+ lockdep_assert_irqs_disabled();
+
+ /*
+ * Still inside a reader / compound section: deboosting is unsafe, so
+ * rearm and retry after a bounded delay. Once clean,
+ * rcu_preempt_deferred_qs_try_report() reports the deferred QS and
+ * releases any boost in the current task's context (or is a no-op if
+ * natural recovery already landed).
+ */
+ if (!rcu_preempt_deferred_qs_try_report(current)) {
+ hrtimer_forward_now(hrtp,
+ us_to_ktime(defer_qs_rescue_delay_us));
+ return HRTIMER_RESTART;
+ }
+ return HRTIMER_NORESTART;
+}
+
/*
* Check if expedited grace period processing during unlock is needed.
*
@@ -892,6 +952,13 @@ static void rcu_read_unlock_special(struct task_struct *t)
irq_work_queue_on(&rdp->defer_qs_iw, rdp->cpu);
}
}
+ // Bounded-delay rescue: arm whenever the compound branch
+ // entered with a pending deferred-QS / deboost obligation,
+ // regardless of which mechanism above was chosen.
+ if (needs_exp && cpu_online(rdp->cpu))
+ hrtimer_start(&rdp->defer_qs_iw_rescue,
+ us_to_ktime(defer_qs_rescue_delay_us),
+ HRTIMER_MODE_REL_PINNED_HARD);
local_irq_restore(flags);
return;
}
@@ -1033,6 +1100,9 @@ dump_blkd_tasks(struct rcu_node *rnp, int ncheck)
static void rcu_preempt_deferred_qs_init(struct rcu_data *rdp)
{
rdp->defer_qs_iw = IRQ_WORK_INIT_HARD(rcu_preempt_deferred_qs_handler);
+ hrtimer_setup(&rdp->defer_qs_iw_rescue,
+ rcu_preempt_deferred_qs_rescue,
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED_HARD);
}
#else /* #ifdef CONFIG_PREEMPT_RCU */
--
2.34.1
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH v4 8/8] rcu: add per-CPU rescue hrtimer for deferred-QS reporting
2026-06-26 0:43 ` [PATCH v4 8/8] rcu: add per-CPU rescue hrtimer for deferred-QS reporting Joel Fernandes
@ 2026-07-15 21:35 ` Paul E. McKenney
0 siblings, 0 replies; 19+ messages in thread
From: Paul E. McKenney @ 2026-07-15 21:35 UTC (permalink / raw)
To: Joel Fernandes
Cc: linux-kernel, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu
On Thu, Jun 25, 2026 at 08:43:01PM -0400, Joel Fernandes wrote:
> The compound branch of rcu_read_unlock_special() arms one of the
> scheduler, RCU_SOFTIRQ (raise_softirq_irqoff()) or irq_work_queue_on()
> in order to report a deferred quiescent state at a later time.
>
> However, that is not enough in scenarios where an interrupts-disabled
> section spans the preempt_enable() of a preempt-disabled section:
>
> rcu_read_lock();
> // receive IPI for expedited GP
> preempt_disable();
> rcu_read_unlock(); // sets the need-resched flag
> local_irq_disable();
> preempt_enable(); // cannot reschedule: IRQs are off
> local_irq_enable();
> // now outside the compound RCU read-side critical section, but the
> // expedited GP is still held up
>
> Introduce a per-CPU bounded-delay rescue hrtimer, armed from the compound
> branch when an expedited GP needs this CPU's quiescent state, that reports
> the deferred QS via rcu_preempt_deferred_qs_try_report() once a clean
> (non-reader, non-compound) context is reached.
>
> To keep the rescue from firing once one of the normal mechanisms has
> already reported the quiescent state, cancel it from
> rcu_preempt_deferred_qs_irqrestore() -- the common path through which the
> deferred QS is reported. Without this the timer keeps firing (and
> re-arming) only to find the work already done; cancelling on the natural
> report path avoids the great majority of those fires (observed as a ~90%
> reduction in rescue-timer fires under rcutorture TREE03 with
> rcutorture.gp_exp=1).
Can this replace some of the complexity in the deferred-quiescent-state
code paths, for example, the irq-work handler? (Yes, we will need an
irq-work handler for immediate deboosting, but that is a separate issue.)
Please see below for another question.
> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
> ---
> kernel/rcu/tree.c | 1 +
> kernel/rcu/tree.h | 1 +
> kernel/rcu/tree_plugin.h | 70 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 72 insertions(+)
>
> diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> index c4352d0c3876..0cacbe642235 100644
> --- a/kernel/rcu/tree.c
> +++ b/kernel/rcu/tree.c
> @@ -27,6 +27,7 @@
> #include <linux/sched.h>
> #include <linux/sched/debug.h>
> #include <linux/nmi.h>
> +#include <linux/hrtimer.h>
> #include <linux/atomic.h>
> #include <linux/bitops.h>
> #include <linux/export.h>
> diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
> index dc03231b2d46..58b120bf0b7b 100644
> --- a/kernel/rcu/tree.h
> +++ b/kernel/rcu/tree.h
> @@ -218,6 +218,7 @@ struct rcu_data {
> /* during and after the last grace */
> /* period it is aware of. */
> struct irq_work defer_qs_iw; /* Obtain later scheduler attention. */
> + struct hrtimer defer_qs_iw_rescue;/* Rescue timer for deferred-QS. */
> int defer_qs_pending; /* irqwork or softirq pending? */
> struct work_struct strict_work; /* Schedule readers for strict GPs. */
>
> diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
> index 6f5d31e3f1a3..324d08c7a91a 100644
> --- a/kernel/rcu/tree_plugin.h
> +++ b/kernel/rcu/tree_plugin.h
> @@ -592,6 +592,18 @@ rcu_preempt_deferred_qs_irqrestore(struct task_struct *t, unsigned long flags)
> local_irq_restore(flags);
> return;
> }
> +
> + /*
> + * A natural report path reached the deferred quiescent state before
> + * the bounded-delay rescue hrtimer fired. Cancel any pending rescue
> + * on this CPU so it does not fire only to find the quiescent state
> + * already reported. Use hrtimer_try_to_cancel() rather than
> + * hrtimer_cancel(): interrupts are disabled here and the timer is
> + * HARD/PINNED, so a callback that is already running must not be
> + * waited on (in that case this is a harmless no-op).
> + */
> + hrtimer_try_to_cancel(&rdp->defer_qs_iw_rescue);
> +
> t->rcu_read_unlock_special.s = 0;
> if (special.b.need_qs) {
> if (IS_ENABLED(CONFIG_RCU_STRICT_GRACE_PERIOD)) {
> @@ -772,6 +784,54 @@ static void rcu_preempt_deferred_qs_handler(struct irq_work *iwp)
> rcu_defer_qs_clear(rdp);
> }
>
> +/*
> + * Bounded-delay rescue timeout for the deferred-QS reporting.
> + *
> + * The compound branch of rcu_read_unlock_special() arms either the
> + * scheduler, RCU_SOFTIRQ (raise_softirq_irqoff) or irq_work_queue_on() in order
> + * to report a deferred QS at a later time.
> + *
> + * However, that is not enough as in scenarios where local_irq_disable()d
> + * sections span the preempt_enable() call of a preempt-disabled section:
> + *
> + * rcu_read_lock();
> + * // receive IPI for exp GP
> + * preempt_disable();
> + * rcu_read_unlock(); // Set the "need reschedule" flag.
> + * local_irq_disable();
> + * preempt_enable(); // Cannot reschedule as IRQs are off.
> + * local_irq_enable();
> + * // Now outside the compound RCU read-side critical section
> + * // however, the expedited GP is still held up.
> + *
> + * Introduce a rescue timer, firing every 50 micro seconds after the last
> + * rcu_read_unlock() call, to fix this.
> + */
> +static int defer_qs_rescue_delay_us = 50;
> +module_param(defer_qs_rescue_delay_us, int, 0644);
> +MODULE_PARM_DESC(defer_qs_rescue_delay_us,
> + "Microseconds before the rescue timer fires a deferred-QS report.");
> +
> +static enum hrtimer_restart
> +rcu_preempt_deferred_qs_rescue(struct hrtimer *hrtp)
> +{
> + lockdep_assert_irqs_disabled();
> +
> + /*
> + * Still inside a reader / compound section: deboosting is unsafe, so
> + * rearm and retry after a bounded delay. Once clean,
> + * rcu_preempt_deferred_qs_try_report() reports the deferred QS and
> + * releases any boost in the current task's context (or is a no-op if
> + * natural recovery already landed).
> + */
> + if (!rcu_preempt_deferred_qs_try_report(current)) {
> + hrtimer_forward_now(hrtp,
> + us_to_ktime(defer_qs_rescue_delay_us));
One way we get here is if we are in an rcu_read_lock()-style RCU read-side
critical section. But in that case, we have an rcu_read_unlock() in
our future, so do we really need to arm the timer now?
And before I forget again, thank you very much for digging into this!!!
This is not a simple situation. ;-)
Thanx, Paul
> + return HRTIMER_RESTART;
> + }
> + return HRTIMER_NORESTART;
> +}
> +
> /*
> * Check if expedited grace period processing during unlock is needed.
> *
> @@ -892,6 +952,13 @@ static void rcu_read_unlock_special(struct task_struct *t)
> irq_work_queue_on(&rdp->defer_qs_iw, rdp->cpu);
> }
> }
> + // Bounded-delay rescue: arm whenever the compound branch
> + // entered with a pending deferred-QS / deboost obligation,
> + // regardless of which mechanism above was chosen.
> + if (needs_exp && cpu_online(rdp->cpu))
> + hrtimer_start(&rdp->defer_qs_iw_rescue,
> + us_to_ktime(defer_qs_rescue_delay_us),
> + HRTIMER_MODE_REL_PINNED_HARD);
> local_irq_restore(flags);
> return;
> }
> @@ -1033,6 +1100,9 @@ dump_blkd_tasks(struct rcu_node *rnp, int ncheck)
> static void rcu_preempt_deferred_qs_init(struct rcu_data *rdp)
> {
> rdp->defer_qs_iw = IRQ_WORK_INIT_HARD(rcu_preempt_deferred_qs_handler);
> + hrtimer_setup(&rdp->defer_qs_iw_rescue,
> + rcu_preempt_deferred_qs_rescue,
> + CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED_HARD);
> }
> #else /* #ifdef CONFIG_PREEMPT_RCU */
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer
2026-06-26 0:42 [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
` (7 preceding siblings ...)
2026-06-26 0:43 ` [PATCH v4 8/8] rcu: add per-CPU rescue hrtimer for deferred-QS reporting Joel Fernandes
@ 2026-06-26 0:44 ` Joel Fernandes
2026-06-26 14:56 ` Joel Fernandes
9 siblings, 0 replies; 19+ messages in thread
From: Joel Fernandes @ 2026-06-26 0:44 UTC (permalink / raw)
To: linux-kernel
Cc: Paul E . McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu
On 6/25/2026 8:42 PM, Joel Fernandes wrote:
> This series fixes a bug where rdp->defer_qs_pending can remain stuck in
> PENDING when a preempted reader's quiescent state is reported up-tree via
> a path other than the deferred-QS irq-work handler (FQS scan, hotplug
> transition, expedited GP IPI, context switch). Once stuck, the pending
> gate in rcu_read_unlock_special() silently suppresses all future arming
> attempts on that CPU. The series adds PENDING -> IDLE transitions at the
> missing sites (patches 1-7), including the case where the deferred-QS
> irq-work handler may run between segments of a compound section (per Paul
> McKenney's counter-example) and the softirq deferred-QS arming path.
>
> Patch 8 adds a per-CPU rescue hrtimer that bounds the worst-case
> deferred-QS reporting latency: when the irq-work handler lands in a clean
> (non-reader, non-compound) context it reports the quiescent state directly
> via the new rcu_preempt_deferred_qs_try_report() helper, and the rescue timer
> reuses the same helper so that, under preempt=none, the QS report is quick
> without depending on the scheduler. The rescue timer is cancelled from the
> normal deferred-QS report path so it does not fire once the quiescent state
> has already been reported.
>
> This version is rebased on top of Paul's latest rcu/dev branch. The
> rcutorture reader-end deboost test patches that were folded into v3 are now
> in rcu/dev and have been dropped here. The git tree below additionally
> carries two debug-only commits on top of the series ([TEST COMMIT], not for
> merge): a detector that WARNs if defer_qs_pending is stuck at GP cleanup,
> and an rcutorture tweak that gives the async deboost mechanisms up to 500us
> before warning. Applied alone on unmodified mainline, the detector reliably
> fires within 5 minutes under TREE03 rcutorture; with the full fix applied I
> could not reproduce the issue.
>
> The git tree with all patches can be found at:
> git://git.kernel.org/pub/scm/linux/kernel/git/jfern/linux.git (tag: rcu-dqs-stuck-v4-20260625)
Just fyi, the 2 "[TEST COMMIT]" patches not for merge are in the above tag. I
missed including it in the LKML posting, but they are not for merge anyway.
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer
2026-06-26 0:42 [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
` (8 preceding siblings ...)
2026-06-26 0:44 ` [PATCH v4 0/8] rcu: fix stuck defer_qs_pending state and add rescue timer Joel Fernandes
@ 2026-06-26 14:56 ` Joel Fernandes
9 siblings, 0 replies; 19+ messages in thread
From: Joel Fernandes @ 2026-06-26 14:56 UTC (permalink / raw)
To: linux-kernel
Cc: Paul E . McKenney, Frederic Weisbecker, Neeraj Upadhyay,
Josh Triplett, Boqun Feng, Uladzislau Rezki, Steven Rostedt,
Mathieu Desnoyers, Lai Jiangshan, Zqiang, Davidlohr Bueso, rcu
On 6/25/2026 8:42 PM, Joel Fernandes wrote:
> This series fixes a bug where rdp->defer_qs_pending can remain stuck in
> PENDING when a preempted reader's quiescent state is reported up-tree via
> a path other than the deferred-QS irq-work handler (FQS scan, hotplug
> transition, expedited GP IPI, context switch). Once stuck, the pending
> gate in rcu_read_unlock_special() silently suppresses all future arming
> attempts on that CPU. The series adds PENDING -> IDLE transitions at the
> missing sites (patches 1-7), including the case where the deferred-QS
> irq-work handler may run between segments of a compound section (per Paul
> McKenney's counter-example) and the softirq deferred-QS arming path.
>
> Patch 8 adds a per-CPU rescue hrtimer that bounds the worst-case
> deferred-QS reporting latency: when the irq-work handler lands in a clean
> (non-reader, non-compound) context it reports the quiescent state directly
> via the new rcu_preempt_deferred_qs_try_report() helper, and the rescue timer
> reuses the same helper so that, under preempt=none, the QS report is quick
> without depending on the scheduler. The rescue timer is cancelled from the
> normal deferred-QS report path so it does not fire once the quiescent state
> has already been reported.
>
> This version is rebased on top of Paul's latest rcu/dev branch. The
> rcutorture reader-end deboost test patches that were folded into v3 are now
> in rcu/dev and have been dropped here. The git tree below additionally
> carries two debug-only commits on top of the series ([TEST COMMIT], not for
> merge): a detector that WARNs if defer_qs_pending is stuck at GP cleanup,
> and an rcutorture tweak that gives the async deboost mechanisms up to 500us
> before warning. Applied alone on unmodified mainline, the detector reliably
> fires within 5 minutes under TREE03 rcutorture; with the full fix applied I
> could not reproduce the issue.
>
> The git tree with all patches can be found at:
> git://git.kernel.org/pub/scm/linux/kernel/git/jfern/linux.git (tag: rcu-dqs-stuck-v4-20260625)
Additional overnight testing with the patch series passes. Perhaps ready
for some linux -next testing? Or do you want to test on your end as well first?
thanks,
Joel Fernandes
^ permalink raw reply [flat|nested] 19+ messages in thread