aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-09-06 20:39:49 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-09-25 09:44:41 -0400
commitcc6783f788d8fe8b23ec6fc2762f5e8c9a418eee (patch)
treedfecd009a80c422393c2c6130d9a38ec7329e851
parentc337f8f58ed7cf150651d232af8222421a71463d (diff)
rcu: Is it safe to enter an RCU read-side critical section?
There is currently no way for kernel code to determine whether it is safe to enter an RCU read-side critical section, in other words, whether or not RCU is paying attention to the currently running CPU. Given the large and increasing quantity of code shared by the idle loop and non-idle code, the this shortcoming is becoming increasingly painful. This commit therefore adds __rcu_is_watching(), which returns true if it is safe to enter an RCU read-side critical section on the currently running CPU. This function is quite fast, using only a __this_cpu_read(). However, the caller must disable preemption. Reported-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Reviewed-by: Josh Triplett <josh@joshtriplett.org>
-rw-r--r--include/linux/rcupdate.h8
-rw-r--r--include/linux/rcutiny.h9
-rw-r--r--include/linux/rcutree.h2
-rw-r--r--kernel/rcutiny.c4
-rw-r--r--kernel/rcutree.c13
5 files changed, 30 insertions, 6 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index f1f1bc39346b..a53a21a2808c 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -261,6 +261,10 @@ static inline void rcu_user_hooks_switch(struct task_struct *prev,
261 rcu_irq_exit(); \ 261 rcu_irq_exit(); \
262 } while (0) 262 } while (0)
263 263
264#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP)
265extern int rcu_is_cpu_idle(void);
266#endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) */
267
264/* 268/*
265 * Infrastructure to implement the synchronize_() primitives in 269 * Infrastructure to implement the synchronize_() primitives in
266 * TREE_RCU and rcu_barrier_() primitives in TINY_RCU. 270 * TREE_RCU and rcu_barrier_() primitives in TINY_RCU.
@@ -297,10 +301,6 @@ static inline void destroy_rcu_head_on_stack(struct rcu_head *head)
297} 301}
298#endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */ 302#endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
299 303
300#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SMP)
301extern int rcu_is_cpu_idle(void);
302#endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_SMP) */
303
304#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) 304#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU)
305bool rcu_lockdep_current_cpu_online(void); 305bool rcu_lockdep_current_cpu_online(void);
306#else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */ 306#else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h
index e31005ee339e..bee665964878 100644
--- a/include/linux/rcutiny.h
+++ b/include/linux/rcutiny.h
@@ -132,4 +132,13 @@ static inline void rcu_scheduler_starting(void)
132} 132}
133#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ 133#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
134 134
135#ifdef CONFIG_RCU_TRACE
136
137static inline bool __rcu_is_watching(void)
138{
139 return !rcu_is_cpu_idle();
140}
141
142#endif /* #ifdef CONFIG_RCU_TRACE */
143
135#endif /* __LINUX_RCUTINY_H */ 144#endif /* __LINUX_RCUTINY_H */
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 226169d1bd2b..293613dfd2a5 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -90,4 +90,6 @@ extern void exit_rcu(void);
90extern void rcu_scheduler_starting(void); 90extern void rcu_scheduler_starting(void);
91extern int rcu_scheduler_active __read_mostly; 91extern int rcu_scheduler_active __read_mostly;
92 92
93extern bool __rcu_is_watching(void);
94
93#endif /* __LINUX_RCUTREE_H */ 95#endif /* __LINUX_RCUTREE_H */
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index 9ed6075dc562..b4bc61874d77 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -174,7 +174,7 @@ void rcu_irq_enter(void)
174} 174}
175EXPORT_SYMBOL_GPL(rcu_irq_enter); 175EXPORT_SYMBOL_GPL(rcu_irq_enter);
176 176
177#ifdef CONFIG_DEBUG_LOCK_ALLOC 177#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE)
178 178
179/* 179/*
180 * Test whether RCU thinks that the current CPU is idle. 180 * Test whether RCU thinks that the current CPU is idle.
@@ -185,7 +185,7 @@ int rcu_is_cpu_idle(void)
185} 185}
186EXPORT_SYMBOL(rcu_is_cpu_idle); 186EXPORT_SYMBOL(rcu_is_cpu_idle);
187 187
188#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ 188#endif /* defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) */
189 189
190/* 190/*
191 * Test whether the current CPU was interrupted from idle. Nested 191 * Test whether the current CPU was interrupted from idle. Nested
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 32618b3fe4e6..910d868808dc 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -671,6 +671,19 @@ int rcu_is_cpu_idle(void)
671} 671}
672EXPORT_SYMBOL(rcu_is_cpu_idle); 672EXPORT_SYMBOL(rcu_is_cpu_idle);
673 673
674/**
675 * __rcu_is_watching - are RCU read-side critical sections safe?
676 *
677 * Return true if RCU is watching the running CPU, which means that
678 * this CPU can safely enter RCU read-side critical sections. Unlike
679 * rcu_is_cpu_idle(), the caller of __rcu_is_watching() must have at
680 * least disabled preemption.
681 */
682bool __rcu_is_watching(void)
683{
684 return !!(atomic_read(this_cpu_ptr(&rcu_dynticks.dynticks)) & 0x1);
685}
686
674#if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU) 687#if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU)
675 688
676/* 689/*