[PATCH 1/3] rcu: Detect illegal rcu dereference in extended quiescent state

From: Frederic Weisbecker
Date: Thu Jun 23 2011 - 19:12:58 EST


Report that none of the rcu read lock map are held while we are in
an RCU extended quiescent state. This helps detecting any use of
rcu dereference when we are in dynticks idle mode.

Signed-off-by: Frederic Weisbecker <fweisbec@xxxxxxxxx>
Cc: Paul E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxx>
Cc: Peter Zijlstra <a.p.zijlstra@xxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Cc: Lai Jiangshan <laijs@xxxxxxxxxxxxxx>
---
include/linux/rcupdate.h | 16 ++++++++++++++++
kernel/rcupdate.c | 4 ++++
kernel/rcutiny.c | 13 +++++++++++++
kernel/rcutree.c | 14 ++++++++++++++
4 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 8be0433..713eb6c 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -179,6 +179,14 @@ static inline void destroy_rcu_head_on_stack(struct rcu_head *head)
}
#endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */

+
+#if defined(CONFIG_PROVE_RCU) && defined(CONFIG_NO_HZ)
+extern bool rcu_check_extended_qs(void);
+#else
+static inline bool rcu_check_extended_qs(void) { return false; }
+#endif
+
+
#ifdef CONFIG_DEBUG_LOCK_ALLOC

extern struct lockdep_map rcu_lock_map;
@@ -215,6 +223,10 @@ static inline int rcu_read_lock_held(void)
{
if (!debug_lockdep_rcu_enabled())
return 1;
+
+ if (rcu_check_extended_qs())
+ return 0;
+
return lock_is_held(&rcu_lock_map);
}

@@ -246,6 +258,10 @@ static inline int rcu_read_lock_sched_held(void)

if (!debug_lockdep_rcu_enabled())
return 1;
+
+ if (rcu_check_extended_qs())
+ return 0;
+
if (debug_locks)
lockdep_opinion = lock_is_held(&rcu_sched_lock_map);
return lockdep_opinion || preempt_count() != 0 || irqs_disabled();
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 7784bd2..d883253 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -88,6 +88,10 @@ int rcu_read_lock_bh_held(void)
{
if (!debug_lockdep_rcu_enabled())
return 1;
+
+ if (rcu_check_extended_qs())
+ return 0;
+
return in_softirq() || irqs_disabled();
}
EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held);
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index 7bbac7d..95581f1 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -77,6 +77,19 @@ void rcu_exit_nohz(void)
rcu_dynticks_nesting++;
}

+
+#ifdef CONFIG_PROVE_RCU
+
+bool rcu_check_extended_qs(void)
+{
+ if (!rcu_dynticks_nesting)
+ return true;
+
+ return false;
+}
+
+#endif
+
#endif /* #ifdef CONFIG_NO_HZ */

/*
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 7e59ffb..c397a86 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -438,6 +438,20 @@ void rcu_irq_exit(void)
rcu_enter_nohz();
}

+#ifdef CONFIG_PROVE_RCU
+
+bool rcu_check_extended_qs(void)
+{
+ struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
+
+ if (atomic_read(&rdtp->dynticks) & 0x1)
+ return false;
+
+ return true;
+}
+
+#endif /* CONFIG_PROVE_RCU */
+
#ifdef CONFIG_SMP

/*
--
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/