mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
To: linux-kernel@vger.kernel.org
Cc: mingo@elte.hu, laijs@cn.fujitsu.com, dipankar@in.ibm.com,
	akpm@linux-foundation.org, mathieu.desnoyers@polymtl.ca,
	josh@joshtriplett.org, dvhltc@us.ibm.com, niv@us.ibm.com,
	tglx@linutronix.de, peterz@infradead.org, rostedt@goodmis.org,
	Valdis.Kletnieks@vt.edu, dhowells@redhat.com,
	eric.dumazet@gmail.com,
	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	"David S. Miller" <davem@davemloft.net>,
	"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>,
	Alexey Dobriyan <adobriyan@gmail.com>
Subject: [PATCH tip/core/rcu 23/48] tree/tiny rcu: Add debug RCU head objects (v5)
Date: Tue,  4 May 2010 13:19:33 -0700	[thread overview]
Message-ID: <1273004398-19760-23-git-send-email-paulmck@linux.vnet.ibm.com> (raw)
In-Reply-To: <20100504201934.GA19234@linux.vnet.ibm.com>

From: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>

Helps finding racy users of call_rcu(), which results in hangs because list
entries are overwritten and/or skipped.

Changelog since v4:
- Bissectability is now OK
- Now generate a WARN_ON_ONCE() for non-initialized rcu_head passed to
  call_rcu(). Statically initialized objects are detected with
  object_is_static().
- Rename rcu_head_init_on_stack to init_rcu_head_on_stack.
- Remove init_rcu_head() completely.

Changelog since v3:
- Include comments from Lai Jiangshan

This new patch version is based on the debugobjects with the newly introduced
"active state" tracker.

Non-initialized entries are all considered as "statically initialized". An
activation fixup (triggered by call_rcu()) takes care of performing the debug
object initialization without issuing any warning. Since we cannot increase the
size of struct rcu_head, I don't see much room to put an identifier for
statically initialized rcu_head structures. So for now, we have to live without
"activation without explicit init" detection. But the main purpose of this debug
option is to detect double-activations (double call_rcu() use of a rcu_head
before the callback is executed), which is correctly addressed here.

This also detects potential internal RCU callback corruption, which would cause
the callbacks to be executed twice.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
CC: David S. Miller <davem@davemloft.net>
CC: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
CC: akpm@linux-foundation.org
CC: mingo@elte.hu
CC: laijs@cn.fujitsu.com
CC: dipankar@in.ibm.com
CC: josh@joshtriplett.org
CC: dvhltc@us.ibm.com
CC: niv@us.ibm.com
CC: tglx@linutronix.de
CC: peterz@infradead.org
CC: rostedt@goodmis.org
CC: Valdis.Kletnieks@vt.edu
CC: dhowells@redhat.com
CC: eric.dumazet@gmail.com
CC: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Lai Jiangshan <laijs@cn.fujitsu.com>
---
 include/linux/rcupdate.h |   49 +++++++++++++++
 kernel/rcupdate.c        |  149 ++++++++++++++++++++++++++++++++++++++++++++++
 kernel/rcutiny.c         |    2 +
 kernel/rcutree.c         |    2 +
 lib/Kconfig.debug        |    6 ++
 5 files changed, 208 insertions(+), 0 deletions(-)

diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 3a1a70d..2f9e56c 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -40,6 +40,7 @@
 #include <linux/seqlock.h>
 #include <linux/lockdep.h>
 #include <linux/completion.h>
+#include <linux/debugobjects.h>
 
 #ifdef CONFIG_RCU_TORTURE_TEST
 extern int rcutorture_runnable; /* for sysctl */
@@ -73,6 +74,16 @@ extern void rcu_init(void);
 #error "Unknown RCU implementation specified to kernel configuration"
 #endif
 
+/*
+ * init_rcu_head_on_stack()/destroy_rcu_head_on_stack() are needed for dynamic
+ * initialization and destruction of rcu_head on the stack. rcu_head structures
+ * allocated dynamically in the heap or defined statically don't need any
+ * initialization.
+ */
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+extern void init_rcu_head_on_stack(struct rcu_head *head);
+extern void destroy_rcu_head_on_stack(struct rcu_head *head);
+#else /* !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 static inline void init_rcu_head_on_stack(struct rcu_head *head)
 {
 }
@@ -80,6 +91,7 @@ static inline void init_rcu_head_on_stack(struct rcu_head *head)
 static inline void destroy_rcu_head_on_stack(struct rcu_head *head)
 {
 }
