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>
This commit is contained in:
committed by
Paul E. McKenney
parent
b57f95a382
commit
2b3fc35f69
@@ -192,6 +192,15 @@ static inline int rcu_read_lock_sched_held(void)
|
|||||||
|
|
||||||
extern int rcu_my_thread_group_empty(void);
|
extern int rcu_my_thread_group_empty(void);
|
||||||
|
|
||||||
|
#define __do_rcu_dereference_check(c) \
|
||||||
|
do { \
|
||||||
|
static bool __warned; \
|
||||||
|
if (debug_lockdep_rcu_enabled() && !__warned && !(c)) { \
|
||||||
|
__warned = true; \
|
||||||
|
lockdep_rcu_dereference(__FILE__, __LINE__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rcu_dereference_check - rcu_dereference with debug checking
|
* rcu_dereference_check - rcu_dereference with debug checking
|
||||||
* @p: The pointer to read, prior to dereferencing
|
* @p: The pointer to read, prior to dereferencing
|
||||||
@@ -221,8 +230,7 @@ extern int rcu_my_thread_group_empty(void);
|
|||||||
*/
|
*/
|
||||||
#define rcu_dereference_check(p, c) \
|
#define rcu_dereference_check(p, c) \
|
||||||
({ \
|
({ \
|
||||||
if (debug_lockdep_rcu_enabled() && !(c)) \
|
__do_rcu_dereference_check(c); \
|
||||||
lockdep_rcu_dereference(__FILE__, __LINE__); \
|
|
||||||
rcu_dereference_raw(p); \
|
rcu_dereference_raw(p); \
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -239,8 +247,7 @@ extern int rcu_my_thread_group_empty(void);
|
|||||||
*/
|
*/
|
||||||
#define rcu_dereference_protected(p, c) \
|
#define rcu_dereference_protected(p, c) \
|
||||||
({ \
|
({ \
|
||||||
if (debug_lockdep_rcu_enabled() && !(c)) \
|
__do_rcu_dereference_check(c); \
|
||||||
lockdep_rcu_dereference(__FILE__, __LINE__); \
|
|
||||||
(p); \
|
(p); \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -3801,8 +3801,11 @@ void lockdep_rcu_dereference(const char *file, const int line)
|
|||||||
{
|
{
|
||||||
struct task_struct *curr = current;
|
struct task_struct *curr = current;
|
||||||
|
|
||||||
|
#ifndef CONFIG_PROVE_RCU_REPEATEDLY
|
||||||
if (!debug_locks_off())
|
if (!debug_locks_off())
|
||||||
return;
|
return;
|
||||||
|
#endif /* #ifdef CONFIG_PROVE_RCU_REPEATEDLY */
|
||||||
|
/* Note: the following can be executed concurrently, so be careful. */
|
||||||
printk("\n===================================================\n");
|
printk("\n===================================================\n");
|
||||||
printk( "[ INFO: suspicious rcu_dereference_check() usage. ]\n");
|
printk( "[ INFO: suspicious rcu_dereference_check() usage. ]\n");
|
||||||
printk( "---------------------------------------------------\n");
|
printk( "---------------------------------------------------\n");
|
||||||
|
@@ -512,6 +512,18 @@ config PROVE_RCU
|
|||||||
|
|
||||||
Say N if you are unsure.
|
Say N if you are unsure.
|
||||||
|
|
||||||
|
config PROVE_RCU_REPEATEDLY
|
||||||
|
bool "RCU debugging: don't disable PROVE_RCU on first splat"
|
||||||
|
depends on PROVE_RCU
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
By itself, PROVE_RCU will disable checking upon issuing the
|
||||||
|
first warning (or "splat"). This feature prevents such
|
||||||
|
disabling, allowing multiple RCU-lockdep warnings to be printed
|
||||||
|
on a single reboot.
|
||||||
|
|
||||||
|
Say N if you are unsure.
|
||||||
|
|
||||||
config LOCKDEP
|
config LOCKDEP
|
||||||
bool
|
bool
|
||||||
depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
|
depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
|
||||||
|
Reference in New Issue
Block a user