diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2012-06-04 19:42:35 -0400 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2012-09-26 09:44:01 -0400 |
commit | 19dd1591fc379f1d89f39cd99cbbe97433baa3c3 (patch) | |
tree | 9c298c4c0f38e68f53c2e4a13080fbec1282953f /kernel/rcutree.c | |
parent | adf5091e6ccaa02905e7a28f9ff44f46c7f4c230 (diff) |
rcu: New rcu_user_enter_after_irq() and rcu_user_exit_after_irq() APIs
In some cases, it is necessary to enter or exit userspace-RCU-idle mode
from an interrupt handler, for example, if some other CPU sends this
CPU a resched IPI. In this case, the current CPU would enter the IPI
handler in userspace-RCU-idle mode, but would need to exit the IPI handler
after having exited that mode.
To allow this to work, this commit adds two new APIs to TREE_RCU:
- rcu_user_enter_after_irq(). This must be called from an interrupt between
rcu_irq_enter() and rcu_irq_exit(). After the irq calls rcu_irq_exit(),
the irq handler will return into an RCU extended quiescent state.
In theory, this interrupt is never a nested interrupt, but in practice
it might interrupt softirq, which looks to RCU like a nested interrupt.
- rcu_user_exit_after_irq(). This must be called from a non-nesting
interrupt, interrupting an RCU extended quiescent state, also
between rcu_irq_enter() and rcu_irq_exit(). After the irq calls
rcu_irq_exit(), the irq handler will return in an RCU non-quiescent
state.
[ Combined with "Allow calls to rcu_exit_user_irq from nesting irqs." ]
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
Diffstat (limited to 'kernel/rcutree.c')
-rw-r--r-- | kernel/rcutree.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index af0dc3472a4b..4138f59fa2f4 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c | |||
@@ -426,6 +426,27 @@ void rcu_user_enter(void) | |||
426 | 426 | ||
427 | 427 | ||
428 | /** | 428 | /** |
429 | * rcu_user_enter_after_irq - inform RCU that we are going to resume userspace | ||
430 | * after the current irq returns. | ||
431 | * | ||
432 | * This is similar to rcu_user_enter() but in the context of a non-nesting | ||
433 | * irq. After this call, RCU enters into idle mode when the interrupt | ||
434 | * returns. | ||
435 | */ | ||
436 | void rcu_user_enter_after_irq(void) | ||
437 | { | ||
438 | unsigned long flags; | ||
439 | struct rcu_dynticks *rdtp; | ||
440 | |||
441 | local_irq_save(flags); | ||
442 | rdtp = &__get_cpu_var(rcu_dynticks); | ||
443 | /* Ensure this irq is interrupting a non-idle RCU state. */ | ||
444 | WARN_ON_ONCE(!(rdtp->dynticks_nesting & DYNTICK_TASK_MASK)); | ||
445 | rdtp->dynticks_nesting = 1; | ||
446 | local_irq_restore(flags); | ||
447 | } | ||
448 | |||
449 | /** | ||
429 | * rcu_irq_exit - inform RCU that current CPU is exiting irq towards idle | 450 | * rcu_irq_exit - inform RCU that current CPU is exiting irq towards idle |
430 | * | 451 | * |
431 | * Exit from an interrupt handler, which might possibly result in entering | 452 | * Exit from an interrupt handler, which might possibly result in entering |
@@ -550,6 +571,28 @@ void rcu_user_exit(void) | |||
550 | } | 571 | } |
551 | 572 | ||
552 | /** | 573 | /** |
574 | * rcu_user_exit_after_irq - inform RCU that we won't resume to userspace | ||
575 | * idle mode after the current non-nesting irq returns. | ||
576 | * | ||
577 | * This is similar to rcu_user_exit() but in the context of an irq. | ||
578 | * This is called when the irq has interrupted a userspace RCU idle mode | ||
579 | * context. When the current non-nesting interrupt returns after this call, | ||
580 | * the CPU won't restore the RCU idle mode. | ||
581 | */ | ||
582 | void rcu_user_exit_after_irq(void) | ||
583 | { | ||
584 | unsigned long flags; | ||
585 | struct rcu_dynticks *rdtp; | ||
586 | |||
587 | local_irq_save(flags); | ||
588 | rdtp = &__get_cpu_var(rcu_dynticks); | ||
589 | /* Ensure we are interrupting an RCU idle mode. */ | ||
590 | WARN_ON_ONCE(rdtp->dynticks_nesting & DYNTICK_TASK_NEST_MASK); | ||
591 | rdtp->dynticks_nesting += DYNTICK_TASK_EXIT_IDLE; | ||
592 | local_irq_restore(flags); | ||
593 | } | ||
594 | |||
595 | /** | ||
553 | * rcu_irq_enter - inform RCU that current CPU is entering irq away from idle | 596 | * rcu_irq_enter - inform RCU that current CPU is entering irq away from idle |
554 | * | 597 | * |
555 | * Enter an interrupt handler, which might possibly result in exiting | 598 | * Enter an interrupt handler, which might possibly result in exiting |