+#endif	/* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 
@@ -511,4 +523,41 @@ extern void call_rcu(struct rcu_head *head,
 extern void call_rcu_bh(struct rcu_head *head,
 			void (*func)(struct rcu_head *head));
 
+/*
+ * debug_rcu_head_queue()/debug_rcu_head_unqueue() are used internally
+ * by call_rcu() and rcu callback execution, and are therefore not part of the
+ * RCU API. Leaving in rcupdate.h because they are used by all RCU flavors.
+ */
+
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+# define STATE_RCU_HEAD_READY	0
+# define STATE_RCU_HEAD_QUEUED	1
+
+extern struct debug_obj_descr rcuhead_debug_descr;
+
+static inline void debug_rcu_head_queue(struct rcu_head *head)
+{
+	debug_object_activate(head, &rcuhead_debug_descr);
+	debug_object_active_state(head, &rcuhead_debug_descr,
+				  STATE_RCU_HEAD_READY,
+				  STATE_RCU_HEAD_QUEUED);
+}
+
+static inline void debug_rcu_head_unqueue(struct rcu_head *head)
+{
+	debug_object_active_state(head, &rcuhead_debug_descr,
+				  STATE_RCU_HEAD_QUEUED,
+				  STATE_RCU_HEAD_READY);
+	debug_object_deactivate(head, &rcuhead_debug_descr);
+}
+#else	/* !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+static inline void debug_rcu_head_queue(struct rcu_head *head)
+{
+}
+
+static inline void debug_rcu_head_unqueue(struct rcu_head *head)
+{
+}
+#endif	/* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
+
 #endif /* __LINUX_RCUPDATE_H */
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 72a8dc9..be12514 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -114,3 +114,152 @@ int rcu_my_thread_group_empty(void)
 }
 EXPORT_SYMBOL_GPL(rcu_my_thread_group_empty);
 #endif /* #ifdef CONFIG_PROVE_RCU */
+
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+static inline void debug_init_rcu_head(struct rcu_head *head)
+{
+	debug_object_init(head, &rcuhead_debug_descr);
+}
+
+static inline void debug_rcu_head_free(struct rcu_head *head)
+{
+	debug_object_free(head, &rcuhead_debug_descr);
+}
+
+/*
+ * fixup_init is called when:
+ * - an active object is initialized
+ */
+static int rcuhead_fixup_init(void *addr, enum debug_obj_state state)
+{
+	struct rcu_head *head = addr;
+
+	switch (state) {
+	case ODEBUG_STATE_ACTIVE:
+		/*
+		 * Ensure that queued callbacks are all executed.
+		 * If we detect that we are nested in a RCU read-side critical
+		 * section, we should simply fail, otherwise we would deadlock.
+		 */
+#ifndef CONFIG_PREEMPT
+		WARN_ON(1);
+		return 0;
+#else
+		if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
+		    irqs_disabled()) {
+			WARN_ON(1);
+			return 0;
+		}
+		rcu_barrier();
+		rcu_barrier_sched();
+		rcu_barrier_bh();
+		debug_object_init(head, &rcuhead_debug_descr);
+		return 1;
+#endif
+	default:
+		return 0;
+	}
+}
+
+/*
+ * fixup_activate is called when:
+ * - an active object is activated
+ * - an unknown object is activated (might be a statically initialized object)
+ * Activation is performed internally by call_rcu().
+ */
+static int rcuhead_fixup_activate(void *addr, enum debug_obj_state state)
+{
+	struct rcu_head *head = addr;
+
+	switch (state) {
+
+	case ODEBUG_STATE_NOTAVAILABLE:
+		/*
+		 * This is not really a fixup. We just make sure that it is
+		 * tracked in the object tracker.
+		 */
+		debug_object_init(head, &rcuhead_debug_descr);
+		debug_object_activate(head, &rcuhead_debug_descr);
+		return 0;
+
+	case ODEBUG_STATE_ACTIVE:
+		/*
+		 * Ensure that queued callbacks are all executed.
+		 * If we detect that we are nested in a RCU read-side critical
+		 * section, we should simply fail, otherwise we would deadlock.
+		 */
+#ifndef CONFIG_PREEMPT
+		WARN_ON(1);
+		return 0;
+#else
+		if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
+		    irqs_disabled()) {
+			WARN_ON(1);
+			return 0;
+		}
+		rcu_barrier();
+		rcu_barrier_sched();
+		rcu_barrier_bh();
+		debug_object_activate(head, &rcuhead_debug_descr);
+		return 1;
+#endif
+	default:
+		return 0;
+	}
+}
+
+/*
+ * fixup_free is called when:
+ * - an active object is freed
+ */
+static int rcuhead_fixup_free(void *addr, enum debug_obj_state state)
+{
+	struct rcu_head *head = addr;
+
+	switch (state) {
+	case ODEBUG_STATE_ACTIVE:
+		/*
+		 * Ensure that queued callbacks are all executed.
+		 * If we detect that we are nested in a RCU read-side critical
+		 * section, we should simply fail, otherwise we would deadlock.
+		 */
+#ifndef CONFIG_PREEMPT
+		WARN_ON(1);
+		return 0;
+#else
+		if (rcu_preempt_depth() != 0 || preempt_count() != 0 ||
+		    irqs_disabled()) {
+			WARN_ON(1);
+			return 0;
+		}
+		rcu_barrier();
+		rcu_barrier_sched();
+		rcu_barrier_bh();
+		debug_object_free(head, &rcuhead_debug_descr);
+		return 1;
+#endif
+	default:
+		return 0;
+	}
+}
+
+void init_rcu_head_on_stack(struct rcu_head *head)
+{
+	debug_object_init_on_stack(head, &rcuhead_debug_descr);
+}
+EXPORT_SYMBOL_GPL(init_rcu_head_on_stack);
+
+void destroy_rcu_head_on_stack(struct rcu_head *head)
+{
+	debug_object_free(head, &rcuhead_debug_descr);
+}
+EXPORT_SYMBOL_GPL(destroy_rcu_head_on_stack);
+
+struct debug_obj_descr rcuhead_debug_descr = {
+	.name = "rcu_head",
+	.fixup_init = rcuhead_fixup_init,
+	.fixup_activate = rcuhead_fixup_activate,
+	.fixup_free = rcuhead_fixup_free,
+};
+EXPORT_SYMBOL_GPL(rcuhead_debug_descr);
+#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index 38729d3..196ec02 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -169,6 +169,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
 	while (list) {
 		next = list->next;
 		prefetch(next);
+		debug_rcu_head_unqueue(list);
 		list->func(list);
 		list = next;
 	}
