smpboot: adjust ordering of operations The primary goal of the change is to add the locking around the setting of the cpu_online_map bit that got introduced in or before 2.6.16. In doing so I noticed, however, that the point in time when this is done wasn't in sync with how native does it (and in actual conflict with additions to that code path in subsequent Linux versions). So the setting of this bit now gets done on the CPU being brought up, and the CPU initiating the bringup, just like on native, waits for up to 5 seconds for the remote to respond. Finally, rather than BUG()ing on eventual errors, do proper cleanup and return the error to the caller. Plus call xen_smp_intr_init() earlier so that no cleanup will need to be performed in case of it failing. Signed-off-by: Jan Beulich --- a/drivers/xen/core/smpboot.c +++ b/drivers/xen/core/smpboot.c @@ -146,7 +146,6 @@ static int __cpuinit xen_smp_intr_init(u return rc; } -#ifdef CONFIG_HOTPLUG_CPU static void xen_smp_intr_exit(unsigned int cpu) { if (cpu != 0) @@ -155,7 +154,6 @@ static void xen_smp_intr_exit(unsigned i unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL); unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); } -#endif void __cpuinit cpu_bringup(void) { @@ -163,7 +161,9 @@ void __cpuinit cpu_bringup(void) identify_cpu(cpu_data + smp_processor_id()); touch_softlockup_watchdog(); preempt_disable(); - local_irq_enable(); + lock_ipi_call_lock(); + cpu_set(smp_processor_id(), cpu_online_map); + unlock_ipi_call_lock(); } static void __cpuinit cpu_bringup_and_idle(void) @@ -414,6 +414,10 @@ int __cpuinit __cpu_up(unsigned int cpu) if (rc) return rc; + rc = xen_smp_intr_init(cpu); + if (rc) + return rc; + cpu_initialize_context(cpu); if (num_online_cpus() == 1) @@ -423,18 +427,27 @@ int __cpuinit __cpu_up(unsigned int cpu) set_cpu_sibling_map(cpu); wmb(); - rc = xen_smp_intr_init(cpu); + rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL); + if (!rc) { + /* Wait 5s total for a response. */ + unsigned long timeout = jiffies + 5 * HZ; + + while (!cpu_online(cpu) && time_before_eq(jiffies, timeout)) + HYPERVISOR_yield(); + if (!cpu_online(cpu)) { + VOID(HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL)); + rc = -ETIMEDOUT; + } + } + if (rc) { + xen_smp_intr_exit(cpu); remove_siblinginfo(cpu); - return rc; + if (num_online_cpus() == 1) + alternatives_smp_switch(0); } - cpu_set(cpu, cpu_online_map); - - rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL); - BUG_ON(rc); - - return 0; + return rc; } void __init smp_cpus_done(unsigned int max_cpus)