All of lore.kernel.org
 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, 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, fweisbec@gmail.com,
	patches@linaro.org, "Paul E. McKenney" <paul.mckenney@linaro.org>,
	"Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Subject: [PATCH RFC tip/core/rcu 18/41] rcu: Protect __rcu_read_unlock() against scheduler-using irq handlers
Date: Wed,  1 Feb 2012 11:41:36 -0800	[thread overview]
Message-ID: <1328125319-5205-18-git-send-email-paulmck@linux.vnet.ibm.com> (raw)
In-Reply-To: <1328125319-5205-1-git-send-email-paulmck@linux.vnet.ibm.com>

From: "Paul E. McKenney" <paul.mckenney@linaro.org>

This commit ports commit #10f39bb1b2 (rcu: protect __rcu_read_unlock()
against scheduler-using irq handlers) from TREE_PREEMPT_RCU to
TINY_PREEMPT_RCU.  The following is a corresponding port of that
commit message.

The addition of RCU read-side critical sections within runqueue and
priority-inheritance critical sections introduced some deadlocks,
for example, involving interrupts from __rcu_read_unlock() where the
interrupt handlers call wake_up().  This situation can cause the
instance of __rcu_read_unlock() invoked from interrupt to do some
of the processing that would otherwise have been carried out by the
task-level instance of __rcu_read_unlock().  When the interrupt-level
instance of __rcu_read_unlock() is called with a scheduler lock held from
interrupt-entry/exit situations where in_irq() returns false, deadlock can
result.  Of course, in a UP kernel, there are not really any deadlocks,
but the upper-level critical section can still be be fatally confused
by the lower-level critical section changing things out from under it.

This commit resolves these deadlocks by using negative values of the
per-task ->rcu_read_lock_nesting counter to indicate that an instance of
__rcu_read_unlock() is in flight, which in turn prevents instances from
interrupt handlers from doing any special processing.  Note that nested
rcu_read_lock()/rcu_read_unlock() pairs are still permitted, but they will
never see ->rcu_read_lock_nesting go to zero, and will therefore never
invoke rcu_read_unlock_special(), thus preventing them from seeing the
RCU_READ_UNLOCK_BLOCKED bit should it be set in ->rcu_read_unlock_special.
This patch also adds a check for ->rcu_read_unlock_special being negative
in rcu_check_callbacks(), thus preventing the RCU_READ_UNLOCK_NEED_QS
bit from being set should a scheduling-clock interrupt occur while
__rcu_read_unlock() is exiting from an outermost RCU read-side critical
section.

Of course, __rcu_read_unlock() can be preempted during the time that
->rcu_read_lock_nesting is negative.  This could result in the setting
of the RCU_READ_UNLOCK_BLOCKED bit after __rcu_read_unlock() checks it,
and would also result it this task being queued on the corresponding
rcu_node structure's blkd_tasks list.  Therefore, some later RCU read-side
critical section would enter rcu_read_unlock_special() to clean up --
which could result in deadlock (OK, OK, fatal confusion) if that RCU
read-side critical section happened to be in the scheduler where the
runqueue or priority-inheritance locks were held.

To prevent the possibility of fatal confusion that might result from
preemption during the time that ->rcu_read_lock_nesting is negative,
this commit also makes rcu_preempt_note_context_switch() check for
negative ->rcu_read_lock_nesting, thus refraining from queuing the task
(and from setting RCU_READ_UNLOCK_BLOCKED) if we are already exiting
from the outermost RCU read-side critical section (in other words,
we really are no longer actually in that RCU read-side critical
section).  In addition, rcu_preempt_note_context_switch() invokes
rcu_read_unlock_special() to carry out the cleanup in this case, which
clears out the ->rcu_read_unlock_special bits and dequeues the task
(if necessary), in turn avoiding needless delay of the current RCU grace
period and needless RCU priority boosting.

