Skip to contentSkip to conversation

rcu: Allow for page faults in NMI handlers

PATCH In review Paul E. McKenney 2 participants 5 messages Oct 12, 2017 – Oct 13, 2017

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 rcu: Allow for page faults in NMI handlers

A number of architecture invoke rcu_irq_enter() on exception entry in order to allow RCU read-side critical sections in the exception handler when the exception is from an idle or nohz_full CPU. This works, at least unless the exception happens in an NMI handler. In that case, rcu_nmi_enter() would already have exited the extended quiescent state, which would mean that rcu_irq_enter() would (incorrectly) cause RCU to think that it is again in an extended quiescent state. This will in turn result in lockdep splats in response to later RCU read-side critical sections.

This commit therefore causes rcu_irq_enter() and rcu_irq_exit() to take no action if there is an rcu_nmi_enter() in effect, thus avoiding the unscheduled return to RCU quiescent state. This in turn should make the kernel safe for on-demand RCU voyeurism.

Fixes 0be964be0 ("module: Sanitize RCU usage and locking")
kernel/rcu/tree.c +12 -0
index f07343b54fe5..8a62cbfe1f2f 100644
@@ -759,6 +759,12 @@ void rcu_irq_exit(void)
 
 	local_irq_save(flags);
 	rdtp = this_cpu_ptr(&rcu_dynticks);
+
+	/* Page faults can happen in NMI handlers, so check... */
+	if (READ_ONCE(rdtp->dynticks_nmi_nesting))
+		return;
+
+	RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_exit() invoked with irqs enabled!!!");
 	oldval = rdtp->dynticks_nesting;
 	rdtp->dynticks_nesting--;
 	WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
@@ -887,6 +893,12 @@ void rcu_irq_enter(void)
 
 	local_irq_save(flags);
 	rdtp = this_cpu_ptr(&rcu_dynticks);
