aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2013-03-26 18:47:24 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2013-04-19 07:54:04 -0400
commitd1e43fa5f8bb25f83a86a29f11fcfb57ed4d7566 (patch)
tree9eff00255c1061248b6aef2c8341ea527610150c
parent0453b435df0d69dd0d8c42eb9b3015aaf0d8a032 (diff)
nohz: Ensure full dynticks CPUs are RCU nocbs
We need full dynticks CPU to also be RCU nocb so that we don't have to keep the tick to handle RCU callbacks. Make sure the range passed to nohz_full= boot parameter is a subset of rcu_nocbs= The CPUs that fail to meet this requirement will be excluded from the nohz_full range. This is checked early in boot time, before any CPU has the opportunity to stop its tick. Suggested-by: Steven Rostedt <rostedt@goodmis.org> Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Chris Metcalf <cmetcalf@tilera.com> Cc: Christoph Lameter <cl@linux.com> Cc: Geoff Levand <geoff@infradead.org> Cc: Gilad Ben Yossef <gilad@benyossef.com> Cc: Hakan Akkan <hakanakkan@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Kevin Hilman <khilman@linaro.org> Cc: Li Zhong <zhong@linux.vnet.ibm.com> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Paul Gortmaker <paul.gortmaker@windriver.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--Documentation/kernel-parameters.txt2
-rw-r--r--include/linux/rcupdate.h7
-rw-r--r--include/linux/tick.h2
-rw-r--r--init/main.c1
-rw-r--r--kernel/rcutree.c6
-rw-r--r--kernel/rcutree.h1
-rw-r--r--kernel/rcutree_plugin.h13
-rw-r--r--kernel/time/tick-sched.c22
8 files changed, 35 insertions, 19 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 887b29708447..4865e9bfd08d 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1918,6 +1918,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
1918 the specified list of CPUs whose tick will be stopped 1918 the specified list of CPUs whose tick will be stopped
1919 whenever possible. The boot CPU will be forced outside 1919 whenever possible. The boot CPU will be forced outside
1920 the range to maintain the timekeeping. 1920 the range to maintain the timekeeping.
1921 The CPUs in this range must also be included in the
1922 rcu_nocbs= set.
1921 1923
1922 noiotrap [SH] Disables trapped I/O port accesses. 1924 noiotrap [SH] Disables trapped I/O port accesses.
1923 1925
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index b758ce17b309..8e0948c872fc 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -999,4 +999,11 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
999#define kfree_rcu(ptr, rcu_head) \ 999#define kfree_rcu(ptr, rcu_head) \
1000 __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head)) 1000 __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head))
1001 1001
1002#ifdef CONFIG_RCU_NOCB_CPU
1003extern bool rcu_is_nocb_cpu(int cpu);
1004#else
1005static inline bool rcu_is_nocb_cpu(int cpu) { return false; }
1006#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
1007
1008
1002#endif /* __LINUX_RCUPDATE_H */ 1009#endif /* __LINUX_RCUPDATE_H */
diff --git a/include/linux/tick.h b/include/linux/tick.h
index b4e3b0c9639e..0b6873cbf512 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -158,8 +158,10 @@ static inline u64 get_cpu_iowait_time_us(int cpu, u64 *unused) { return -1; }
158# endif /* !CONFIG_NO_HZ_COMMON */ 158# endif /* !CONFIG_NO_HZ_COMMON */
159 159
160#ifdef CONFIG_NO_HZ_FULL 160#ifdef CONFIG_NO_HZ_FULL
161extern void tick_nohz_init(void);
161extern int tick_nohz_full_cpu(int cpu); 162extern int tick_nohz_full_cpu(int cpu);
162#else 163#else
164static inline void tick_nohz_init(void) { }
163static inline int tick_nohz_full_cpu(int cpu) { return 0; } 165static inline int tick_nohz_full_cpu(int cpu) { return 0; }
164#endif 166#endif
165 167
diff --git a/init/main.c b/init/main.c
index 63534a141b4e..2acb5bbde99b 100644
--- a/init/main.c
+++ b/init/main.c
@@ -547,6 +547,7 @@ asmlinkage void __init start_kernel(void)
547 idr_init_cache(); 547 idr_init_cache();
548 perf_event_init(); 548 perf_event_init();
549 rcu_init(); 549 rcu_init();
550 tick_nohz_init();
550 radix_tree_init(); 551 radix_tree_init();
551 /* init some links before init_ISA_irqs() */ 552 /* init some links before init_ISA_irqs() */
552 early_irq_init(); 553 early_irq_init();
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/tick-sched.c b/kernel/time/tick-sched.c
index 2bac5ea2c9af..d71a5f2bd7b2 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -203,17 +203,27 @@ static int __cpuinit tick_nohz_cpu_down_callback(struct notifier_block *nfb,
203 */ 203 */
204static char __initdata nohz_full_buf[NR_CPUS + 1]; 204static char __initdata nohz_full_buf[NR_CPUS + 1];
205 205
206static int __init init_tick_nohz_full(void) 206void __init tick_nohz_init(void)
207{ 207{
208 if (have_nohz_full_mask) 208 int cpu;
209 cpu_notifier(tick_nohz_cpu_down_callback, 0); 209
210 if (!have_nohz_full_mask)
211 return;
212
213 cpu_notifier(tick_nohz_cpu_down_callback, 0);
214
215 /* Make sure full dynticks CPU are also RCU nocbs */
216 for_each_cpu(cpu, nohz_full_mask) {
217 if (!rcu_is_nocb_cpu(cpu)) {
218 pr_warning("NO_HZ: CPU %d is not RCU nocb: "
219 "cleared from nohz_full range", cpu);
220 cpumask_clear_cpu(cpu, nohz_full_mask);
221 }
222 }
210 223
211 cpulist_scnprintf(nohz_full_buf, sizeof(nohz_full_buf), nohz_full_mask); 224 cpulist_scnprintf(nohz_full_buf, sizeof(nohz_full_buf), nohz_full_mask);
212 pr_info("NO_HZ: Full dynticks CPUs: %s.\n", nohz_full_buf); 225 pr_info("NO_HZ: Full dynticks CPUs: %s.\n", nohz_full_buf);
213
214 return 0;
215} 226}
216core_initcall(init_tick_nohz_full);
217#else 227#else
218#define have_nohz_full_mask (0) 228#define have_nohz_full_mask (0)
219#endif 229#endif