It is still illegal to call rcu_read_unlock() while holding a scheduler
lock if the prior RCU read-side critical section has ever had both
preemption and irqs enabled.  However, the common use case is legal,
namely where then entire RCU read-side critical section executes with
irqs disabled, for example, when the scheduler lock is held across the
entire lifetime of the RCU read-side critical section.

Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---
 kernel/rcutiny_plugin.h |   43 +++++++++++++++++++++++++++++++++++--------
 1 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/kernel/rcutiny_plugin.h b/kernel/rcutiny_plugin.h
index dd672e7..6cba20b 100644
--- a/kernel/rcutiny_plugin.h
+++ b/kernel/rcutiny_plugin.h
@@ -132,6 +132,7 @@ static struct rcu_preempt_ctrlblk rcu_preempt_ctrlblk = {
 	RCU_TRACE(.rcb.name = "rcu_preempt")
 };
 
+static void rcu_read_unlock_special(struct task_struct *t);
 static int rcu_preempted_readers_exp(void);
 static void rcu_report_exp_done(void);
 
@@ -146,6 +147,16 @@ static int rcu_cpu_blocking_cur_gp(void)
 /*
  * Check for a running RCU reader.  Because there is only one CPU,
  * there can be but one running RCU reader at a time.  ;-)
+ *
+ * Returns zero if there are no running readers.  Returns a positive
+ * number if there is at least one reader within its RCU read-side
+ * critical section.  Returns a negative number if an outermost reader
+ * is in the midst of exiting from its RCU read-side critical section
+ *
+ * Returns zero if there are no running readers.  Returns a positive
+ * number if there is at least one reader within its RCU read-side
+ * critical section.  Returns a negative number if an outermost reader
+ * is in the midst of exiting from its RCU read-side critical section.
  */
 static int rcu_preempt_running_reader(void)
 {
@@ -475,7 +486,7 @@ void rcu_preempt_note_context_switch(void)
 	unsigned long flags;
 
 	local_irq_save(flags); /* must exclude scheduler_tick(). */
-	if (rcu_preempt_running_reader() &&
+	if (rcu_preempt_running_reader() > 0 &&
 	    (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) {
 
 		/* Possibly blocking in an RCU read-side critical section. */
@@ -494,6 +505,13 @@ void rcu_preempt_note_context_switch(void)
 		list_add(&t->rcu_node_entry, &rcu_preempt_ctrlblk.blkd_tasks);
 		if (rcu_cpu_blocking_cur_gp())
 			rcu_preempt_ctrlblk.gp_tasks = &t->rcu_node_entry;
+	} else if (rcu_preempt_running_reader() < 0 &&
+		   t->rcu_read_unlock_special) {
+		/*
+		 * Complete exit from RCU read-side critical section on
+		 * behalf of preempted instance of __rcu_read_unlock().
+		 */
+		rcu_read_unlock_special(t);
 	}
 
 	/*
@@ -618,13 +636,22 @@ void __rcu_read_unlock(void)
 	struct task_struct *t = current;
 
 	barrier();  /* needed if we ever invoke rcu_read_unlock in rcutiny.c */
-	--t->rcu_read_lock_nesting;
-	barrier();  /* decrement before load of ->rcu_read_unlock_special */
-	if (t->rcu_read_lock_nesting == 0 &&
-	    unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
-		rcu_read_unlock_special(t);
+	if (t->rcu_read_lock_nesting != 1)
+		--t->rcu_read_lock_nesting;
+	else {
+		t->rcu_read_lock_nesting = INT_MIN;
+		barrier();  /* assign before ->rcu_read_unlock_special load */
+		if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
+			rcu_read_unlock_special(t);
+		barrier();  /* ->rcu_read_unlock_special load before assign */
+		t->rcu_read_lock_nesting = 0;
+	}
 #ifdef CONFIG_PROVE_LOCKING
-	WARN_ON_ONCE(t->rcu_read_lock_nesting < 0);
+	{
+		int rrln = ACCESS_ONCE(t->rcu_read_lock_nesting);
+
+		WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2);
+	}
 #endif /* #ifdef CONFIG_PROVE_LOCKING */
 }
 EXPORT_SYMBOL_GPL(__rcu_read_unlock);
@@ -649,7 +676,7 @@ static void rcu_preempt_check_callbacks(void)
 		invoke_rcu_callbacks();
 	if (rcu_preempt_gp_in_progress() &&
 	    rcu_cpu_blocking_cur_gp() &&
-	    rcu_preempt_running_reader())
+	    rcu_preempt_running_reader() > 0)
 		t->rcu_read_unlock_special |= RCU_READ_UNLOCK_NEED_QS;
 }
 