@@ -211,6 +212,7 @@ static void __call_rcu(struct rcu_head *head,
 {
 	unsigned long flags;
 
+	debug_rcu_head_queue(head);
 	head->func = func;
 	head->next = NULL;
 
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index d443734..d5bc439 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -1112,6 +1112,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
 	while (list) {
 		next = list->next;
 		prefetch(next);
+		debug_rcu_head_unqueue(list);
 		list->func(list);
 		list = next;
 		if (++count >= rdp->blimit)
@@ -1388,6 +1389,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
 	unsigned long flags;
 	struct rcu_data *rdp;
 
+	debug_rcu_head_queue(head);
 	head->func = func;
 	head->next = NULL;
 
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 930a9e5..8689646 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -307,6 +307,12 @@ config DEBUG_OBJECTS_WORK
 	  work queue routines to track the life time of work objects and
 	  validate the work operations.
 
+config DEBUG_OBJECTS_RCU_HEAD
+	bool "Debug RCU callbacks objects"
+	depends on DEBUG_OBJECTS
+	help
+	  Enable this to turn on debugging of RCU list heads (call_rcu() usage).
+
 config DEBUG_OBJECTS_ENABLE_DEFAULT
 	int "debug_objects bootup default value (0-1)"
         range 0 1
-- 
1.7.0


  parent reply	other threads:[~2010-05-04 20:29 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-05-04 20:19 [PATCH tip/core/rcu 0/48] v4 patches queued for 2.6.35 Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 01/48] rcu: optionally leave lockdep enabled after RCU lockdep splat Paul E. McKenney
2010-05-05 22:46   ` Mathieu Desnoyers
2010-05-05 23:05     ` Paul E. McKenney
2010-05-05 23:24       ` Mathieu Desnoyers
2010-05-05 23:36         ` Paul E. McKenney
2010-05-06  2:05           ` Mathieu Desnoyers
2010-05-06 23:09             ` Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 02/48] rcu: substitute set_need_resched for sending resched IPIs Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 03/48] rcu: make dead code really dead Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 04/48] rcu: move some code from macro to function Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 05/48] rcu: ignore offline CPUs in last non-dyntick-idle CPU check Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 06/48] rcu: Fix bogus CONFIG_PROVE_LOCKING in comments to reflect reality Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 07/48] rcu: fix now-bogus rcu_scheduler_active comments Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 08/48] rcu: shrink rcutiny by making synchronize_rcu_bh() be inline Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 09/48] rcu: rename rcutiny rcu_ctrlblk to rcu_sched_ctrlblk Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 10/48] rcu: refactor RCU's context-switch handling Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 11/48] rcu: slim down rcutiny by removing rcu_scheduler_active and friends Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 12/48] rcu: enable CPU_STALL_VERBOSE by default Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 13/48] rcu: disable CPU stall warnings upon panic Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 14/48] rcu: print boot-time console messages if RCU configs out of ordinary Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 15/48] rcu: improve RCU CPU stall-warning messages Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 16/48] rcu: permit discontiguous cpu_possible_mask CPU numbering Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 17/48] rcu: v2: reduce the number of spurious RCU_SOFTIRQ invocations Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 18/48] rcu: improve the RCU CPU-stall warning documentation Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 19/48] Debugobjects transition check Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 20/48] rcu head introduce rcu head init on stack Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 21/48] remove all rcu head initializations, except on_stack initializations Paul E. McKenney
2010-05-04 20:27   ` Matt Mackall
2010-05-04 20:36     ` Paul E. McKenney
2010-05-04 23:44   ` James Morris
2010-05-05  0:03     ` Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 22/48] rcu head remove init Paul E. McKenney
2010-05-04 20:19 ` Paul E. McKenney [this message]
2010-05-04 20:19 ` [PATCH tip/core/rcu 24/48] rcu: make SRCU usable in modules Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 25/48] rcu: fix debugobjects rcu head init on stack in rcutree_plugin.h Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 26/48] rcu: RCU_FAST_NO_HZ must check RCU dyntick state Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 27/48] vfs: add fs.h to define struct file Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 28/48] net: Make accesses to ->br_port safe for sparse RCU Paul E. McKenney
2010-05-04 21:26   ` Stephen Hemminger
2010-05-04 21:41     ` Arnd Bergmann
2010-05-05 22:03       ` Paul E. McKenney
2010-05-06 14:09         ` Arnd Bergmann
2010-05-06 23:12           ` Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 29/48] rcu: add an rcu_dereference_index_check() Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 30/48] mce: convert to rcu_dereference_index_check() Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 31/48] rcu: define __rcu address space modifier for sparse Paul E. McKenney
2010-05-04 20:58   ` Arnd Bergmann
2010-05-04 23:07     ` Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 32/48] rculist: avoid __rcu annotations Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 33/48] cgroups: " Paul E. McKenney
2010-05-04 20:48   ` Paul Menage
2010-05-05  0:04     ` Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 34/48] credentials: rcu annotation Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 35/48] keys: __rcu annotations Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 36/48] nfs: " Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 37/48] net: __rcu annotations for drivers Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 38/48] perf_event: __rcu annotations Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 39/48] notifiers: " Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 40/48] radix-tree: " Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 41/48] idr: " Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 42/48] input: " Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 43/48] vhost: add " Paul E. McKenney
2010-05-04 21:39   ` Michael S. Tsirkin
2010-05-04 23:57     ` Paul E. McKenney
2010-05-04 23:59       ` Michael S. Tsirkin
2010-05-05  0:39         ` Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 44/48] net/netfilter: " Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 45/48] kvm: add " Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 46/48] kernel: " Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 47/48] net: " Paul E. McKenney
2010-05-04 20:19 ` [PATCH tip/core/rcu 48/48] kvm: more " Paul E. McKenney
2010-05-05 10:14 ` [PATCH tip/core/rcu 36/48] nfs: " David Howells
2010-05-05 12:44   ` Trond Myklebust
2010-05-05 21:01     ` Paul E. McKenney

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1273004398-19760-23-git-send-email-paulmck@linux.vnet.ibm.com \
    --to=paulmck@linux.vnet.ibm.com \
    --cc=Valdis.Kletnieks@vt.edu \
    --cc=adobriyan@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=davem@davemloft.net \
    --cc=dhowells@redhat.com \
    --cc=dipankar@in.ibm.com \
    --cc=dvhltc@us.ibm.com \
    --cc=eric.dumazet@gmail.com \
    --cc=josh@joshtriplett.org \
    --cc=laijs@cn.fujitsu.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mathieu.desnoyers@polymtl.ca \
    --cc=mingo@elte.hu \
    --cc=niv@us.ibm.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®