]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
rcu: Permit RCU_NONIDLE() to be used from interrupt context
authorPaul E. McKenney <paul.mckenney@linaro.org>
Tue, 31 Jul 2012 17:12:48 +0000 (10:12 -0700)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Tue, 4 Sep 2012 23:20:52 +0000 (16:20 -0700)
There is a need to use RCU from interrupt context, but either before
rcu_irq_enter() is called or after rcu_irq_exit() is called.  If the
interrupt occurs from idle, then lockdep-RCU will complain about such
uses, as they appear to be illegal uses of RCU from the idle loop.
In other environments, RCU_NONIDLE() could be used to properly protect
the use of RCU, but RCU_NONIDLE() currently cannot be invoked except
from process context.

This commit therefore modifies RCU_NONIDLE() to permit its use more
globally.

It also exports rcu_irq_exit() and rcu_irq_enter() in order to avoid
build errors.  The need for this is a bit counter-intuitive, hence this
explanation from Steven Rostedt:

Because some trace events happen inside the idle loop after rcu
has "shutdown", we needed to create "trace_foo_rcuidle()" handlers
that can handle this condition. That is, for every trace_foo()
static inline (used at the tracepoint location), there exists a
static inline trace_foo_rcuidle(), that looks something like this:

static inline void trace_##name##_rcuidle(proto) {
if (static_key_false(&__tracepoint_##name.key)) {
rcu_idle_exit();
__DO_TRACE();
rcu_idle_enter();
}
}

Although these calls are never used by module code, because they
are static inlines, they are still defined for all tracepoints,
kernel tracepoints as well as module tracepoints. And thus,
need the export :-(

Reported-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
include/linux/rcupdate.h
kernel/rcutiny.c
kernel/rcutree.c

index 115ead2b51553d78a523c4e62db3cb4b84866cd0..0fbbd52e01f9c731d19d29f543d71e2c83fadb91 100644 (file)
@@ -210,14 +210,12 @@ extern void exit_rcu(void);
  * to nest RCU_NONIDLE() wrappers, but the nesting level is currently
  * quite limited.  If deeper nesting is required, it will be necessary
  * to adjust DYNTICK_TASK_NESTING_VALUE accordingly.
- *
- * This macro may be used from process-level code only.
  */
 #define RCU_NONIDLE(a) \
        do { \
-               rcu_idle_exit(); \
+               rcu_irq_enter(); \
                do { a; } while (0); \
-               rcu_idle_enter(); \
+               rcu_irq_exit(); \
        } while (0)
 
 /*
index e4163c5af1de96478ee654346ef902a17aaba453..2e073a24d25098326f44a032bdce9960341265d3 100644 (file)
@@ -115,6 +115,7 @@ void rcu_irq_exit(void)
        rcu_idle_enter_common(newval);
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_irq_exit);
 
 /* Common code for rcu_idle_exit() and rcu_irq_enter(), see kernel/rcutree.c. */
 static void rcu_idle_exit_common(long long oldval)
@@ -172,6 +173,7 @@ void rcu_irq_enter(void)
        rcu_idle_exit_common(oldval);
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_irq_enter);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 
index f280e542e3e9f531df83b03d1e1fce6cf8ebaaa2..96b8aff433a9363a5c7094421caef945972b1b42 100644 (file)
@@ -447,6 +447,7 @@ void rcu_irq_exit(void)
                rcu_idle_enter_common(rdtp, oldval);
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_irq_exit);
 
 /*
  * rcu_idle_exit_common - inform RCU that current CPU is moving away from idle
@@ -542,6 +543,7 @@ void rcu_irq_enter(void)
                rcu_idle_exit_common(rdtp, oldval);
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_irq_enter);
 
 /**
  * rcu_nmi_enter - inform RCU of entry to NMI context