aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2015-04-12 11:06:55 -0400
committerIngo Molnar <mingo@kernel.org>2015-04-13 02:25:16 -0400
commit00df35f991914db6b8bde8cf09808e19a9cffc3d (patch)
tree626f0f8fd29b55f9a203565948dfd8bb70530496
parent4bfe186dbe0a058680e4bfb0d673194f0ceaffd4 (diff)
cpu: Defer smpboot kthread unparking until CPU known to scheduler
Currently, smpboot_unpark_threads() is invoked before the incoming CPU has been added to the scheduler's runqueue structures. This might potentially cause the unparked kthread to run on the wrong CPU, since the correct CPU isn't fully set up yet. That causes a sporadic, hard to debug boot crash triggering on some systems, reported by Borislav Petkov, and bisected down to: 2a442c9c6453 ("x86: Use common outgoing-CPU-notification code") This patch places smpboot_unpark_threads() in a CPU hotplug notifier with priority set so that these kthreads are unparked just after the CPU has been added to the runqueues. Reported-and-tested-by: Borislav Petkov <bp@suse.de> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/linux/cpu.h2
-rw-r--r--init/main.c1
-rw-r--r--kernel/cpu.c34
3 files changed, 34 insertions, 3 deletions
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index d028721748d4..091badf0f6ba 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -73,6 +73,7 @@ enum {
73 /* migration should happen before other stuff but after perf */ 73 /* migration should happen before other stuff but after perf */
74 CPU_PRI_PERF = 20, 74 CPU_PRI_PERF = 20,
75 CPU_PRI_MIGRATION = 10, 75 CPU_PRI_MIGRATION = 10,
76 CPU_PRI_SMPBOOT = 9,
76 /* bring up workqueues before normal notifiers and down after */ 77 /* bring up workqueues before normal notifiers and down after */
77 CPU_PRI_WORKQUEUE_UP = 5, 78 CPU_PRI_WORKQUEUE_UP = 5,
78 CPU_PRI_WORKQUEUE_DOWN = -5, 79 CPU_PRI_WORKQUEUE_DOWN = -5,
@@ -165,6 +166,7 @@ static inline void __unregister_cpu_notifier(struct notifier_block *nb)
165} 166}
166#endif 167#endif
167 168
169void smpboot_thread_init(void);
168int cpu_up(unsigned int cpu); 170int cpu_up(unsigned int cpu);
169void notify_cpu_starting(unsigned int cpu); 171void notify_cpu_starting(unsigned int cpu);
170extern void cpu_maps_update_begin(void); 172extern void cpu_maps_update_begin(void);
diff --git a/init/main.c b/init/main.c
index 6f0f1c5ff8cc..a12548c93318 100644
--- a/init/main.c
+++ b/init/main.c
@@ -384,6 +384,7 @@ static noinline void __init_refok rest_init(void)
384 int pid; 384 int pid;
385 385
386 rcu_scheduler_starting(); 386 rcu_scheduler_starting();
387 smpboot_thread_init();
387 /* 388 /*
388 * We need to spawn init first so that it obtains pid 1, however 389 * We need to spawn init first so that it obtains pid 1, however
389 * the init task will end up wanting to create kthreads, which, if 390 * the init task will end up wanting to create kthreads, which, if
diff --git a/kernel/cpu.c b/kernel/cpu.c
index d46b4dae0ca0..57858cebd6b5 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -448,6 +448,37 @@ out:
448EXPORT_SYMBOL(cpu_down); 448EXPORT_SYMBOL(cpu_down);
449#endif /*CONFIG_HOTPLUG_CPU*/ 449#endif /*CONFIG_HOTPLUG_CPU*/
450 450
451/*
452 * Unpark per-CPU smpboot kthreads at CPU-online time.
453 */
454static int smpboot_thread_call(struct notifier_block *nfb,
455 unsigned long action, void *hcpu)
456{
457 int cpu = (long)hcpu;
458
459 switch (action & ~CPU_TASKS_FROZEN) {
460
461 case CPU_ONLINE:
462 smpboot_unpark_threads(cpu);
463 break;
464
465 default:
466 break;
467 }
468
469 return NOTIFY_OK;
470}
471
472static struct notifier_block smpboot_thread_notifier = {
473 .notifier_call = smpboot_thread_call,
474 .priority = CPU_PRI_SMPBOOT,
475};
476
477void __cpuinit smpboot_thread_init(void)
478{
479 register_cpu_notifier(&smpboot_thread_notifier);
480}
481
451/* Requires cpu_add_remove_lock to be held */ 482/* Requires cpu_add_remove_lock to be held */
452static int _cpu_up(unsigned int cpu, int tasks_frozen) 483static int _cpu_up(unsigned int cpu, int tasks_frozen)
453{ 484{
@@ -487,9 +518,6 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen)
487 goto out_notify; 518 goto out_notify;
488 BUG_ON(!cpu_online(cpu)); 519 BUG_ON(!cpu_online(cpu));
489 520
490 /* Wake the per cpu threads */
491 smpboot_unpark_threads(cpu);
492
493 /* Now call notifier in preparation. */ 521 /* Now call notifier in preparation. */
494 cpu_notify(CPU_ONLINE | mod, hcpu); 522 cpu_notify(CPU_ONLINE | mod, hcpu);
495 523