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.

Change-Id: I8921987de9c2a2f475cc63dc82662d6ebf6e8725
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>
Git-commit: 00df35f991914db6b8bde8cf09808e19a9cffc3d
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
This commit is contained in:
Paul E. McKenney 2015-04-12 08:06:55 -07:00 committed by Zhao Wei Liew
parent 061336f2bb
commit b7703ca834
3 changed files with 34 additions and 3 deletions

View file

@ -75,6 +75,7 @@ enum {
/* migration should happen before other stuff but after perf */
CPU_PRI_PERF = 20,
CPU_PRI_MIGRATION = 10,
CPU_PRI_SMPBOOT = 9,
/* prepare workqueues for other notifiers */
CPU_PRI_WORKQUEUE = 5,
};
@ -142,6 +143,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);

View file

@ -362,6 +362,7 @@ static noinline void __init_refok rest_init(void)
const struct sched_param param = { .sched_priority = 1 };
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

View file

@ -294,6 +294,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 __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
{
@ -331,9 +362,6 @@ static int __cpuinit _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);