aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcutree.c
diff options
context:
space:
mode:
authorPaul E. McKenney <paul.mckenney@linaro.org>2012-08-20 00:35:53 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2012-11-16 13:05:56 -0500
commit3fbfbf7a3b66ec424042d909f14ba2ddf4372ea8 (patch)
treecc364c320a6e23927ecc154a8ef8021dc7d1a9e8 /kernel/rcutree.c
parentaac1cda34b84a9411d6b8d18c3658f094c834911 (diff)
rcu: Add callback-free CPUs
RCU callback execution can add significant OS jitter and also can degrade both scheduling latency and, in asymmetric multiprocessors, energy efficiency. This commit therefore adds the ability for selected CPUs ("rcu_nocbs=" boot parameter) to have their callbacks offloaded to kthreads. If the "rcu_nocb_poll" boot parameter is also specified, these kthreads will do polling, removing the need for the offloaded CPUs to do wakeups. At least one CPU must be doing normal callback processing: currently CPU 0 cannot be selected as a no-CBs CPU. In addition, attempts to offline the last normal-CBs CPU will fail. This feature was inspired by Jim Houston's and Joe Korty's JRCU, and this commit includes fixes to problems located by Fengguang Wu's kbuild test robot. [ paulmck: Added gfp.h include file as suggested by Fengguang Wu. ] Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/rcutree.c')
-rw-r--r--kernel/rcutree.c63
1 files changed, 51 insertions, 12 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 5ffadcc3bb26..7733eb56e156 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -303,7 +303,8 @@ EXPORT_SYMBOL_GPL(rcu_sched_force_quiescent_state);
303static int 303static int
304cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp) 304cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp)
305{ 305{
306 return &rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL]; 306 return &rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL] &&
307 rdp->nxttail[RCU_DONE_TAIL] != NULL;
307} 308}
308 309
309/* 310/*
@@ -312,8 +313,11 @@ cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp)
312static int 313static int
313cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp) 314cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
314{ 315{
315 return *rdp->nxttail[RCU_DONE_TAIL + 316 struct rcu_head **ntp;
316 (ACCESS_ONCE(rsp->completed) != rdp->completed)] && 317
318 ntp = rdp->nxttail[RCU_DONE_TAIL +
319 (ACCESS_ONCE(rsp->completed) != rdp->completed)];
320 return rdp->nxttail[RCU_DONE_TAIL] && ntp && *ntp &&
317 !rcu_gp_in_progress(rsp); 321 !rcu_gp_in_progress(rsp);
318} 322}
319 323
@@ -1123,6 +1127,7 @@ static void init_callback_list(struct rcu_data *rdp)
1123 rdp->nxtlist = NULL; 1127 rdp->nxtlist = NULL;
1124 for (i = 0; i < RCU_NEXT_SIZE; i++) 1128 for (i = 0; i < RCU_NEXT_SIZE; i++)
1125 rdp->nxttail[i] = &rdp->nxtlist; 1129 rdp->nxttail[i] = &rdp->nxtlist;
1130 init_nocb_callback_list(rdp);
1126} 1131}
1127 1132
1128/* 1133/*
@@ -1633,6 +1638,10 @@ static void
1633rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp, 1638rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp,
1634 struct rcu_node *rnp, struct rcu_data *rdp) 1639 struct rcu_node *rnp, struct rcu_data *rdp)
1635{ 1640{
1641 /* No-CBs CPUs do not have orphanable callbacks. */
1642 if (is_nocb_cpu(rdp->cpu))
1643 return;
1644
1636 /* 1645 /*
1637 * Orphan the callbacks. First adjust the counts. This is safe 1646 * Orphan the callbacks. First adjust the counts. This is safe
1638 * because _rcu_barrier() excludes CPU-hotplug operations, so it 1647 * because _rcu_barrier() excludes CPU-hotplug operations, so it
@@ -1684,6 +1693,10 @@ static void rcu_adopt_orphan_cbs(struct rcu_state *rsp)
1684 int i; 1693 int i;
1685 struct rcu_data *rdp = __this_cpu_ptr(rsp->rda); 1694 struct rcu_data *rdp = __this_cpu_ptr(rsp->rda);
1686 1695
1696 /* No-CBs CPUs are handled specially. */
1697 if (rcu_nocb_adopt_orphan_cbs(rsp, rdp))
1698 return;
1699
1687 /* Do the accounting first. */ 1700 /* Do the accounting first. */
1688 rdp->qlen_lazy += rsp->qlen_lazy; 1701 rdp->qlen_lazy += rsp->qlen_lazy;
1689 rdp->qlen += rsp->qlen; 1702 rdp->qlen += rsp->qlen;
@@ -2162,9 +2175,15 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp,
2162 } 2175 }
2163} 2176}
2164 2177
2178/*
2179 * Helper function for call_rcu() and friends. The cpu argument will
2180 * normally be -1, indicating "currently running CPU". It may specify
2181 * a CPU only if that CPU is a no-CBs CPU. Currently, only _rcu_barrier()
2182 * is expected to specify a CPU.
2183 */
2165static void 2184static void
2166__call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), 2185__call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
2167 struct rcu_state *rsp, bool lazy) 2186 struct rcu_state *rsp, int cpu, bool lazy)
2168{ 2187{
2169 unsigned long flags; 2188 unsigned long flags;
2170 struct rcu_data *rdp; 2189 struct rcu_data *rdp;
@@ -2184,9 +2203,14 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
2184 rdp = this_cpu_ptr(rsp->rda); 2203 rdp = this_cpu_ptr(rsp->rda);
2185 2204
2186 /* Add the callback to our list. */ 2205 /* Add the callback to our list. */
2187 if (unlikely(rdp->nxttail[RCU_NEXT_TAIL] == NULL)) { 2206 if (unlikely(rdp->nxttail[RCU_NEXT_TAIL] == NULL) || cpu != -1) {
2207 int offline;
2208
2209 if (cpu != -1)
2210 rdp = per_cpu_ptr(rsp->rda, cpu);
2211 offline = !__call_rcu_nocb(rdp, head, lazy);
2212 WARN_ON_ONCE(offline);
2188 /* _call_rcu() is illegal on offline CPU; leak the callback. */ 2213 /* _call_rcu() is illegal on offline CPU; leak the callback. */
2189 WARN_ON_ONCE(1);
2190 local_irq_restore(flags); 2214 local_irq_restore(flags);
2191 return; 2215 return;
2192 } 2216 }
@@ -2215,7 +2239,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
2215 */ 2239 */
2216void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) 2240void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
2217{ 2241{
2218 __call_rcu(head, func, &rcu_sched_state, 0); 2242 __call_rcu(head, func, &rcu_sched_state, -1, 0);
2219} 2243}
2220EXPORT_SYMBOL_GPL(call_rcu_sched); 2244EXPORT_SYMBOL_GPL(call_rcu_sched);
2221 2245
@@ -2224,7 +2248,7 @@ EXPORT_SYMBOL_GPL(call_rcu_sched);
2224 */ 2248 */
2225void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) 2249void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
2226{ 2250{
2227 __call_rcu(head, func, &rcu_bh_state, 0); 2251 __call_rcu(head, func, &rcu_bh_state, -1, 0);
2228} 2252}
2229EXPORT_SYMBOL_GPL(call_rcu_bh); 2253EXPORT_SYMBOL_GPL(call_rcu_bh);
2230 2254
@@ -2676,9 +2700,17 @@ static void _rcu_barrier(struct rcu_state *rsp)
2676 * When that callback is invoked, we will know that all of the 2700 * When that callback is invoked, we will know that all of the
2677 * corresponding CPU's preceding callbacks have been invoked. 2701 * corresponding CPU's preceding callbacks have been invoked.
2678 */ 2702 */
2679 for_each_online_cpu(cpu) { 2703 for_each_possible_cpu(cpu) {
2704 if (!cpu_online(cpu) && !is_nocb_cpu(cpu))
2705 continue;
2680 rdp = per_cpu_ptr(rsp->rda, cpu); 2706 rdp = per_cpu_ptr(rsp->rda, cpu);
2681 if (ACCESS_ONCE(rdp->qlen)) { 2707 if (is_nocb_cpu(cpu)) {
2708 _rcu_barrier_trace(rsp, "OnlineNoCB", cpu,
2709 rsp->n_barrier_done);
2710 atomic_inc(&rsp->barrier_cpu_count);
2711 __call_rcu(&rdp->barrier_head, rcu_barrier_callback,
2712 rsp, cpu, 0);
2713 } else if (ACCESS_ONCE(rdp->qlen)) {
2682 _rcu_barrier_trace(rsp, "OnlineQ", cpu, 2714 _rcu_barrier_trace(rsp, "OnlineQ", cpu,
2683 rsp->n_barrier_done); 2715 rsp->n_barrier_done);
2684 smp_call_function_single(cpu, rcu_barrier_func, rsp, 1); 2716 smp_call_function_single(cpu, rcu_barrier_func, rsp, 1);
@@ -2752,6 +2784,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
2752#endif 2784#endif
2753 rdp->cpu = cpu; 2785 rdp->cpu = cpu;
2754 rdp->rsp = rsp; 2786 rdp->rsp = rsp;
2787 rcu_boot_init_nocb_percpu_data(rdp);
2755 raw_spin_unlock_irqrestore(&rnp->lock, flags); 2788 raw_spin_unlock_irqrestore(&rnp->lock, flags);
2756} 2789}
2757 2790
@@ -2833,6 +2866,7 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
2833 struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu); 2866 struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
2834 struct rcu_node *rnp = rdp->mynode; 2867 struct rcu_node *rnp = rdp->mynode;
2835 struct rcu_state *rsp; 2868 struct rcu_state *rsp;
2869 int ret = NOTIFY_OK;
2836 2870
2837 trace_rcu_utilization("Start CPU hotplug"); 2871 trace_rcu_utilization("Start CPU hotplug");
2838 switch (action) { 2872 switch (action) {
@@ -2846,7 +2880,10 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
2846 rcu_boost_kthread_setaffinity(rnp, -1); 2880 rcu_boost_kthread_setaffinity(rnp, -1);
2847 break; 2881 break;
2848 case CPU_DOWN_PREPARE: 2882 case CPU_DOWN_PREPARE:
2849 rcu_boost_kthread_setaffinity(rnp, cpu); 2883 if (nocb_cpu_expendable(cpu))
2884 rcu_boost_kthread_setaffinity(rnp, cpu);
2885 else
2886 ret = NOTIFY_BAD;
2850 break; 2887 break;
2851 case CPU_DYING: 2888 case CPU_DYING:
2852 case CPU_DYING_FROZEN: 2889 case CPU_DYING_FROZEN:
@@ -2870,7 +2907,7 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
2870 break; 2907 break;
2871 } 2908 }
2872 trace_rcu_utilization("End CPU hotplug"); 2909 trace_rcu_utilization("End CPU hotplug");
2873 return NOTIFY_OK; 2910 return ret;
2874} 2911}
2875 2912
2876/* 2913/*
@@ -2890,6 +2927,7 @@ static int __init rcu_spawn_gp_kthread(void)
2890 raw_spin_lock_irqsave(&rnp->lock, flags); 2927 raw_spin_lock_irqsave(&rnp->lock, flags);
2891 rsp->gp_kthread = t; 2928 rsp->gp_kthread = t;
2892 raw_spin_unlock_irqrestore(&rnp->lock, flags); 2929 raw_spin_unlock_irqrestore(&rnp->lock, flags);
2930 rcu_spawn_nocb_kthreads(rsp);
2893 } 2931 }
2894 return 0; 2932 return 0;
2895} 2933}
@@ -3085,6 +3123,7 @@ void __init rcu_init(void)
3085 rcu_init_one(&rcu_sched_state, &rcu_sched_data); 3123 rcu_init_one(&rcu_sched_state, &rcu_sched_data);
3086 rcu_init_one(&rcu_bh_state, &rcu_bh_data); 3124 rcu_init_one(&rcu_bh_state, &rcu_bh_data);
3087 __rcu_init_preempt(); 3125 __rcu_init_preempt();
3126 rcu_init_nocb();
3088 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); 3127 open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
3089 3128
3090 /* 3129 /*