diff options
| author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2011-05-24 11:31:09 -0400 |
|---|---|---|
| committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2011-09-29 00:36:37 -0400 |
| commit | b3fbab0571eb09746cc0283648165ec00efc8eb2 (patch) | |
| tree | 63bc01cbf03a5df34a96af292a00df4a96dc148a /include/linux | |
| parent | d5988af53102f3b73e5e0788be024ccfa51869de (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.h | 2 | ||||
| -rw-r--r-- | include/linux/rcupdate.h | 28 |
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 |
| 551 | extern void lockdep_rcu_dereference(const char *file, const int line); | 551 | void 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 | }) |
