diff mbox

[1/2] xen/x86: Convert to hotplug state machine

Message ID 1471272407-4292-2-git-send-email-boris.ostrovsky@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Boris Ostrovsky Aug. 15, 2016, 2:46 p.m. UTC
Switch to new CPU hotplug infrastructure.

Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Suggested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 arch/x86/xen/enlighten.c   |  115 +++++++++++++++++++++++++-------------------
 include/linux/cpuhotplug.h |    2 +
 2 files changed, 67 insertions(+), 50 deletions(-)

Comments

Sebastian Andrzej Siewior Aug. 17, 2016, 8:33 a.m. UTC | #1
On 2016-08-15 10:46:46 [-0400], Boris Ostrovsky wrote:
> Switch to new CPU hotplug infrastructure.
> 
> Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
> Suggested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
>  arch/x86/xen/enlighten.c   |  115 +++++++++++++++++++++++++-------------------
>  include/linux/cpuhotplug.h |    2 +
>  2 files changed, 67 insertions(+), 50 deletions(-)
> 
> diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
> index c7f6b1f..2283976 100644
> --- a/arch/x86/xen/enlighten.c
> +++ b/arch/x86/xen/enlighten.c
> @@ -1541,6 +1543,24 @@ static void __init xen_dom0_set_legacy_features(void)
>  	x86_platform.legacy.rtc = 1;
>  }
>  
> +static int xen_cpuhp_setup(void)
> +{
> +	int rc;
> +
> +	rc = cpuhp_setup_state_nocalls(CPUHP_XEN_PREPARE,
> +				       "XEN_HVM_GUEST_PREPARE",
> +				       xen_cpu_up_prepare, xen_cpu_up_cancel);

The old states UP_CANCEL is different from UP_PREPARE. The latter was
invoked only in the error case while your new callback is always
invoked. From looking at the code you free memory in
xen_cpu_up_cancel() which was allocated in xen_cpu_up_prepare() and
therefore I would name it xen_cpu_dead().
If you do find the time, you might manage to rework the code to avoid
using the _nocalls() function. If see this right, you use
xen_setup_vcpu_info_placement() for the init in the first place. This
uses for_each_possible_cpu macro. The cpuhp_setup_state() function would
perform the init for all CPUs before they come up.

> +	if (!rc) {
> +		rc = cpuhp_setup_state_nocalls(CPUHP_AP_XEN_ONLINE,

If there is no need to run this after KVM's CLK callback please use
CPUHP_AP_ONLINE_DYN. If there is such a need then please document it.

> +					       "XEN_HVM_GUEST_PREPARE",
> +					       xen_cpu_up_online, NULL);
> +		if (rc)
> +			cpuhp_remove_state_nocalls(CPUHP_XEN_PREPARE);
> +	}
> +
> +	return rc;
> +}
> +
>  /* First C function to be called on Xen boot */
>  asmlinkage __visible void __init xen_start_kernel(void)
>  {

Sebastian
Boris Ostrovsky Aug. 26, 2016, 7:37 p.m. UTC | #2
On 08/17/2016 04:33 AM, Sebastian Andrzej Siewior wrote:
> On 2016-08-15 10:46:46 [-0400], Boris Ostrovsky wrote:
>> Switch to new CPU hotplug infrastructure.
>>
>> Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
>> Suggested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>> ---
>>  arch/x86/xen/enlighten.c   |  115 +++++++++++++++++++++++++-------------------
>>  include/linux/cpuhotplug.h |    2 +
>>  2 files changed, 67 insertions(+), 50 deletions(-)
>>
>> diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
>> index c7f6b1f..2283976 100644
>> --- a/arch/x86/xen/enlighten.c
>> +++ b/arch/x86/xen/enlighten.c
>> @@ -1541,6 +1543,24 @@ static void __init xen_dom0_set_legacy_features(void)
>>  	x86_platform.legacy.rtc = 1;
>>  }
>>  
>> +static int xen_cpuhp_setup(void)
>> +{
>> +	int rc;
>> +
>> +	rc = cpuhp_setup_state_nocalls(CPUHP_XEN_PREPARE,
>> +				       "XEN_HVM_GUEST_PREPARE",
>> +				       xen_cpu_up_prepare, xen_cpu_up_cancel);
> The old states UP_CANCEL is different from UP_PREPARE. The latter was
> invoked only in the error case while your new callback is always
> invoked. From looking at the code you free memory in
> xen_cpu_up_cancel() which was allocated in xen_cpu_up_prepare() and
> therefore I would name it xen_cpu_dead().

Yes, "cancel" is wrong term to use here.

> If you do find the time, you might manage to rework the code to avoid
> using the _nocalls() function. If see this right, you use
> xen_setup_vcpu_info_placement() for the init in the first place. This
> uses for_each_possible_cpu macro. The cpuhp_setup_state() function would
> perform the init for all CPUs before they come up.

I am not sure I see what this would buy us.

Besides, cpuhp_setup_state() uses for_each_present_cpu().

>
>> +	if (!rc) {
>> +		rc = cpuhp_setup_state_nocalls(CPUHP_AP_XEN_ONLINE,
> If there is no need to run this after KVM's CLK callback please use
> CPUHP_AP_ONLINE_DYN. If there is such a need then please document it.

OK.

-boris

>
>> +					       "XEN_HVM_GUEST_PREPARE",
>> +					       xen_cpu_up_online, NULL);
>> +		if (rc)
>> +			cpuhp_remove_state_nocalls(CPUHP_XEN_PREPARE);
>> +	}
>> +
>> +	return rc;
>> +}
>> +
>>  /* First C function to be called on Xen boot */
>>  asmlinkage __visible void __init xen_start_kernel(void)
>>  {
> Sebastian
Sebastian Andrzej Siewior Aug. 31, 2016, 4:15 p.m. UTC | #3
On 2016-08-26 15:37:38 [-0400], Boris Ostrovsky wrote:
> > If you do find the time, you might manage to rework the code to avoid
> > using the _nocalls() function. If see this right, you use
> > xen_setup_vcpu_info_placement() for the init in the first place. This
> > uses for_each_possible_cpu macro. The cpuhp_setup_state() function would
> > perform the init for all CPUs before they come up.
> 
> I am not sure I see what this would buy us.
> 
> Besides, cpuhp_setup_state() uses for_each_present_cpu().

Correct. So you would avoid running the init code on CPUs which are
within the for_each_possible_cpu() set but not in for_each_present_cpu().

Assuming a NUMA box with two CPUs, 8 cores each gives you 32 CPUs in
Linux with hyper threading. BIOS may report 240 CPUs as the upper limit
(possible CPUs) but if you never deploy them you don't need to
initialize them… Should they be plugged physically then the
for_each_present_cpu() loop will cover them once they come up.

Sebastian
Boris Ostrovsky Sept. 2, 2016, 2:03 a.m. UTC | #4
On 08/31/2016 12:15 PM, Sebastian Andrzej Siewior wrote:
> On 2016-08-26 15:37:38 [-0400], Boris Ostrovsky wrote:
>>> If you do find the time, you might manage to rework the code to avoid
>>> using the _nocalls() function. If see this right, you use
>>> xen_setup_vcpu_info_placement() for the init in the first place. This
>>> uses for_each_possible_cpu macro. The cpuhp_setup_state() function would
>>> perform the init for all CPUs before they come up.
>> I am not sure I see what this would buy us.
>>
>> Besides, cpuhp_setup_state() uses for_each_present_cpu().
> Correct. So you would avoid running the init code on CPUs which are
> within the for_each_possible_cpu() set but not in for_each_present_cpu().
>
> Assuming a NUMA box with two CPUs, 8 cores each gives you 32 CPUs in
> Linux with hyper threading. BIOS may report 240 CPUs as the upper limit
> (possible CPUs) but if you never deploy them you don't need to
> initialize them… Should they be plugged physically then the
> for_each_present_cpu() loop will cover them once they come up.
>

That's not going to help Xen guests: all possible CPUs are brought up
right away and then those that are not in use are unplugged.


-boris
diff mbox

Patch

diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index c7f6b1f..2283976 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -140,7 +140,9 @@  RESERVE_BRK(shared_info_page_brk, PAGE_SIZE);
 __read_mostly int xen_have_vector_callback;
 EXPORT_SYMBOL_GPL(xen_have_vector_callback);
 
-static struct notifier_block xen_cpu_notifier;
+static int xen_cpu_up_prepare(unsigned int cpu);
+static int xen_cpu_up_online(unsigned int cpu);
+static int xen_cpu_up_cancel(unsigned int cpu);
 
 /*
  * Point at some empty memory to start with. We map the real shared_info
@@ -1541,6 +1543,24 @@  static void __init xen_dom0_set_legacy_features(void)
 	x86_platform.legacy.rtc = 1;
 }
 
+static int xen_cpuhp_setup(void)
+{
+	int rc;
+
+	rc = cpuhp_setup_state_nocalls(CPUHP_XEN_PREPARE,
+				       "XEN_HVM_GUEST_PREPARE",
+				       xen_cpu_up_prepare, xen_cpu_up_cancel);
+	if (!rc) {
+		rc = cpuhp_setup_state_nocalls(CPUHP_AP_XEN_ONLINE,
+					       "XEN_HVM_GUEST_PREPARE",
+					       xen_cpu_up_online, NULL);
+		if (rc)
+			cpuhp_remove_state_nocalls(CPUHP_XEN_PREPARE);
+	}
+
+	return rc;
+}
+
 /* First C function to be called on Xen boot */
 asmlinkage __visible void __init xen_start_kernel(void)
 {
@@ -1629,7 +1649,7 @@  asmlinkage __visible void __init xen_start_kernel(void)
 	xen_initial_gdt = &per_cpu(gdt_page, 0);
 
 	xen_smp_init();
-	register_cpu_notifier(&xen_cpu_notifier);
+	WARN_ON(xen_cpuhp_setup());
 
 #ifdef CONFIG_ACPI_NUMA
 	/*
@@ -1823,63 +1843,58 @@  static void __init init_hvm_pv_info(void)
 	xen_domain_type = XEN_HVM_DOMAIN;
 }
 
-static int xen_cpu_notify(struct notifier_block *self, unsigned long action,
-			 void *hcpu)
+static int xen_cpu_up_prepare(unsigned int cpu)
 {
-	int cpu = (long)hcpu;
 	int rc;
 
-	switch (action) {
-	case CPU_UP_PREPARE:
-		if (xen_hvm_domain()) {
-			/*
-			 * This can happen if CPU was offlined earlier and
-			 * offlining timed out in common_cpu_die().
-			 */
-			if (cpu_report_state(cpu) == CPU_DEAD_FROZEN) {
-				xen_smp_intr_free(cpu);
-				xen_uninit_lock_cpu(cpu);
-			}
-
-			if (cpu_acpi_id(cpu) != U32_MAX)
-				per_cpu(xen_vcpu_id, cpu) = cpu_acpi_id(cpu);
-			else
-				per_cpu(xen_vcpu_id, cpu) = cpu;
-			xen_vcpu_setup(cpu);
+	if (xen_hvm_domain()) {
+		/*
+		 * This can happen if CPU was offlined earlier and
+		 * offlining timed out in common_cpu_die().
+		 */
+		if (cpu_report_state(cpu) == CPU_DEAD_FROZEN) {
+			xen_smp_intr_free(cpu);
+			xen_uninit_lock_cpu(cpu);
 		}
 
-		if (xen_pv_domain() ||
-		    (xen_have_vector_callback &&
-		     xen_feature(XENFEAT_hvm_safe_pvclock)))
-			xen_setup_timer(cpu);
+		if (cpu_acpi_id(cpu) != U32_MAX)
+			per_cpu(xen_vcpu_id, cpu) = cpu_acpi_id(cpu);
+		else
+			per_cpu(xen_vcpu_id, cpu) = cpu;
+		xen_vcpu_setup(cpu);
+	}
 
-		rc = xen_smp_intr_init(cpu);
-		if (rc) {
-			WARN(1, "xen_smp_intr_init() for CPU %d failed: %d\n",
-			     cpu, rc);
-			return NOTIFY_BAD;
-		}
+	if (xen_pv_domain() ||
+	    (xen_have_vector_callback &&
+	     xen_feature(XENFEAT_hvm_safe_pvclock)))
+		xen_setup_timer(cpu);
 
-		break;
-	case CPU_ONLINE:
-		xen_init_lock_cpu(cpu);
-		break;
-	case CPU_UP_CANCELED:
-		xen_smp_intr_free(cpu);
-		if (xen_pv_domain() ||
-		    (xen_have_vector_callback &&
-		     xen_feature(XENFEAT_hvm_safe_pvclock)))
-			xen_teardown_timer(cpu);
-		break;
-	default:
-		break;
+	rc = xen_smp_intr_init(cpu);
+	if (rc) {
+		WARN(1, "xen_smp_intr_init() for CPU %d failed: %d\n",
+		     cpu, rc);
+		return rc;
 	}
-	return NOTIFY_OK;
+	return 0;
 }
 
-static struct notifier_block xen_cpu_notifier = {
-	.notifier_call	= xen_cpu_notify,
-};
+static int xen_cpu_up_cancel(unsigned int cpu)
+{
+	xen_smp_intr_free(cpu);
+
+	if (xen_pv_domain() ||
+	    (xen_have_vector_callback &&
+	     xen_feature(XENFEAT_hvm_safe_pvclock)))
+		xen_teardown_timer(cpu);
+
+	return 0;
+}
+
+static int xen_cpu_up_online(unsigned int cpu)
+{
+	xen_init_lock_cpu(cpu);
+	return 0;
+}
 
 #ifdef CONFIG_KEXEC_CORE
 static void xen_hvm_shutdown(void)
@@ -1910,7 +1925,7 @@  static void __init xen_hvm_guest_init(void)
 	if (xen_feature(XENFEAT_hvm_callback_vector))
 		xen_have_vector_callback = 1;
 	xen_hvm_smp_init();
-	register_cpu_notifier(&xen_cpu_notifier);
+	WARN_ON(xen_cpuhp_setup());
 	xen_unplug_emulated_devices();
 	x86_init.irqs.intr_init = xen_init_IRQ;
 	xen_hvm_init_time_ops();
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 242bf53..d6beeb9 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -21,6 +21,7 @@  enum cpuhp_state {
 	CPUHP_X2APIC_PREPARE,
 	CPUHP_SMPCFD_PREPARE,
 	CPUHP_RCUTREE_PREP,
+	CPUHP_XEN_PREPARE,
 	CPUHP_NOTIFY_PREPARE,
 	CPUHP_TIMERS_DEAD,
 	CPUHP_BRINGUP_CPU,
@@ -93,6 +94,7 @@  enum cpuhp_state {
 	CPUHP_AP_ONLINE_DYN_END		= CPUHP_AP_ONLINE_DYN + 30,
 	CPUHP_AP_X86_HPET_ONLINE,
 	CPUHP_AP_X86_KVM_CLK_ONLINE,
+	CPUHP_AP_XEN_ONLINE,
 	CPUHP_AP_ACTIVE,
 	CPUHP_ONLINE,
 };