aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2014-07-29 17:50:47 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2014-09-07 19:18:17 -0400
commit9fdd3bc9005824704f9802bec7b3e06f5edae434 (patch)
tree94433c52525a23ecb250aa155130cdd0753d4404
parent66d701ea7e148f8ed8b1497c9159fbf6175d462f (diff)
rcu: Break more call_rcu() deadlock involving scheduler and perf
Commit 96d3fd0d315a9 (rcu: Break call_rcu() deadlock involving scheduler and perf) covered the case where __call_rcu_nocb_enqueue() needs to wake the rcuo kthread due to the queue being initially empty, but did not do anything for the case where the queue was overflowing. This commit therefore also defers wakeup for the overflow case. Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-rw-r--r--include/trace/events/rcu.h3
-rw-r--r--kernel/rcu/tree.h9
-rw-r--r--kernel/rcu/tree_plugin.h26
3 files changed, 28 insertions, 10 deletions
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
index aca382266411..9b56f37148cf 100644
--- a/include/trace/events/rcu.h
+++ b/include/trace/events/rcu.h
@@ -180,9 +180,12 @@ TRACE_EVENT(rcu_grace_period_init,
180 * argument is a string as follows: 180 * argument is a string as follows:
181 * 181 *
182 * "WakeEmpty": Wake rcuo kthread, first CB to empty list. 182 * "WakeEmpty": Wake rcuo kthread, first CB to empty list.
183 * "WakeEmptyIsDeferred": Wake rcuo kthread later, first CB to empty list.
183 * "WakeOvf": Wake rcuo kthread, CB list is huge. 184 * "WakeOvf": Wake rcuo kthread, CB list is huge.
185 * "WakeOvfIsDeferred": Wake rcuo kthread later, CB list is huge.
184 * "WakeNot": Don't wake rcuo kthread. 186 * "WakeNot": Don't wake rcuo kthread.
185 * "WakeNotPoll": Don't wake rcuo kthread because it is polling. 187 * "WakeNotPoll": Don't wake rcuo kthread because it is polling.
188 * "DeferredWake": Carried out the "IsDeferred" wakeup.
186 * "Poll": Start of new polling cycle for rcu_nocb_poll. 189 * "Poll": Start of new polling cycle for rcu_nocb_poll.
187 * "Sleep": Sleep waiting for CBs for !rcu_nocb_poll. 190 * "Sleep": Sleep waiting for CBs for !rcu_nocb_poll.
188 * "WokeEmpty": rcuo kthread woke to find empty list. 191 * "WokeEmpty": rcuo kthread woke to find empty list.
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index 6a86eb7bac45..e33562f2a655 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -350,7 +350,7 @@ struct rcu_data {
350 int nocb_p_count_lazy; /* (approximate). */ 350 int nocb_p_count_lazy; /* (approximate). */
351 wait_queue_head_t nocb_wq; /* For nocb kthreads to sleep on. */ 351 wait_queue_head_t nocb_wq; /* For nocb kthreads to sleep on. */
352 struct task_struct *nocb_kthread; 352 struct task_struct *nocb_kthread;
353 bool nocb_defer_wakeup; /* Defer wakeup of nocb_kthread. */ 353 int nocb_defer_wakeup; /* Defer wakeup of nocb_kthread. */
354 354
355 /* The following fields are used by the leader, hence own cacheline. */ 355 /* The following fields are used by the leader, hence own cacheline. */
356 struct rcu_head *nocb_gp_head ____cacheline_internodealigned_in_smp; 356 struct rcu_head *nocb_gp_head ____cacheline_internodealigned_in_smp;
@@ -383,6 +383,11 @@ struct rcu_data {
383#define RCU_FORCE_QS 3 /* Need to force quiescent state. */ 383#define RCU_FORCE_QS 3 /* Need to force quiescent state. */
384#define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK 384#define RCU_SIGNAL_INIT RCU_SAVE_DYNTICK
385 385
386/* Values for nocb_defer_wakeup field in struct rcu_data. */
387#define RCU_NOGP_WAKE_NOT 0
388#define RCU_NOGP_WAKE 1
389#define RCU_NOGP_WAKE_FORCE 2
390
386#define RCU_JIFFIES_TILL_FORCE_QS (1 + (HZ > 250) + (HZ > 500)) 391#define RCU_JIFFIES_TILL_FORCE_QS (1 + (HZ > 250) + (HZ > 500))
387 /* For jiffies_till_first_fqs and */ 392 /* For jiffies_till_first_fqs and */
388 /* and jiffies_till_next_fqs. */ 393 /* and jiffies_till_next_fqs. */
@@ -589,7 +594,7 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
589static bool rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp, 594static bool rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
590 struct rcu_data *rdp, 595 struct rcu_data *rdp,
591 unsigned long flags); 596 unsigned long flags);
592static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp); 597static int rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp);
593static void do_nocb_deferred_wakeup(struct rcu_data *rdp); 598static void do_nocb_deferred_wakeup(struct rcu_data *rdp);
594static void rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp); 599static void rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp);
595static void rcu_spawn_nocb_kthreads(struct rcu_state *rsp); 600static void rcu_spawn_nocb_kthreads(struct rcu_state *rsp);
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index bb564560aeb8..d67cc5c375c5 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -2121,16 +2121,23 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp,
2121 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, 2121 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
2122 TPS("WakeEmpty")); 2122 TPS("WakeEmpty"));
2123 } else { 2123 } else {
2124 rdp->nocb_defer_wakeup = true; 2124 rdp->nocb_defer_wakeup = RCU_NOGP_WAKE;
2125 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, 2125 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
2126 TPS("WakeEmptyIsDeferred")); 2126 TPS("WakeEmptyIsDeferred"));
2127 } 2127 }
2128 rdp->qlen_last_fqs_check = 0; 2128 rdp->qlen_last_fqs_check = 0;
2129 } else if (len > rdp->qlen_last_fqs_check + qhimark) { 2129 } else if (len > rdp->qlen_last_fqs_check + qhimark) {
2130 /* ... or if many callbacks queued. */ 2130 /* ... or if many callbacks queued. */
2131 wake_nocb_leader(rdp, true); 2131 if (!irqs_disabled_flags(flags)) {
2132 wake_nocb_leader(rdp, true);
2133 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
2134 TPS("WakeOvf"));
2135 } else {
2136 rdp->nocb_defer_wakeup = RCU_NOGP_WAKE_FORCE;
2137 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
2138 TPS("WakeOvfIsDeferred"));
2139 }
2132 rdp->qlen_last_fqs_check = LONG_MAX / 2; 2140 rdp->qlen_last_fqs_check = LONG_MAX / 2;
2133 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeOvf"));
2134 } else { 2141 } else {
2135 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeNot")); 2142 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeNot"));
2136 } 2143 }
@@ -2438,7 +2445,7 @@ static int rcu_nocb_kthread(void *arg)
2438} 2445}
2439 2446
2440/* Is a deferred wakeup of rcu_nocb_kthread() required? */ 2447/* Is a deferred wakeup of rcu_nocb_kthread() required? */
2441static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp) 2448static int rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp)
2442{ 2449{
2443 return ACCESS_ONCE(rdp->nocb_defer_wakeup); 2450 return ACCESS_ONCE(rdp->nocb_defer_wakeup);
2444} 2451}
@@ -2446,11 +2453,14 @@ static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp)
2446/* Do a deferred wakeup of rcu_nocb_kthread(). */ 2453/* Do a deferred wakeup of rcu_nocb_kthread(). */
2447static void do_nocb_deferred_wakeup(struct rcu_data *rdp) 2454static void do_nocb_deferred_wakeup(struct rcu_data *rdp)
2448{ 2455{
2456 int ndw;
2457
2449 if (!rcu_nocb_need_deferred_wakeup(rdp)) 2458 if (!rcu_nocb_need_deferred_wakeup(rdp))
2450 return; 2459 return;
2451 ACCESS_ONCE(rdp->nocb_defer_wakeup) = false; 2460 ndw = ACCESS_ONCE(rdp->nocb_defer_wakeup);
2452 wake_nocb_leader(rdp, false); 2461 ACCESS_ONCE(rdp->nocb_defer_wakeup) = RCU_NOGP_WAKE_NOT;
2453 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("DeferredWakeEmpty")); 2462 wake_nocb_leader(rdp, ndw == RCU_NOGP_WAKE_FORCE);
2463 trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("DeferredWake"));
2454} 2464}
2455 2465
2456/* Initialize per-rcu_data variables for no-CBs CPUs. */ 2466/* Initialize per-rcu_data variables for no-CBs CPUs. */
@@ -2557,7 +2567,7 @@ static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp)
2557{ 2567{
2558} 2568}
2559 2569
2560static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp) 2570static int rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp)
2561{ 2571{
2562 return false; 2572 return false;
2563} 2573}