aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2013-04-21 05:04:42 -0400
committerIngo Molnar <mingo@kernel.org>2013-04-21 05:04:42 -0400
commit2727872dfe5d273f313f8a0c0dd0fcc58e96cde7 (patch)
tree069ceb12d981f33d997afd214c2082a6685a2fd0 /kernel
parent65d798f0f9339ae2c4ebe9480e3260b33382a584 (diff)
parentf98823ac758ba1aa77c6e3f8ad4ef3ad84ee0a7c (diff)
Merge branch 'timers/nohz-reviewed' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/linux-dynticks into timers/nohz
Pull full dynticks timekeeping and RCU improvements from Frederic Weisbecker. Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/rcutree.c6
-rw-r--r--kernel/rcutree.h1
-rw-r--r--kernel/rcutree_plugin.h13
-rw-r--r--kernel/time/Kconfig10
-rw-r--r--kernel/time/tick-sched.c77
5 files changed, 58 insertions, 49 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index f5ab50235cba..1d4ceff793a4 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -1695,7 +1695,7 @@ rcu_send_cbs_to_orphanage(int cpu, struct rcu_state *rsp,
1695 struct rcu_node *rnp, struct rcu_data *rdp) 1695 struct rcu_node *rnp, struct rcu_data *rdp)
1696{ 1696{
1697 /* No-CBs CPUs do not have orphanable callbacks. */ 1697 /* No-CBs CPUs do not have orphanable callbacks. */
1698 if (is_nocb_cpu(rdp->cpu)) 1698 if (rcu_is_nocb_cpu(rdp->cpu))
1699 return; 1699 return;
1700 1700
1701 /* 1701 /*
@@ -2757,10 +2757,10 @@ static void _rcu_barrier(struct rcu_state *rsp)
2757 * corresponding CPU's preceding callbacks have been invoked. 2757 * corresponding CPU's preceding callbacks have been invoked.
2758 */ 2758 */
2759 for_each_possible_cpu(cpu) { 2759 for_each_possible_cpu(cpu) {
2760 if (!cpu_online(cpu) && !is_nocb_cpu(cpu)) 2760 if (!cpu_online(cpu) && !rcu_is_nocb_cpu(cpu))
2761 continue; 2761 continue;
2762 rdp = per_cpu_ptr(rsp->rda, cpu); 2762 rdp = per_cpu_ptr(rsp->rda, cpu);
2763 if (is_nocb_cpu(cpu)) { 2763 if (rcu_is_nocb_cpu(cpu)) {
2764 _rcu_barrier_trace(rsp, "OnlineNoCB", cpu, 2764 _rcu_barrier_trace(rsp, "OnlineNoCB", cpu,
2765 rsp->n_barrier_done); 2765 rsp->n_barrier_done);
2766 atomic_inc(&rsp->barrier_cpu_count); 2766 atomic_inc(&rsp->barrier_cpu_count);
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index f993c0ac47db..38acc49da2c6 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -529,7 +529,6 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu);
529static void print_cpu_stall_info_end(void); 529static void print_cpu_stall_info_end(void);
530static void zero_cpu_stall_ticks(struct rcu_data *rdp); 530static void zero_cpu_stall_ticks(struct rcu_data *rdp);
531static void increment_cpu_stall_ticks(void); 531static void increment_cpu_stall_ticks(void);
532static bool is_nocb_cpu(int cpu);
533static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, 532static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
534 bool lazy); 533 bool lazy);
535static bool rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp, 534static bool rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index a5745e9b5d5a..0cd91cc18db4 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -2167,7 +2167,7 @@ static int __init parse_rcu_nocb_poll(char *arg)
2167early_param("rcu_nocb_poll", parse_rcu_nocb_poll); 2167early_param("rcu_nocb_poll", parse_rcu_nocb_poll);
2168 2168
2169/* Is the specified CPU a no-CPUs CPU? */ 2169/* Is the specified CPU a no-CPUs CPU? */
2170static bool is_nocb_cpu(int cpu) 2170bool rcu_is_nocb_cpu(int cpu)
2171{ 2171{
2172 if (have_rcu_nocb_mask) 2172 if (have_rcu_nocb_mask)
2173 return cpumask_test_cpu(cpu, rcu_nocb_mask); 2173 return cpumask_test_cpu(cpu, rcu_nocb_mask);
@@ -2225,7 +2225,7 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
2225 bool lazy) 2225 bool lazy)
2226{ 2226{
2227 2227
2228 if (!is_nocb_cpu(rdp->cpu)) 2228 if (!rcu_is_nocb_cpu(rdp->cpu))
2229 return 0; 2229 return 0;
2230 __call_rcu_nocb_enqueue(rdp, rhp, &rhp->next, 1, lazy); 2230 __call_rcu_nocb_enqueue(rdp, rhp, &rhp->next, 1, lazy);
2231 return 1; 2231 return 1;
@@ -2242,7 +2242,7 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
2242 long qll = rsp->qlen_lazy; 2242 long qll = rsp->qlen_lazy;
2243 2243
2244 /* If this is not a no-CBs CPU, tell the caller to do it the old way. */ 2244 /* If this is not a no-CBs CPU, tell the caller to do it the old way. */
2245 if (!is_nocb_cpu(smp_processor_id())) 2245 if (!rcu_is_nocb_cpu(smp_processor_id()))
2246 return 0; 2246 return 0;
2247 rsp->qlen = 0; 2247 rsp->qlen = 0;
2248 rsp->qlen_lazy = 0; 2248 rsp->qlen_lazy = 0;
@@ -2282,7 +2282,7 @@ static bool nocb_cpu_expendable(int cpu)
2282 * If there are no no-CB CPUs or if this CPU is not a no-CB CPU, 2282 * If there are no no-CB CPUs or if this CPU is not a no-CB CPU,
2283 * then offlining this CPU is harmless. Let it happen. 2283 * then offlining this CPU is harmless. Let it happen.
2284 */ 2284 */
2285 if (!have_rcu_nocb_mask || is_nocb_cpu(cpu)) 2285 if (!have_rcu_nocb_mask || rcu_is_nocb_cpu(cpu))
2286 return 1; 2286 return 1;
2287 2287
2288 /* If no memory, play it safe and keep the CPU around. */ 2288 /* If no memory, play it safe and keep the CPU around. */
@@ -2464,11 +2464,6 @@ static void __init rcu_init_nocb(void)
2464 2464
2465#else /* #ifdef CONFIG_RCU_NOCB_CPU */ 2465#else /* #ifdef CONFIG_RCU_NOCB_CPU */
2466 2466
2467static bool is_nocb_cpu(int cpu)
2468{
2469 return false;
2470}
2471
2472static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp, 2467static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
2473 bool lazy) 2468 bool lazy)
2474{ 2469{
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index 358d601a4fec..99c3f13dd478 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -128,6 +128,16 @@ config NO_HZ_FULL
128 128
129endchoice 129endchoice
130 130
131config NO_HZ_FULL_ALL
132 bool "Full dynticks system on all CPUs by default"
133 depends on NO_HZ_FULL
134 help
135 If the user doesn't pass the nohz_full boot option to
136 define the range of full dynticks CPUs, consider that all
137 CPUs in the system are full dynticks by default.
138 Note the boot CPU will still be kept outside the range to
139 handle the timekeeping duty.
140
131config NO_HZ 141config NO_HZ
132 bool "Old Idle dynticks config" 142 bool "Old Idle dynticks config"
133 depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS 143 depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 369b5769fc97..a76e09044f9f 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -158,11 +158,21 @@ int tick_nohz_full_cpu(int cpu)
158/* Parse the boot-time nohz CPU list from the kernel parameters. */ 158/* Parse the boot-time nohz CPU list from the kernel parameters. */
159static int __init tick_nohz_full_setup(char *str) 159static int __init tick_nohz_full_setup(char *str)
160{ 160{
161 int cpu;
162
161 alloc_bootmem_cpumask_var(&nohz_full_mask); 163 alloc_bootmem_cpumask_var(&nohz_full_mask);
162 if (cpulist_parse(str, nohz_full_mask) < 0) 164 if (cpulist_parse(str, nohz_full_mask) < 0) {
163 pr_warning("NOHZ: Incorrect nohz_full cpumask\n"); 165 pr_warning("NOHZ: Incorrect nohz_full cpumask\n");
164 else 166 return 1;
165 have_nohz_full_mask = true; 167 }
168
169 cpu = smp_processor_id();
170 if (cpumask_test_cpu(cpu, nohz_full_mask)) {
171 pr_warning("NO_HZ: Clearing %d from nohz_full range for timekeeping\n", cpu);
172 cpumask_clear_cpu(cpu, nohz_full_mask);
173 }
174 have_nohz_full_mask = true;
175
166 return 1; 176 return 1;
167} 177}
168__setup("nohz_full=", tick_nohz_full_setup); 178__setup("nohz_full=", tick_nohz_full_setup);
@@ -193,51 +203,46 @@ static int __cpuinit tick_nohz_cpu_down_callback(struct notifier_block *nfb,
193 */ 203 */
194static char __initdata nohz_full_buf[NR_CPUS + 1]; 204static char __initdata nohz_full_buf[NR_CPUS + 1];
195 205
196static int __init init_tick_nohz_full(void) 206static int tick_nohz_init_all(void)
197{ 207{
198 cpumask_var_t online_nohz; 208 int err = -1;
199 int cpu;
200 209
201 if (!have_nohz_full_mask) 210#ifdef CONFIG_NO_HZ_FULL_ALL
202 return 0; 211 if (!alloc_cpumask_var(&nohz_full_mask, GFP_KERNEL)) {
212 pr_err("NO_HZ: Can't allocate full dynticks cpumask\n");
213 return err;
214 }
215 err = 0;
216 cpumask_setall(nohz_full_mask);
217 cpumask_clear_cpu(smp_processor_id(), nohz_full_mask);
218 have_nohz_full_mask = true;
219#endif
220 return err;
221}
203 222
204 cpu_notifier(tick_nohz_cpu_down_callback, 0); 223void __init tick_nohz_init(void)
224{
225 int cpu;
205 226
206 if (!zalloc_cpumask_var(&online_nohz, GFP_KERNEL)) { 227 if (!have_nohz_full_mask) {
207 pr_warning("NO_HZ: Not enough memory to check full nohz mask\n"); 228 if (tick_nohz_init_all() < 0)
208 return -ENOMEM; 229 return;
209 } 230 }
210 231
211 /* 232 cpu_notifier(tick_nohz_cpu_down_callback, 0);
212 * CPUs can probably not be concurrently offlined on initcall time.
213 * But we are paranoid, aren't we?
214 */
215 get_online_cpus();
216 233
217 /* Ensure we keep a CPU outside the dynticks range for timekeeping */ 234 /* Make sure full dynticks CPU are also RCU nocbs */
218 cpumask_and(online_nohz, cpu_online_mask, nohz_full_mask); 235 for_each_cpu(cpu, nohz_full_mask) {
219 if (cpumask_equal(online_nohz, cpu_online_mask)) { 236 if (!rcu_is_nocb_cpu(cpu)) {
220 pr_warning("NO_HZ: Must keep at least one online CPU " 237 pr_warning("NO_HZ: CPU %d is not RCU nocb: "
221 "out of nohz_full range\n"); 238 "cleared from nohz_full range", cpu);
222 /* 239 cpumask_clear_cpu(cpu, nohz_full_mask);
223 * We know the current CPU doesn't have its tick stopped. 240 }
224 * Let's use it for the timekeeping duty.
225 */
226 preempt_disable();
227 cpu = smp_processor_id();
228 pr_warning("NO_HZ: Clearing %d from nohz_full range\n", cpu);
229 cpumask_clear_cpu(cpu, nohz_full_mask);
230 preempt_enable();
231 } 241 }
232 put_online_cpus();
233 free_cpumask_var(online_nohz);
234 242
235 cpulist_scnprintf(nohz_full_buf, sizeof(nohz_full_buf), nohz_full_mask); 243 cpulist_scnprintf(nohz_full_buf, sizeof(nohz_full_buf), nohz_full_mask);
236 pr_info("NO_HZ: Full dynticks CPUs: %s.\n", nohz_full_buf); 244 pr_info("NO_HZ: Full dynticks CPUs: %s.\n", nohz_full_buf);
237
238 return 0;
239} 245}
240core_initcall(init_tick_nohz_full);
241#else 246#else
242#define have_nohz_full_mask (0) 247#define have_nohz_full_mask (0)
243#endif 248#endif