aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-09 14:16:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-09 14:16:19 -0400
commit4d3c4a42938a23cc826e6e191aaff3567541ad05 (patch)
treee983e2c2c82f299d282e62dfe77c3e8eb157f839
parent4fde846ac0f019b7c877da35e1c1517d79e17ffc (diff)
parent9cd4f1a4e7a858849e889a081a99adff83e08e4c (diff)
Merge branch 'smp-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull smp/hotplug fix from Thomas Gleixner: "A single fix for a brown paperbag bug: The unparking of the initial percpu threads of an upcoming CPU happens right now on the idle task, but that's wrong as the unpark function might sleep. Move it to the control CPU." * 'smp-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: smp/hotplug: Move unparking of percpu threads to the control CPU
-rw-r--r--kernel/cpu.c37
1 files changed, 19 insertions, 18 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c
index b03a32595cfe..ab860453841d 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -271,11 +271,25 @@ void cpu_hotplug_enable(void)
271EXPORT_SYMBOL_GPL(cpu_hotplug_enable); 271EXPORT_SYMBOL_GPL(cpu_hotplug_enable);
272#endif /* CONFIG_HOTPLUG_CPU */ 272#endif /* CONFIG_HOTPLUG_CPU */
273 273
274static void __cpuhp_kick_ap_work(struct cpuhp_cpu_state *st);
275
274static int bringup_wait_for_ap(unsigned int cpu) 276static int bringup_wait_for_ap(unsigned int cpu)
275{ 277{
276 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 278 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
277 279
280 /* Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE */
278 wait_for_completion(&st->done); 281 wait_for_completion(&st->done);
282 BUG_ON(!cpu_online(cpu));
283
284 /* Unpark the stopper thread and the hotplug thread of the target cpu */
285 stop_machine_unpark(cpu);
286 kthread_unpark(st->thread);
287
288 /* Should we go further up ? */
289 if (st->target > CPUHP_AP_ONLINE_IDLE) {
290 __cpuhp_kick_ap_work(st);
291 wait_for_completion(&st->done);
292 }
279 return st->result; 293 return st->result;
280} 294}
281 295
@@ -296,9 +310,7 @@ static int bringup_cpu(unsigned int cpu)
296 irq_unlock_sparse(); 310 irq_unlock_sparse();
297 if (ret) 311 if (ret)
298 return ret; 312 return ret;
299 ret = bringup_wait_for_ap(cpu); 313 return bringup_wait_for_ap(cpu);
300 BUG_ON(!cpu_online(cpu));
301 return ret;
302} 314}
303 315
304/* 316/*
@@ -767,31 +779,20 @@ void notify_cpu_starting(unsigned int cpu)
767} 779}
768 780
769/* 781/*
770 * Called from the idle task. We need to set active here, so we can kick off 782 * Called from the idle task. Wake up the controlling task which brings the
771 * the stopper thread and unpark the smpboot threads. If the target state is 783 * stopper and the hotplug thread of the upcoming CPU up and then delegates
772 * beyond CPUHP_AP_ONLINE_IDLE we kick cpuhp thread and let it bring up the 784 * the rest of the online bringup to the hotplug thread.
773 * cpu further.
774 */ 785 */
775void cpuhp_online_idle(enum cpuhp_state state) 786void cpuhp_online_idle(enum cpuhp_state state)
776{ 787{
777 struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 788 struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
778 unsigned int cpu = smp_processor_id();
779 789
780 /* Happens for the boot cpu */ 790 /* Happens for the boot cpu */
781 if (state != CPUHP_AP_ONLINE_IDLE) 791 if (state != CPUHP_AP_ONLINE_IDLE)
782 return; 792 return;
783 793
784 st->state = CPUHP_AP_ONLINE_IDLE; 794 st->state = CPUHP_AP_ONLINE_IDLE;
785 795 complete(&st->done);
786 /* Unpark the stopper thread and the hotplug thread of this cpu */
787 stop_machine_unpark(cpu);
788 kthread_unpark(st->thread);
789
790 /* Should we go further up ? */
791 if (st->target > CPUHP_AP_ONLINE_IDLE)
792 __cpuhp_kick_ap_work(st);
793 else
794 complete(&st->done);
795} 796}
796 797
797/* Requires cpu_add_remove_lock to be held */ 798/* Requires cpu_add_remove_lock to be held */