-- 
1.7.8


  parent reply	other threads:[~2012-02-01 19:54 UTC|newest]

Thread overview: 104+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-02-01 19:41 [PATCH RFC 0/41] RCU commits for 3.4 Paul E. McKenney
2012-02-01 19:41 ` [PATCH RFC tip/core/rcu 01/41] rcu: Bring RTFP.txt up to date Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 02/41] rcu: Improve synchronize_rcu() diagnostics Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 03/41] rcu: Add lockdep-RCU checks for simple self-deadlock Paul E. McKenney
2012-02-02  0:55     ` Josh Triplett
2012-02-02 16:20       ` Paul E. McKenney
2012-02-02 19:56         ` Josh Triplett
2012-02-02 20:42           ` Paul E. McKenney
2012-02-03  9:04             ` Josh Triplett
2012-02-03 18:05               ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 04/41] rcu: Add diagnostic for misaligned rcu_head structures Paul E. McKenney
2012-02-02  1:00     ` Josh Triplett
2012-02-02 16:22       ` Paul E. McKenney
2012-02-02 20:11         ` Josh Triplett
2012-02-02  1:01     ` Josh Triplett
2012-02-02 16:27       ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 05/41] rcu: Avoid waking up CPUs having only kfree_rcu() callbacks Paul E. McKenney
2012-02-02  1:15     ` Josh Triplett
2012-02-02 16:34       ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 06/41] rcu: Move RCU_TRACE to lib/Kconfig.debug Paul E. McKenney
2012-02-02  1:39     ` Josh Triplett
2012-02-02 17:05       ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 07/41] s390: Convert call_rcu() to kfree_rcu() Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 08/41] tcm_fc: " Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 09/41] ipv4: " Paul E. McKenney
2012-02-01 19:49     ` David Miller
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 10/41] " Paul E. McKenney
2012-02-01 19:50     ` David Miller
2012-02-02  0:24     ` Josh Triplett
2012-02-02 15:56       ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 11/41] mac80211: " Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 12/41] rcu: Simplify offline processing Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 13/41] rcu: Make rcutorture flag online/offline failures Paul E. McKenney
2012-02-02  1:46     ` Josh Triplett
2012-02-02 17:08       ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 14/41] rcu: Limit lazy-callback duration Paul E. McKenney
2012-02-02  2:03     ` Josh Triplett
2012-02-02 17:13       ` Paul E. McKenney
2012-02-03  4:07         ` Josh Triplett
2012-02-03  5:54           ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 15/41] rcu: Check for callback invocation from offline CPUs Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 16/41] rcu: Don't make callbacks go through second full grace period Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 17/41] rcu: Remove single-rcu_node optimization in rcu_start_gp() Paul E. McKenney
2012-02-02  2:13     ` Josh Triplett
2012-02-02 17:16       ` Paul E. McKenney
2012-02-01 19:41   ` Paul E. McKenney [this message]
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 19/41] rcu: Streamline code produced by __rcu_read_unlock() Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 20/41] rcu: Prevent RCU callbacks from executing before scheduler initialized Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 21/41] rcu: Inform RCU of irq_exit() activity Paul E. McKenney
2012-02-02  2:30     ` Josh Triplett
2012-02-02 17:30       ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 22/41] rcu: Simplify unboosting checks Paul E. McKenney
2012-02-02  2:38     ` Josh Triplett
2012-02-02 17:48       ` Paul E. McKenney
2012-02-03  4:23         ` Josh Triplett
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 23/41] rcu: Clean up straggling rcu_preempt_needs_cpu() name Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 24/41] rcu: Check for idle-loop entry while in RCU read-side critical section Paul E. McKenney
2012-02-02  5:13     ` Josh Triplett
2012-02-02 17:50       ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 25/41] rcu: Make rcu_sleep_check() also check rcu_lock_map Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 26/41] rcu: Note that rcu_access_pointer() can be used for teardown Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 27/41] rcu: Remove #ifdef CONFIG_SMP from TREE_RCU Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 28/41] rcu: Set RCU CPU stall times via sysfs Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 29/41] rcu: Print scheduling-clock information on RCU CPU stall-warning messages Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 30/41] rcutorture: Permit holding off CPU-hotplug operations during boot Paul E. McKenney
2012-02-02  5:43     ` Josh Triplett
2012-02-02 17:56       ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 31/41] rcu: Add CPU-stall capability to rcutorture Paul E. McKenney
2012-02-02  5:53     ` Josh Triplett
2012-02-02  9:15       ` Julia Lawall
2012-02-02 18:03         ` Paul E. McKenney
2012-02-02 18:00       ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 32/41] rcu: Update stall-warning documentation Paul E. McKenney
2012-02-02  5:56     ` Josh Triplett
2012-02-02 18:18       ` Paul E. McKenney
2012-02-03  5:42         ` Josh Triplett
2012-02-03  5:58           ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 33/41] rcu: Make boolean rcutorture parameters be of type "bool" Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 34/41] rcu: Check for illegal use of RCU from offlined CPUs Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 35/41] rcu: Move synchronize_sched_expedited() to rcutree.c Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 36/41] rcu: No interrupt disabling for rcu_prepare_for_idle() Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 37/41] lockdep: Add CPU-idle/offline warning to lockdep-RCU splat Paul E. McKenney
2012-02-02  6:07     ` Josh Triplett
2012-02-02 18:30       ` Paul E. McKenney
2012-02-03  6:12         ` Josh Triplett
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 38/41] rcu: Rework detection of use of RCU by offline CPUs Paul E. McKenney
2012-02-02  6:11     ` Josh Triplett
2012-02-02 18:31       ` Paul E. McKenney
2012-02-03  9:17         ` Josh Triplett
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 39/41] rcu: Wait at least a jiffy before declaring a CPU to be offline Paul E. McKenney
2012-02-02  6:12     ` Josh Triplett
2012-02-02 18:27       ` Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 40/41] rcu: Call out dangers of expedited RCU primitives Paul E. McKenney
2012-02-01 19:41   ` [PATCH RFC tip/core/rcu 41/41] rcu: Trace only after NULL-pointer check Paul E. McKenney
2012-02-02  0:18   ` [PATCH RFC tip/core/rcu 01/41] rcu: Bring RTFP.txt up to date Josh Triplett
2012-02-02  1:33     ` Paul E. McKenney
2012-02-02  2:01       ` Josh Triplett
2012-02-02 16:47         ` Paul E. McKenney
2012-02-02 22:32           ` Josh Triplett
2012-02-03 18:00             ` Paul E. McKenney
2012-02-02 22:47 ` [PATCH RFC 0/41] RCU commits for 3.4 Kevin Hilman
2012-02-02 23:58   ` Paul E. McKenney
2012-02-03 19:54     ` Kevin Hilman
2012-02-06  7:04       ` 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=1328125319-5205-18-git-send-email-paulmck@linux.vnet.ibm.com \
    --to=paulmck@linux.vnet.ibm.com \
    --cc=Valdis.Kletnieks@vt.edu \
    --cc=akpm@linux-foundation.org \
    --cc=darren@dvhart.com \
    --cc=dhowells@redhat.com \
    --cc=dipankar@in.ibm.com \
    --cc=eric.dumazet@gmail.com \
    --cc=fweisbec@gmail.com \
    --cc=josh@joshtriplett.org \
    --cc=laijs@cn.fujitsu.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mathieu.desnoyers@polymtl.ca \
    --cc=mingo@elte.hu \
    --cc=niv@us.ibm.com \
    --cc=patches@linaro.org \
    --cc=paul.mckenney@linaro.org \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.