Jan Beulich
2012-Mar-23  11:01 UTC
[PATCH] linux-2.6.18/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 <jbeulich@suse.com>
--- 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)
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel