cpu: Defer smpboot kthread unparking until CPU known to scheduler
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Sun, 12 Apr 2015 15:06:55 +0000 (08:06 -0700)
committerIngo Molnar <mingo@kernel.org>
Mon, 13 Apr 2015 06:25:16 +0000 (08:25 +0200)
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>
include/linux/cpu.h
init/main.c
kernel/cpu.c

index d028721748d47b24780806f5b57bf14822726dc1..091badf0f6ba99152860ad3bf95f778e7cf90415 100644 (file)
@@ -73,6 +73,7 @@ enum {
        /* migration should happen before other stuff but after perf */
        CPU_PRI_PERF            = 20,
        CPU_PRI_MIGRATION       = 10,
+       CPU_PRI_SMPBOOT         = 9,
        /* bring up workqueues before normal notifiers and down after */
        CPU_PRI_WORKQUEUE_UP    = 5,
        CPU_PRI_WORKQUEUE_DOWN  = -5,
@@ -165,6 +166,7 @@ static inline void __unregister_cpu_notifier(struct notifier_block *nb)
 }
 #endif
 
+void smpboot_thread_init(void);
 int cpu_up(unsigned int cpu);
 void notify_cpu_starting(unsigned int cpu);
 extern void cpu_maps_update_begin(void);
index 6f0f1c5ff8cc82c41b36f107f68732003c5b1dc3..a12548c93318b8354e332a1ca638f5105c451756 100644 (file)
@@ -384,6 +384,7 @@ static noinline void __init_refok rest_init(void)
        int pid;
 
        rcu_scheduler_starting();
+       smpboot_thread_init();
        /*
         * We need to spawn init first so that it obtains pid 1, however
         * the init task will end up wanting to create kthreads, which, if
index d46b4dae0ca097130f78ffa39a5aada6931e5a95..57858cebd6b561939dbc5b1bbaeecf797ec56492 100644 (file)
@@ -448,6 +448,37 @@ out:
 EXPORT_SYMBOL(cpu_down);
 #endif /*CONFIG_HOTPLUG_CPU*/
 
+/*
+ * Unpark per-CPU smpboot kthreads at CPU-online time.
+ */
+static int smpboot_thread_call(struct notifier_block *nfb,
+                              unsigned long action, void *hcpu)
+{
+       int cpu = (long)hcpu;
+
+       switch (action & ~CPU_TASKS_FROZEN) {
+
+       case CPU_ONLINE:
+               smpboot_unpark_threads(cpu);
+               break;
+
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block smpboot_thread_notifier = {
+       .notifier_call = smpboot_thread_call,
+       .priority = CPU_PRI_SMPBOOT,
+};
+
+void __cpuinit smpboot_thread_init(void)
+{
+       register_cpu_notifier(&smpboot_thread_notifier);
+}
+
 /* Requires cpu_add_remove_lock to be held */
 static int _cpu_up(unsigned int cpu, int tasks_frozen)
 {
@@ -487,9 +518,6 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen)
                goto out_notify;
        BUG_ON(!cpu_online(cpu));
 
-       /* Wake the per cpu threads */
-       smpboot_unpark_threads(cpu);
-
        /* Now call notifier in preparation. */
        cpu_notify(CPU_ONLINE | mod, hcpu);