Skip to content

Commit

Permalink
cpu: Defer smpboot kthread unparking until CPU known to scheduler
Browse files Browse the repository at this point in the history
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:

  2a442c9 ("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 <[email protected]>
Signed-off-by: Paul E. McKenney <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
paulmck authored and Ingo Molnar committed Apr 13, 2015
1 parent 4bfe186 commit 00df35f
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 3 deletions.
2 changes: 2 additions & 0 deletions include/linux/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions init/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 31 additions & 3 deletions kernel/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,37 @@ int __ref cpu_down(unsigned int cpu)
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)
{
Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit 00df35f

Please sign in to comment.