aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2011-05-24 11:31:09 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2011-09-29 00:36:37 -0400
commitb3fbab0571eb09746cc0283648165ec00efc8eb2 (patch)
tree63bc01cbf03a5df34a96af292a00df4a96dc148a /include/linux
parentd5988af53102f3b73e5e0788be024ccfa51869de (diff)
rcu: Restore checks for blocking in RCU read-side critical sections
Long ago, using TREE_RCU with PREEMPT would result in "scheduling while atomic" diagnostics if you blocked in an RCU read-side critical section. However, PREEMPT now implies TREE_PREEMPT_RCU, which defeats this diagnostic. This commit therefore adds a replacement diagnostic based on PROVE_RCU. Because rcu_lockdep_assert() and lockdep_rcu_dereference() are now being used for things that have nothing to do with rcu_dereference(), rename lockdep_rcu_dereference() to lockdep_rcu_suspicious() and add a third argument that is a string indicating what is suspicious. This third argument is passed in from a new third argument to rcu_lockdep_assert(). Update all calls to rcu_lockdep_assert() to add an informative third argument. Also, add a pair of rcu_lockdep_assert() calls from within rcu_note_context_switch(), one complaining if a context switch occurs in an RCU-bh read-side critical section and another complaining if a context switch occurs in an RCU-sched read-side critical section. These are present only if the PROVE_RCU kernel parameter is enabled. Finally, fix some checkpatch whitespace complaints in lockdep.c. Again, you must enable PROVE_RCU to see these new diagnostics. But you are enabling PROVE_RCU to check out new RCU uses in any case, aren't you? Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/lockdep.h2
-rw-r--r--include/linux/rcupdate.h28
2 files changed, 23 insertions, 7 deletions
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index ef820a3c378b..b6a56e37284c 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -548,7 +548,7 @@ do { \
548#endif 548#endif
549 549
550#ifdef CONFIG_PROVE_RCU 550#ifdef CONFIG_PROVE_RCU
551extern void lockdep_rcu_dereference(const char *file, const int line); 551void lockdep_rcu_suspicious(const char *file, const int line, const char *s);
552#endif 552#endif
553 553
554#endif /* __LINUX_LOCKDEP_H */ 554#endif /* __LINUX_LOCKDEP_H */
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 8f4f881a0ad8..8e7470d8b676 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -297,19 +297,31 @@ extern int rcu_my_thread_group_empty(void);
297/** 297/**
298 * rcu_lockdep_assert - emit lockdep splat if specified condition not met 298 * rcu_lockdep_assert - emit lockdep splat if specified condition not met
299 * @c: condition to check 299 * @c: condition to check
300 * @s: informative message
300 */ 301 */
301#define rcu_lockdep_assert(c) \ 302#define rcu_lockdep_assert(c, s) \
302 do { \ 303 do { \
303 static bool __warned; \ 304 static bool __warned; \
304 if (debug_lockdep_rcu_enabled() && !__warned && !(c)) { \ 305 if (debug_lockdep_rcu_enabled() && !__warned && !(c)) { \
305 __warned = true; \ 306 __warned = true; \
306 lockdep_rcu_dereference(__FILE__, __LINE__); \ 307 lockdep_rcu_suspicious(__FILE__, __LINE__, s); \
307 } \ 308 } \
308 } while (0) 309 } while (0)
309 310
311#define rcu_sleep_check() \
312 do { \
313 rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map), \
314 "Illegal context switch in RCU-bh" \
315 " read-side critical section"); \
316 rcu_lockdep_assert(!lock_is_held(&rcu_sched_lock_map), \
317 "Illegal context switch in RCU-sched"\
318 " read-side critical section"); \
319 } while (0)
320
310#else /* #ifdef CONFIG_PROVE_RCU */ 321#else /* #ifdef CONFIG_PROVE_RCU */
311 322
312#define rcu_lockdep_assert(c) do { } while (0) 323#define rcu_lockdep_assert(c, s) do { } while (0)
324#define rcu_sleep_check() do { } while (0)
313 325
314#endif /* #else #ifdef CONFIG_PROVE_RCU */ 326#endif /* #else #ifdef CONFIG_PROVE_RCU */
315 327
@@ -338,14 +350,16 @@ extern int rcu_my_thread_group_empty(void);
338#define __rcu_dereference_check(p, c, space) \ 350#define __rcu_dereference_check(p, c, space) \
339 ({ \ 351 ({ \
340 typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \ 352 typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \
341 rcu_lockdep_assert(c); \ 353 rcu_lockdep_assert(c, "suspicious rcu_dereference_check()" \
354 " usage"); \
342 rcu_dereference_sparse(p, space); \ 355 rcu_dereference_sparse(p, space); \
343 smp_read_barrier_depends(); \ 356 smp_read_barrier_depends(); \
344 ((typeof(*p) __force __kernel *)(_________p1)); \ 357 ((typeof(*p) __force __kernel *)(_________p1)); \
345 }) 358 })
346#define __rcu_dereference_protected(p, c, space) \ 359#define __rcu_dereference_protected(p, c, space) \
347 ({ \ 360 ({ \
348 rcu_lockdep_assert(c); \ 361 rcu_lockdep_assert(c, "suspicious rcu_dereference_protected()" \
362 " usage"); \
349 rcu_dereference_sparse(p, space); \ 363 rcu_dereference_sparse(p, space); \
350 ((typeof(*p) __force __kernel *)(p)); \ 364 ((typeof(*p) __force __kernel *)(p)); \
351 }) 365 })
@@ -359,7 +373,9 @@ extern int rcu_my_thread_group_empty(void);
359#define __rcu_dereference_index_check(p, c) \ 373#define __rcu_dereference_index_check(p, c) \
360 ({ \ 374 ({ \
361 typeof(p) _________p1 = ACCESS_ONCE(p); \ 375 typeof(p) _________p1 = ACCESS_ONCE(p); \
362 rcu_lockdep_assert(c); \ 376 rcu_lockdep_assert(c, \
377 "suspicious rcu_dereference_index_check()" \
378 " usage"); \
363 smp_read_barrier_depends(); \ 379 smp_read_barrier_depends(); \
364 (_________p1); \ 380 (_________p1); \
365 }) 381 })