* [PATCH RFC tip/core/rcu 0/2] Fix RCU idle-exit problem and comment
@ 2020-03-13 2:40 Paul E. McKenney
2020-03-13 2:40 ` [PATCH RFC tip/core/rcu 1/2] rcu: Don't acquire lock in NMI handler in rcu_nmi_enter_common() paulmck
2020-03-13 2:40 ` [PATCH RFC tip/core/rcu 2/2] rcu: Add comments marking transitions between RCU watching and not paulmck
0 siblings, 2 replies; 5+ messages in thread
From: Paul E. McKenney @ 2020-03-13 2:40 UTC (permalink / raw)
To: rcu
Cc: linux-kernel, kernel-team, mingo, jiangshanlai, dipankar, akpm,
mathieu.desnoyers, josh, tglx, peterz, rostedt, dhowells,
edumazet, fweisbec, oleg, joel
Hello!
This series fixes a brown-paper-bag NMI self-deadlock bug located by
Thomas Gleixner and adds comments:
1. Don't acquire lock in NMI handler in rcu_nmi_enter_common().
2. Add comments marking transitions between RCU watching and not.
These pass light rcutorture testing, and seem like v5.8 material.
Thanx, Paul
------------------------------------------------------------------------
tree.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH RFC tip/core/rcu 1/2] rcu: Don't acquire lock in NMI handler in rcu_nmi_enter_common()
2020-03-13 2:40 [PATCH RFC tip/core/rcu 0/2] Fix RCU idle-exit problem and comment Paul E. McKenney
@ 2020-03-13 2:40 ` paulmck
2020-03-13 3:52 ` Joel Fernandes
2020-03-13 2:40 ` [PATCH RFC tip/core/rcu 2/2] rcu: Add comments marking transitions between RCU watching and not paulmck
1 sibling, 1 reply; 5+ messages in thread
From: paulmck @ 2020-03-13 2:40 UTC (permalink / raw)
To: rcu
Cc: linux-kernel, kernel-team, mingo, jiangshanlai, dipankar, akpm,
mathieu.desnoyers, josh, tglx, peterz, rostedt, dhowells,
edumazet, fweisbec, oleg, joel, Paul E. McKenney, # 5 . 5 . x
From: "Paul E. McKenney" <paulmck@kernel.org>
The rcu_nmi_enter_common() function can be invoked both in interrupt
and NMI handlers. If it is invoked from process context (as opposed
to userspace or idle context) on a nohz_full CPU, it might acquire the
CPU's leaf rcu_node structure's ->lock. Because this lock is held only
with interrupts disabled, this is safe from an interrupt handler, but
doing so from an NMI handler can result in self-deadlock.
This commit therefore adds "irq" to the "if" condition so as to only
acquire the ->lock from irq handlers or process context, never from
an NMI handler.
Fixes: 5b14557b073c ("rcu: Avoid tick_dep_set_cpu() misordering")
Reported-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
Cc: <stable@vger.kernel.org> # 5.5.x
---
kernel/rcu/tree.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index d3f52c3..f7d3e48 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -825,7 +825,7 @@ static __always_inline void rcu_nmi_enter_common(bool irq)
rcu_cleanup_after_idle();
incby = 1;
- } else if (tick_nohz_full_cpu(rdp->cpu) &&
+ } else if (irq && tick_nohz_full_cpu(rdp->cpu) &&
rdp->dynticks_nmi_nesting == DYNTICK_IRQ_NONIDLE &&
READ_ONCE(rdp->rcu_urgent_qs) &&
!READ_ONCE(rdp->rcu_forced_tick)) {
--
2.9.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH RFC tip/core/rcu 2/2] rcu: Add comments marking transitions between RCU watching and not
2020-03-13 2:40 [PATCH RFC tip/core/rcu 0/2] Fix RCU idle-exit problem and comment Paul E. McKenney
2020-03-13 2:40 ` [PATCH RFC tip/core/rcu 1/2] rcu: Don't acquire lock in NMI handler in rcu_nmi_enter_common() paulmck
@ 2020-03-13 2:40 ` paulmck
1 sibling, 0 replies; 5+ messages in thread
From: paulmck @ 2020-03-13 2:40 UTC (permalink / raw)
To: rcu
Cc: linux-kernel, kernel-team, mingo, jiangshanlai, dipankar, akpm,
mathieu.desnoyers, josh, tglx, peterz, rostedt, dhowells,
edumazet, fweisbec, oleg, joel, Paul E. McKenney
From: "Paul E. McKenney" <paulmck@kernel.org>
It is not as clear as it might be just where in RCU's idle entry/exit
code RCU stops and starts watching the current CPU. This commit therefore
adds comments calling out the transitions.
Reported-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
---
kernel/rcu/tree.c | 29 +++++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index f7d3e48..2f4c91a 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -225,7 +225,9 @@ void rcu_softirq_qs(void)
/*
* Record entry into an extended quiescent state. This is only to be
- * called when not already in an extended quiescent state.
+ * called when not already in an extended quiescent state, that is,
+ * RCU is watching prior to the call to this function and is no longer
+ * watching upon return.
*/
static void rcu_dynticks_eqs_enter(void)
{
@@ -238,7 +240,7 @@ static void rcu_dynticks_eqs_enter(void)
* next idle sojourn.
*/
seq = atomic_add_return(RCU_DYNTICK_CTRL_CTR, &rdp->dynticks);
- /* Better be in an extended quiescent state! */
+ // RCU is no longer watching. Better be in extended quiescent state!
WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
(seq & RCU_DYNTICK_CTRL_CTR));
/* Better not have special action (TLB flush) pending! */
@@ -248,7 +250,8 @@ static void rcu_dynticks_eqs_enter(void)
/*
* Record exit from an extended quiescent state. This is only to be
- * called from an extended quiescent state.
+ * called from an extended quiescent state, that is, RCU is not watching
+ * prior to the call to this function and is watching upon return.
*/
static void rcu_dynticks_eqs_exit(void)
{
@@ -261,6 +264,7 @@ static void rcu_dynticks_eqs_exit(void)
* critical section.
*/
seq = atomic_add_return(RCU_DYNTICK_CTRL_CTR, &rdp->dynticks);
+ // RCU is now watching. Better not be in an extended quiescent state!
WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
!(seq & RCU_DYNTICK_CTRL_CTR));
if (seq & RCU_DYNTICK_CTRL_MASK) {
@@ -571,6 +575,7 @@ static void rcu_eqs_enter(bool user)
WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
rdp->dynticks_nesting == 0);
if (rdp->dynticks_nesting != 1) {
+ // RCU will still be watching, so just do accounting and leave.
rdp->dynticks_nesting--;
return;
}
@@ -583,7 +588,9 @@ static void rcu_eqs_enter(bool user)
rcu_prepare_for_idle();
rcu_preempt_deferred_qs(current);
WRITE_ONCE(rdp->dynticks_nesting, 0); /* Avoid irq-access tearing. */
+ // RCU is watching here ...
rcu_dynticks_eqs_enter();
+ // ... but is no longer watching here.
rcu_dynticks_task_enter();
}
@@ -663,7 +670,9 @@ static __always_inline void rcu_nmi_exit_common(bool irq)
if (irq)
rcu_prepare_for_idle();
+ // RCU is watching here ...
rcu_dynticks_eqs_enter();
+ // ... but is no longer watching here.
if (irq)
rcu_dynticks_task_enter();
@@ -738,11 +747,14 @@ static void rcu_eqs_exit(bool user)
oldval = rdp->dynticks_nesting;
WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && oldval < 0);
if (oldval) {
+ // RCU was already watching, so just do accounting and leave.
rdp->dynticks_nesting++;
return;
}
rcu_dynticks_task_exit();
+ // RCU is not watching here ...
rcu_dynticks_eqs_exit();
+ // ... but is watching here.
rcu_cleanup_after_idle();
trace_rcu_dyntick(TPS("End"), rdp->dynticks_nesting, 1, atomic_read(&rdp->dynticks));
WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) && !user && !is_idle_task(current));
@@ -819,7 +831,9 @@ static __always_inline void rcu_nmi_enter_common(bool irq)
if (irq)
rcu_dynticks_task_exit();
+ // RCU is not watching here ...
rcu_dynticks_eqs_exit();
+ // ... but is watching here.
if (irq)
rcu_cleanup_after_idle();
@@ -829,9 +843,16 @@ static __always_inline void rcu_nmi_enter_common(bool irq)
rdp->dynticks_nmi_nesting == DYNTICK_IRQ_NONIDLE &&
READ_ONCE(rdp->rcu_urgent_qs) &&
!READ_ONCE(rdp->rcu_forced_tick)) {
+ // We get here only if we had already exited the extended
+ // quiescent state and this was an interrupt (not an NMI).
+ // Therefore, (1) RCU is already watching and (2) The fact
+ // that we are in an interrupt handler and that the rcu_node
+ // lock is an irq-disabled lock prevents self-deadlock.
+ // So we can safely recheck under the lock.
raw_spin_lock_rcu_node(rdp->mynode);
- // Recheck under lock.
if (rdp->rcu_urgent_qs && !rdp->rcu_forced_tick) {
+ // A nohz_full CPU is in the kernel and RCU
+ // needs a quiescent state. Turn on the tick!
WRITE_ONCE(rdp->rcu_forced_tick, true);
tick_dep_set_cpu(rdp->cpu, TICK_DEP_BIT_RCU);
}
--
2.9.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH RFC tip/core/rcu 1/2] rcu: Don't acquire lock in NMI handler in rcu_nmi_enter_common()
2020-03-13 2:40 ` [PATCH RFC tip/core/rcu 1/2] rcu: Don't acquire lock in NMI handler in rcu_nmi_enter_common() paulmck
@ 2020-03-13 3:52 ` Joel Fernandes
2020-03-13 21:47 ` Paul E. McKenney
0 siblings, 1 reply; 5+ messages in thread
From: Joel Fernandes @ 2020-03-13 3:52 UTC (permalink / raw)
To: paulmck
Cc: rcu, linux-kernel, kernel-team, mingo, jiangshanlai, dipankar,
akpm, mathieu.desnoyers, josh, tglx, peterz, rostedt, dhowells,
edumazet, fweisbec, oleg, # 5 . 5 . x
On Thu, Mar 12, 2020 at 07:40:45PM -0700, paulmck@kernel.org wrote:
> From: "Paul E. McKenney" <paulmck@kernel.org>
>
> The rcu_nmi_enter_common() function can be invoked both in interrupt
> and NMI handlers. If it is invoked from process context (as opposed
> to userspace or idle context) on a nohz_full CPU, it might acquire the
> CPU's leaf rcu_node structure's ->lock. Because this lock is held only
> with interrupts disabled, this is safe from an interrupt handler, but
> doing so from an NMI handler can result in self-deadlock.
>
> This commit therefore adds "irq" to the "if" condition so as to only
> acquire the ->lock from irq handlers or process context, never from
> an NMI handler.
I think Peter's new lockdep changes for NMI would also catch this issue.
>
> Fixes: 5b14557b073c ("rcu: Avoid tick_dep_set_cpu() misordering")
Reviewed-by: Joel Fernandes (Google) <joel@joelfernandes.org>
thanks,
- Joel
> Reported-by: Thomas Gleixner <tglx@linutronix.de>
> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
> Cc: <stable@vger.kernel.org> # 5.5.x
> ---
> kernel/rcu/tree.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> index d3f52c3..f7d3e48 100644
> --- a/kernel/rcu/tree.c
> +++ b/kernel/rcu/tree.c
> @@ -825,7 +825,7 @@ static __always_inline void rcu_nmi_enter_common(bool irq)
> rcu_cleanup_after_idle();
>
> incby = 1;
> - } else if (tick_nohz_full_cpu(rdp->cpu) &&
> + } else if (irq && tick_nohz_full_cpu(rdp->cpu) &&
> rdp->dynticks_nmi_nesting == DYNTICK_IRQ_NONIDLE &&
> READ_ONCE(rdp->rcu_urgent_qs) &&
> !READ_ONCE(rdp->rcu_forced_tick)) {
> --
> 2.9.5
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH RFC tip/core/rcu 1/2] rcu: Don't acquire lock in NMI handler in rcu_nmi_enter_common()
2020-03-13 3:52 ` Joel Fernandes
@ 2020-03-13 21:47 ` Paul E. McKenney
0 siblings, 0 replies; 5+ messages in thread
From: Paul E. McKenney @ 2020-03-13 21:47 UTC (permalink / raw)
To: Joel Fernandes
Cc: rcu, linux-kernel, kernel-team, mingo, jiangshanlai, dipankar,
akpm, mathieu.desnoyers, josh, tglx, peterz, rostedt, dhowells,
edumazet, fweisbec, oleg, # 5 . 5 . x
On Thu, Mar 12, 2020 at 11:52:01PM -0400, Joel Fernandes wrote:
> On Thu, Mar 12, 2020 at 07:40:45PM -0700, paulmck@kernel.org wrote:
> > From: "Paul E. McKenney" <paulmck@kernel.org>
> >
> > The rcu_nmi_enter_common() function can be invoked both in interrupt
> > and NMI handlers. If it is invoked from process context (as opposed
> > to userspace or idle context) on a nohz_full CPU, it might acquire the
> > CPU's leaf rcu_node structure's ->lock. Because this lock is held only
> > with interrupts disabled, this is safe from an interrupt handler, but
> > doing so from an NMI handler can result in self-deadlock.
> >
> > This commit therefore adds "irq" to the "if" condition so as to only
> > acquire the ->lock from irq handlers or process context, never from
> > an NMI handler.
>
> I think Peter's new lockdep changes for NMI would also catch this issue.
>
> >
> > Fixes: 5b14557b073c ("rcu: Avoid tick_dep_set_cpu() misordering")
>
> Reviewed-by: Joel Fernandes (Google) <joel@joelfernandes.org>
Applied, thank you!!!
Thanx, Paul
> thanks,
>
> - Joel
>
>
> > Reported-by: Thomas Gleixner <tglx@linutronix.de>
> > Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
> > Cc: <stable@vger.kernel.org> # 5.5.x
> > ---
> > kernel/rcu/tree.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> > index d3f52c3..f7d3e48 100644
> > --- a/kernel/rcu/tree.c
> > +++ b/kernel/rcu/tree.c
> > @@ -825,7 +825,7 @@ static __always_inline void rcu_nmi_enter_common(bool irq)
> > rcu_cleanup_after_idle();
> >
> > incby = 1;
> > - } else if (tick_nohz_full_cpu(rdp->cpu) &&
> > + } else if (irq && tick_nohz_full_cpu(rdp->cpu) &&
> > rdp->dynticks_nmi_nesting == DYNTICK_IRQ_NONIDLE &&
> > READ_ONCE(rdp->rcu_urgent_qs) &&
> > !READ_ONCE(rdp->rcu_forced_tick)) {
> > --
> > 2.9.5
> >
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2020-03-13 21:47 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-03-13 2:40 [PATCH RFC tip/core/rcu 0/2] Fix RCU idle-exit problem and comment Paul E. McKenney
2020-03-13 2:40 ` [PATCH RFC tip/core/rcu 1/2] rcu: Don't acquire lock in NMI handler in rcu_nmi_enter_common() paulmck
2020-03-13 3:52 ` Joel Fernandes
2020-03-13 21:47 ` Paul E. McKenney
2020-03-13 2:40 ` [PATCH RFC tip/core/rcu 2/2] rcu: Add comments marking transitions between RCU watching and not paulmck
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.