rcu: optionally leave lockdep enabled after RCU lockdep splat
authorLai Jiangshan <laijs@cn.fujitsu.com>
Tue, 20 Apr 2010 08:23:07 +0000 (16:23 +0800)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Mon, 10 May 2010 18:08:31 +0000 (11:08 -0700)
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>
include/linux/rcupdate.h
kernel/lockdep.c
lib/Kconfig.debug

index db266bbed23f3f8f2751e85166789cc55fbb80ea..4dca2752cfde969b7e96dcf7bc73b9fd7b6802cd 100644 (file)
@@ -192,6 +192,15 @@ static inline int rcu_read_lock_sched_held(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
  * @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) \
        ({ \
-               if (debug_lockdep_rcu_enabled() && !(c)) \
-                       lockdep_rcu_dereference(__FILE__, __LINE__); \
+               __do_rcu_dereference_check(c); \
                rcu_dereference_raw(p); \
        })
 
@@ -239,8 +247,7 @@ extern int rcu_my_thread_group_empty(void);
  */
 #define rcu_dereference_protected(p, c) \
        ({ \
-               if (debug_lockdep_rcu_enabled() && !(c)) \
-                       lockdep_rcu_dereference(__FILE__, __LINE__); \
+               __do_rcu_dereference_check(c); \
                (p); \
        })
 
index 2594e1ce41cbf12889b44deb3fc202c0a5c30fa2..3a756ba8d5d85ccf86baa47883cb171be601c5b4 100644 (file)
@@ -3801,8 +3801,11 @@ void lockdep_rcu_dereference(const char *file, const int line)
 {
        struct task_struct *curr = current;
 
+#ifndef CONFIG_PROVE_RCU_REPEATEDLY
        if (!debug_locks_off())
                return;
+#endif /* #ifdef CONFIG_PROVE_RCU_REPEATEDLY */
+       /* Note: the following can be executed concurrently, so be careful. */
        printk("\n===================================================\n");
        printk(  "[ INFO: suspicious rcu_dereference_check() usage. ]\n");
        printk(  "---------------------------------------------------\n");
index 935248bdbc471aaf8485ef545784b70313c9dfda..94090b4bb7d2dfa9674b1f0a07584fa076b70529 100644 (file)
@@ -512,6 +512,18 @@ config PROVE_RCU
 
         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
        bool
        depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT