From patchwork Fri Jul 8 15:43:48 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Paul E. McKenney" X-Patchwork-Id: 2603 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 5ABF523F41 for ; Fri, 8 Jul 2011 15:44:10 +0000 (UTC) Received: from mail-qw0-f52.google.com (mail-qw0-f52.google.com [209.85.216.52]) by fiordland.canonical.com (Postfix) with ESMTP id 13E3EA187A6 for ; Fri, 8 Jul 2011 15:44:09 +0000 (UTC) Received: by mail-qw0-f52.google.com with SMTP id 8so1421555qwb.11 for ; Fri, 08 Jul 2011 08:44:09 -0700 (PDT) Received: by 10.229.1.140 with SMTP id 12mr1694998qcf.118.1310139849643; Fri, 08 Jul 2011 08:44:09 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.229.48.135 with SMTP id r7cs139258qcf; Fri, 8 Jul 2011 08:44:09 -0700 (PDT) Received: by 10.52.99.163 with SMTP id er3mr3108497vdb.86.1310139849153; Fri, 08 Jul 2011 08:44:09 -0700 (PDT) Received: from e4.ny.us.ibm.com (e4.ny.us.ibm.com [32.97.182.144]) by mx.google.com with ESMTPS id p9si12855763vdg.36.2011.07.08.08.44.08 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 08 Jul 2011 08:44:09 -0700 (PDT) Received-SPF: pass (google.com: domain of paulmck@linux.vnet.ibm.com designates 32.97.182.144 as permitted sender) client-ip=32.97.182.144; Authentication-Results: mx.google.com; spf=pass (google.com: domain of paulmck@linux.vnet.ibm.com designates 32.97.182.144 as permitted sender) smtp.mail=paulmck@linux.vnet.ibm.com Received: from d01relay03.pok.ibm.com (d01relay03.pok.ibm.com [9.56.227.235]) by e4.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p68FM4is012729 for ; Fri, 8 Jul 2011 11:22:04 -0400 Received: from d01av01.pok.ibm.com (d01av01.pok.ibm.com [9.56.224.215]) by d01relay03.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p68Fi8GR173700 for ; Fri, 8 Jul 2011 11:44:08 -0400 Received: from d01av01.pok.ibm.com (loopback [127.0.0.1]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p68Fi3B0028081 for ; Fri, 8 Jul 2011 11:44:08 -0400 Received: from paulmck-ThinkPad-W500 (sig-9-65-152-173.mts.ibm.com [9.65.152.173]) by d01av01.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p68Fi1n0027877; Fri, 8 Jul 2011 11:44:01 -0400 Received: by paulmck-ThinkPad-W500 (Postfix, from userid 1000) id AE6B413F803; Fri, 8 Jul 2011 08:43:54 -0700 (PDT) From: "Paul E. McKenney" 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, niv@us.ibm.com, tglx@linutronix.de, peterz@infradead.org, rostedt@goodmis.org, Valdis.Kletnieks@vt.edu, dhowells@redhat.com, eric.dumazet@gmail.com, darren@dvhart.com, patches@linaro.org, Frederic Weisbecker , "Paul E. McKenney" , Peter Zijlstra Subject: [PATCH RFC tip/core/rcu 1/6] rcu: Detect illegal rcu dereference in extended quiescent state Date: Fri, 8 Jul 2011 08:43:48 -0700 Message-Id: <1310139833-20804-1-git-send-email-paulmck@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.3.2 In-Reply-To: <20110708154331.GA20161@linux.vnet.ibm.com> References: <20110708154331.GA20161@linux.vnet.ibm.com> From: Frederic Weisbecker Report that none of the rcu read lock maps are held while in an RCU extended quiescent state (in this case, the RCU extended quiescent state is dyntick-idle mode). This helps detect any use of rcu_dereference() and friends from within dyntick-idle mode. Signed-off-by: Frederic Weisbecker Cc: Paul E. McKenney Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Lai Jiangshan Signed-off-by: Paul E. McKenney --- include/linux/rcupdate.h | 36 ++++++++++++++++++++++++++++++++++++ kernel/rcupdate.c | 17 ++++++++++++++++- kernel/rcutiny.c | 14 ++++++++++++++ kernel/rcutree.c | 16 ++++++++++++++++ 4 files changed, 82 insertions(+), 1 deletions(-) diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 99f9aa7..0a33075 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; @@ -210,11 +218,25 @@ extern int debug_lockdep_rcu_enabled(void); * * Checks debug_lockdep_rcu_enabled() to prevent false positives during boot * and while lockdep is disabled. + * + * Note that if the CPU is in an extended quiescent state, for example, + * if the CPU is in dyntick-idle mode, then rcu_read_lock_held() returns + * false even if the CPU did an rcu_read_lock(). The reason for this is + * that RCU ignores CPUs that are in extended quiescent states, so such + * a CPU is effectively never in an RCU read-side critical section + * regardless of what RCU primitives it invokes. This state of affairs + * is required -- RCU would otherwise need to periodically wake up + * dyntick-idle CPUs, which would defeat the whole purpose of dyntick-idle + * mode. */ 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); } @@ -238,6 +260,16 @@ extern int rcu_read_lock_bh_held(void); * * Check debug_lockdep_rcu_enabled() to prevent false positives during boot * and while lockdep is disabled. + * + * Note that if the CPU is in an extended quiescent state, for example, + * if the CPU is in dyntick-idle mode, then rcu_read_lock_held() returns + * false even if the CPU did an rcu_read_lock(). The reason for this is + * that RCU ignores CPUs that are in extended quiescent states, so such + * a CPU is effectively never in an RCU read-side critical section + * regardless of what RCU primitives it invokes. This state of affairs + * is required -- RCU would otherwise need to periodically wake up + * dyntick-idle CPUs, which would defeat the whole purpose of dyntick-idle + * mode. */ #ifdef CONFIG_PREEMPT static inline int rcu_read_lock_sched_held(void) @@ -246,6 +278,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..a0e7e59 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -82,12 +82,27 @@ EXPORT_SYMBOL_GPL(debug_lockdep_rcu_enabled); * that require that they be called within an RCU read-side critical * section. * - * Check debug_lockdep_rcu_enabled() to prevent false positives during boot. + * Check debug_lockdep_rcu_enabled() to prevent false positives during boot + * and while lockdep is disabled. + * + * Note that if the CPU is in an extended quiescent state, for example, + * if the CPU is in dyntick-idle mode, then rcu_read_lock_held() returns + * false even if the CPU did an rcu_read_lock(). The reason for this is + * that RCU ignores CPUs that are in extended quiescent states, so such + * a CPU is effectively never in an RCU read-side critical section + * regardless of what RCU primitives it invokes. This state of affairs + * is required -- RCU would otherwise need to periodically wake up + * dyntick-idle CPUs, which would defeat the whole purpose of dyntick-idle + * mode. */ 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..d01d390 100644 --- a/kernel/rcutiny.c +++ b/kernel/rcutiny.c @@ -77,6 +77,20 @@ 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; +} +EXPORT_SYMBOL_GPL(rcu_check_extended_qs); + +#endif + #endif /* #ifdef CONFIG_NO_HZ */ /* diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 7e59ffb..485cdc9 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -438,6 +438,22 @@ void rcu_irq_exit(void) rcu_enter_nohz(); } +#ifdef CONFIG_PROVE_RCU + +bool rcu_check_extended_qs(void) +{ + struct rcu_dynticks *rdtp; + + rdtp = &per_cpu(rcu_dynticks, raw_smp_processor_id()); + if (atomic_read(&rdtp->dynticks) & 0x1) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(rcu_check_extended_qs); + +#endif /* CONFIG_PROVE_RCU */ + #ifdef CONFIG_SMP /*