+
+	/* Page faults can happen in NMI handlers, so check... */
+	if (READ_ONCE(rdtp->dynticks_nmi_nesting))
+		return;
+
+	RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_enter() invoked with irqs enabled!!!");
 	oldval = rdtp->dynticks_nesting;
 	rdtp->dynticks_nesting++;
 	WARN_ON_ONCE(IS_ENABLED(CONFIG_RCU_EQS_DEBUG) &&
maintainer
#1 lore raw
Quoted 15 lines · Paul E. McKenney

A number of architecture invoke rcu_irq_enter() on exception entry in order to allow RCU read-side critical sections in the exception handler when the exception is from an idle or nohz_full CPU. This works, at least unless the exception happens in an NMI handler. In that case, rcu_nmi_enter() would already have exited the extended quiescent state, which would mean that rcu_irq_enter() would (incorrectly) cause RCU to think that it is again in an extended quiescent state. This will in turn result in lockdep splats in response to later RCU read-side critical sections.

This commit therefore causes rcu_irq_enter() and rcu_irq_exit() to take no action if there is an rcu_nmi_enter() in effect, thus avoiding the unscheduled return to RCU quiescent state. This in turn should make the kernel safe for on-demand RCU voyeurism.

Quoted 7 lines
Fixes 0be964be0 ("module: Sanitize RCU usage and locking")

This does not apply to the 4.4-stable tree, was this the correct patch I should be using for that tree?

thanks,

greg k-h

#2 lore raw
Quoted 18 lines · Greg KH
Quoted 17 lines · Paul E. McKenney

A number of architecture invoke rcu_irq_enter() on exception entry in order to allow RCU read-side critical sections in the exception handler when the exception is from an idle or nohz_full CPU. This works, at least unless the exception happens in an NMI handler. In that case, rcu_nmi_enter() would already have exited the extended quiescent state, which would mean that rcu_irq_enter() would (incorrectly) cause RCU to think that it is again in an extended quiescent state. This will in turn result in lockdep splats in response to later RCU read-side critical sections.

This commit therefore causes rcu_irq_enter() and rcu_irq_exit() to take no action if there is an rcu_nmi_enter() in effect, thus avoiding the unscheduled return to RCU quiescent state. This in turn should make the kernel safe for on-demand RCU voyeurism.

Quoted 8 lines
Quoted 5 lines
Fixes 0be964be0 ("module: Sanitize RCU usage and locking")

This does not apply to the 4.4-stable tree, was this the correct patch I should be using for that tree?

Hmmm... Idiot here backported to v4.4 in Linus's tree, which of course might not work... But it applies to v4.4.92 of -stable:

git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

Am I still applying it in the wrong place?

Thanx, Paul

maintainer
#3 lore raw
Quoted 28 lines · Paul E. McKenney
Quoted 18 lines · Greg KH
Quoted 17 lines · Paul E. McKenney

A number of architecture invoke rcu_irq_enter() on exception entry in order to allow RCU read-side critical sections in the exception handler when the exception is from an idle or nohz_full CPU. This works, at least unless the exception happens in an NMI handler. In that case, rcu_nmi_enter() would already have exited the extended quiescent state, which would mean that rcu_irq_enter() would (incorrectly) cause RCU to think that it is again in an extended quiescent state. This will in turn result in lockdep splats in response to later RCU read-side critical sections.

This commit therefore causes rcu_irq_enter() and rcu_irq_exit() to take no action if there is an rcu_nmi_enter() in effect, thus avoiding the unscheduled return to RCU quiescent state. This in turn should make the kernel safe for on-demand RCU voyeurism.

Quoted 8 lines
Quoted 5 lines
Fixes 0be964be0 ("module: Sanitize RCU usage and locking")

This does not apply to the 4.4-stable tree, was this the correct patch I should be using for that tree?

Quoted 6 lines

Hmmm... Idiot here backported to v4.4 in Linus's tree, which of course might not work... But it applies to v4.4.92 of -stable:

git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

Am I still applying it in the wrong place?

Ugh, no, you are doing the right thing. I don't know what failed on my end, that's what I get for trying to deal with RCU early in the morning :)

I'll go apply this now, sorry for the noise, and thanks for checking and the backport.

greg k-h

#4 lore raw
Quoted 32 lines · Greg KH
Quoted 31 lines · Paul E. McKenney
Quoted 18 lines · Greg KH
Quoted 17 lines · Paul E. McKenney

A number of architecture invoke rcu_irq_enter() on exception entry in order to allow RCU read-side critical sections in the exception handler when the exception is from an idle or nohz_full CPU. This works, at least unless the exception happens in an NMI handler. In that case, rcu_nmi_enter() would already have exited the extended quiescent state, which would mean that rcu_irq_enter() would (incorrectly) cause RCU to think that it is again in an extended quiescent state. This will in turn result in lockdep splats in response to later RCU read-side critical sections.

This commit therefore causes rcu_irq_enter() and rcu_irq_exit() to take no action if there is an rcu_nmi_enter() in effect, thus avoiding the unscheduled return to RCU quiescent state. This in turn should make the kernel safe for on-demand RCU voyeurism.

Quoted 8 lines
Quoted 5 lines
Fixes 0be964be0 ("module: Sanitize RCU usage and locking")

This does not apply to the 4.4-stable tree, was this the correct patch I should be using for that tree?

Hmmm... Idiot here backported to v4.4 in Linus's tree, which of course might not work... But it applies to v4.4.92 of -stable:

Quoted 7 lines
Quoted 3 lines

git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

Am I still applying it in the wrong place?

Ugh, no, you are doing the right thing. I don't know what failed on my end, that's what I get for trying to deal with RCU early in the morning :)

Believe me, I know that feeling very well! ;-)

Thanx, Paul

Quoted 5 lines

I'll go apply this now, sorry for the noise, and thanks for checking and the backport.

greg k-h