diff options
| author | Lai Jiangshan <laijs@cn.fujitsu.com> | 2010-04-20 04:23:07 -0400 |
|---|---|---|
| committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2010-05-10 14:08:31 -0400 |
| commit | 2b3fc35f6919344e3cf722dde8308f47235c0b70 (patch) | |
| tree | 2bc2cfc9c1a032d51a3d99a10e309e100b9eea4a | |
| parent | b57f95a38233a2e73b679bea4a5453a1cc2a1cc9 (diff) | |
rcu: optionally leave lockdep enabled after RCU lockdep splat
There is no need to disable lockdep after an RCU lockdep splat,
so remove the debug_lockdeps_off() from lockdep_rcu_dereference().
To avoid repeated lockdep splats, use a static variable in the inlined
rcu_dereference_check() and rcu_dereference_protected() macros so that
a given instance splats only once, but so that multiple instances can
be detected per boot.
This is controlled by a new config variable CONFIG_PROVE_RCU_REPEATEDLY,
which is disabled by default. This provides the normal lockdep behavior
by default, but permits people who want to find multiple RCU-lockdep
splats per boot to easily do so.
Requested-by: Eric Paris <eparis@redhat.com>
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Tested-by: Eric Paris <eparis@redhat.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
| -rw-r--r-- | include/linux/rcupdate.h | 15 | ||||
| -rw-r--r-- | kernel/lockdep.c | 3 | ||||
| -rw-r--r-- | lib/Kconfig.debug | 12 |
3 files changed, 26 insertions, 4 deletions
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index db266bbed23f..4dca2752cfde 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h | |||
| @@ -192,6 +192,15 @@ static inline int rcu_read_lock_sched_held(void) | |||
| 192 | 192 | ||
| 193 | extern int rcu_my_thread_group_empty(void); | 193 | extern int rcu_my_thread_group_empty(void); |
| 194 | 194 | ||
| 195 | #define __do_rcu_dereference_check(c) \ | ||
| 196 | do { \ | ||
| 197 | static bool __warned; \ | ||
| 198 | if (debug_lockdep_rcu_enabled() && !__warned && !(c)) { \ | ||
| 199 | __warned = true; \ | ||
| 200 | lockdep_rcu_dereference(__FILE__, __LINE__); \ | ||
| 201 | } \ | ||
| 202 | } while (0) | ||
| 203 | |||
| 195 | /** | 204 | /** |
| 196 | * rcu_dereference_check - rcu_dereference with debug checking | 205 | * rcu_dereference_check - rcu_dereference with debug checking |
| 197 | * @p: The pointer to read, prior to dereferencing | 206 | * @p: The pointer to read, prior to dereferencing |
| @@ -221,8 +230,7 @@ extern int rcu_my_thread_group_empty(void); | |||
| 221 | */ | 230 | */ |
| 222 | #define rcu_dereference_check(p, c) \ | 231 | #define rcu_dereference_check(p, c) \ |
| 223 | ({ \ | 232 | ({ \ |
| 224 | if (debug_lockdep_rcu_enabled() && !(c)) \ | 233 | __do_rcu_dereference_check(c); \ |
| 225 | lockdep_rcu_dereference(__FILE__, __LINE__); \ | ||
| 226 | rcu_dereference_raw(p); \ | 234 | rcu_dereference_raw(p); \ |
| 227 | }) | 235 | }) |
| 228 | 236 | ||
| @@ -239,8 +247,7 @@ extern int rcu_my_thread_group_empty(void); | |||
| 239 | */ | 247 | */ |
| 240 | #define rcu_dereference_protected(p, c) \ | 248 | #define rcu_dereference_protected(p, c) \ |
| 241 | ({ \ | 249 | ({ \ |
| 242 | if (debug_lockdep_rcu_enabled() && !(c)) \ | 250 | __do_rcu_dereference_check(c); \ |
| 243 | lockdep_rcu_dereference(__FILE__, __LINE__); \ | ||
| 244 | (p); \ | 251 | (p); \ |
| 245 | }) | 252 | }) |
| 246 | 253 | ||
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 2594e1ce41cb..3a756ba8d5d8 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
| @@ -3801,8 +3801,11 @@ void lockdep_rcu_dereference(const char *file, const int line) | |||
| 3801 | { | 3801 | { |
| 3802 | struct task_struct *curr = current; | 3802 | struct task_struct *curr = current; |
| 3803 | 3803 | ||
| 3804 | #ifndef CONFIG_PROVE_RCU_REPEATEDLY | ||
| 3804 | if (!debug_locks_off()) | 3805 | if (!debug_locks_off()) |
| 3805 | return; | 3806 | return; |
| 3807 | #endif /* #ifdef CONFIG_PROVE_RCU_REPEATEDLY */ | ||
| 3808 | /* Note: the following can be executed concurrently, so be careful. */ | ||
| 3806 | printk("\n===================================================\n"); | 3809 | printk("\n===================================================\n"); |
| 3807 | printk( "[ INFO: suspicious rcu_dereference_check() usage. ]\n"); | 3810 | printk( "[ INFO: suspicious rcu_dereference_check() usage. ]\n"); |
| 3808 | printk( "---------------------------------------------------\n"); | 3811 | printk( "---------------------------------------------------\n"); |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 935248bdbc47..94090b4bb7d2 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
| @@ -512,6 +512,18 @@ config PROVE_RCU | |||
| 512 | 512 | ||
| 513 | Say N if you are unsure. | 513 | Say N if you are unsure. |
| 514 | 514 | ||
| 515 | config PROVE_RCU_REPEATEDLY | ||
| 516 | bool "RCU debugging: don't disable PROVE_RCU on first splat" | ||
| 517 | depends on PROVE_RCU | ||
| 518 | default n | ||
| 519 | help | ||
| 520 | By itself, PROVE_RCU will disable checking upon issuing the | ||
| 521 | first warning (or "splat"). This feature prevents such | ||
| 522 | disabling, allowing multiple RCU-lockdep warnings to be printed | ||
| 523 | on a single reboot. | ||
| 524 | |||
| 525 | Say N if you are unsure. | ||
| 526 | |||
| 515 | config LOCKDEP | 527 | config LOCKDEP |
| 516 | bool | 528 | bool |
| 517 | depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT | 529 | depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT |
