diff options
author | Ankur Arora <ankur.a.arora@oracle.com> | 2017-06-02 20:05:59 -0400 |
---|---|---|
committer | Juergen Gross <jgross@suse.com> | 2017-06-13 10:05:17 -0400 |
commit | 0b64ffb8db4e310f77a01079ca752d946a8526b5 (patch) | |
tree | 0975f7c4353148b0526752e84462945af44e7802 | |
parent | ad73fd595c2ab168fdd01a266cbe6e4df95f8db0 (diff) |
xen/pvh*: Support > 32 VCPUs at domain restore
When Xen restores a PVHVM or PVH guest, its shared_info only holds
up to 32 CPUs. The hypercall VCPUOP_register_vcpu_info allows
us to setup per-page areas for VCPUs. This means we can boot
PVH* guests with more than 32 VCPUs. During restore the per-cpu
structure is allocated freshly by the hypervisor (vcpu_info_mfn is
set to INVALID_MFN) so that the newly restored guest can make a
VCPUOP_register_vcpu_info hypercall.
However, we end up triggering this condition in Xen:
/* Run this command on yourself or on other offline VCPUS. */
if ( (v != current) && !test_bit(_VPF_down, &v->pause_flags) )
which means we are unable to setup the per-cpu VCPU structures
for running VCPUS. The Linux PV code paths makes this work by
iterating over cpu_possible in xen_vcpu_restore() with:
1) is target CPU up (VCPUOP_is_up hypercall?)
2) if yes, then VCPUOP_down to pause it
3) VCPUOP_register_vcpu_info
4) if it was down, then VCPUOP_up to bring it back up
With Xen commit 192df6f9122d ("xen/x86: allow HVM guests to use
hypercalls to bring up vCPUs") this is available for non-PV guests.
As such first check if VCPUOP_is_up is actually possible before
trying this dance.
As most of this dance code is done already in xen_vcpu_restore()
let's make it callable on PV, PVH and PVHVM.
Based-on-patch-by: Konrad Wilk <konrad.wilk@oracle.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Signed-off-by: Ankur Arora <ankur.a.arora@oracle.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
-rw-r--r-- | arch/x86/xen/enlighten.c | 45 | ||||
-rw-r--r-- | arch/x86/xen/enlighten_hvm.c | 20 | ||||
-rw-r--r-- | arch/x86/xen/smp_hvm.c | 10 | ||||
-rw-r--r-- | arch/x86/xen/suspend_hvm.c | 11 | ||||
-rw-r--r-- | include/xen/xen-ops.h | 2 |
5 files changed, 54 insertions, 34 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 96b745e3f56c..276cc21619ec 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -106,6 +106,21 @@ int xen_cpuhp_setup(int (*cpu_up_prepare_cb)(unsigned int), | |||
106 | return rc >= 0 ? 0 : rc; | 106 | return rc >= 0 ? 0 : rc; |
107 | } | 107 | } |
108 | 108 | ||
109 | static void xen_vcpu_setup_restore(int cpu) | ||
110 | { | ||
111 | /* Any per_cpu(xen_vcpu) is stale, so reset it */ | ||
112 | xen_vcpu_info_reset(cpu); | ||
113 | |||
114 | /* | ||
115 | * For PVH and PVHVM, setup online VCPUs only. The rest will | ||
116 | * be handled by hotplug. | ||
117 | */ | ||
118 | if (xen_pv_domain() || | ||
119 | (xen_hvm_domain() && cpu_online(cpu))) { | ||
120 | xen_vcpu_setup(cpu); | ||
121 | } | ||
122 | } | ||
123 | |||
109 | /* | 124 | /* |
110 | * On restore, set the vcpu placement up again. | 125 | * On restore, set the vcpu placement up again. |
111 | * If it fails, then we're in a bad state, since | 126 | * If it fails, then we're in a bad state, since |
@@ -117,17 +132,23 @@ void xen_vcpu_restore(void) | |||
117 | 132 | ||
118 | for_each_possible_cpu(cpu) { | 133 | for_each_possible_cpu(cpu) { |
119 | bool other_cpu = (cpu != smp_processor_id()); | 134 | bool other_cpu = (cpu != smp_processor_id()); |
120 | bool is_up = HYPERVISOR_vcpu_op(VCPUOP_is_up, xen_vcpu_nr(cpu), | 135 | bool is_up; |
121 | NULL); | 136 | |
137 | if (xen_vcpu_nr(cpu) == XEN_VCPU_ID_INVALID) | ||
138 | continue; | ||
139 | |||
140 | /* Only Xen 4.5 and higher support this. */ | ||
141 | is_up = HYPERVISOR_vcpu_op(VCPUOP_is_up, | ||
142 | xen_vcpu_nr(cpu), NULL) > 0; | ||
122 | 143 | ||
123 | if (other_cpu && is_up && | 144 | if (other_cpu && is_up && |
124 | HYPERVISOR_vcpu_op(VCPUOP_down, xen_vcpu_nr(cpu), NULL)) | 145 | HYPERVISOR_vcpu_op(VCPUOP_down, xen_vcpu_nr(cpu), NULL)) |
125 | BUG(); | 146 | BUG(); |
126 | 147 | ||
127 | xen_setup_runstate_info(cpu); | 148 | if (xen_pv_domain() || xen_feature(XENFEAT_hvm_safe_pvclock)) |
149 | xen_setup_runstate_info(cpu); | ||
128 | 150 | ||
129 | if (xen_have_vcpu_info_placement) | 151 | xen_vcpu_setup_restore(cpu); |
130 | xen_vcpu_setup(cpu); | ||
131 | 152 | ||
132 | if (other_cpu && is_up && | 153 | if (other_cpu && is_up && |
133 | HYPERVISOR_vcpu_op(VCPUOP_up, xen_vcpu_nr(cpu), NULL)) | 154 | HYPERVISOR_vcpu_op(VCPUOP_up, xen_vcpu_nr(cpu), NULL)) |
@@ -163,11 +184,11 @@ void xen_vcpu_setup(int cpu) | |||
163 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); | 184 | BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); |
164 | 185 | ||
165 | /* | 186 | /* |
166 | * This path is called twice on PVHVM - first during bootup via | 187 | * This path is called on PVHVM at bootup (xen_hvm_smp_prepare_boot_cpu) |
167 | * smp_init -> xen_hvm_cpu_notify, and then if the VCPU is being | 188 | * and at restore (xen_vcpu_restore). Also called for hotplugged |
168 | * hotplugged: cpu_up -> xen_hvm_cpu_notify. | 189 | * VCPUs (cpu_init -> xen_hvm_cpu_prepare_hvm). |
169 | * As we can only do the VCPUOP_register_vcpu_info once lets | 190 | * However, the hypercall can only be done once (see below) so if a VCPU |
170 | * not over-write its result. | 191 | * is offlined and comes back online then let's not redo the hypercall. |
171 | * | 192 | * |
172 | * For PV it is called during restore (xen_vcpu_restore) and bootup | 193 | * For PV it is called during restore (xen_vcpu_restore) and bootup |
173 | * (xen_setup_vcpu_info_placement). The hotplug mechanism does not | 194 | * (xen_setup_vcpu_info_placement). The hotplug mechanism does not |
@@ -178,8 +199,6 @@ void xen_vcpu_setup(int cpu) | |||
178 | return; | 199 | return; |
179 | } | 200 | } |
180 | 201 | ||
181 | xen_vcpu_info_reset(cpu); | ||
182 | |||
183 | if (xen_have_vcpu_info_placement) { | 202 | if (xen_have_vcpu_info_placement) { |
184 | vcpup = &per_cpu(xen_vcpu_info, cpu); | 203 | vcpup = &per_cpu(xen_vcpu_info, cpu); |
185 | info.mfn = arbitrary_virt_to_mfn(vcpup); | 204 | info.mfn = arbitrary_virt_to_mfn(vcpup); |
@@ -214,7 +233,7 @@ void xen_vcpu_setup(int cpu) | |||
214 | if (!xen_have_vcpu_info_placement) { | 233 | if (!xen_have_vcpu_info_placement) { |
215 | if (cpu >= MAX_VIRT_CPUS) | 234 | if (cpu >= MAX_VIRT_CPUS) |
216 | clamp_max_cpus(); | 235 | clamp_max_cpus(); |
217 | return; | 236 | xen_vcpu_info_reset(cpu); |
218 | } | 237 | } |
219 | } | 238 | } |
220 | 239 | ||
diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c index eb53da6547ee..ba1afadb2512 100644 --- a/arch/x86/xen/enlighten_hvm.c +++ b/arch/x86/xen/enlighten_hvm.c | |||
@@ -20,7 +20,6 @@ | |||
20 | 20 | ||
21 | void __ref xen_hvm_init_shared_info(void) | 21 | void __ref xen_hvm_init_shared_info(void) |
22 | { | 22 | { |
23 | int cpu; | ||
24 | struct xen_add_to_physmap xatp; | 23 | struct xen_add_to_physmap xatp; |
25 | static struct shared_info *shared_info_page; | 24 | static struct shared_info *shared_info_page; |
26 | 25 | ||
@@ -35,18 +34,6 @@ void __ref xen_hvm_init_shared_info(void) | |||
35 | BUG(); | 34 | BUG(); |
36 | 35 | ||
37 | HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; | 36 | HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; |
38 | |||
39 | /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info | ||
40 | * page, we use it in the event channel upcall and in some pvclock | ||
41 | * related functions. We don't need the vcpu_info placement | ||
42 | * optimizations because we don't use any pv_mmu or pv_irq op on | ||
43 | * HVM. | ||
44 | * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is | ||
45 | * online but xen_hvm_init_shared_info is run at resume time too and | ||
46 | * in that case multiple vcpus might be online. */ | ||
47 | for_each_online_cpu(cpu) { | ||
48 | xen_vcpu_info_reset(cpu); | ||
49 | } | ||
50 | } | 37 | } |
51 | 38 | ||
52 | static void __init init_hvm_pv_info(void) | 39 | static void __init init_hvm_pv_info(void) |
@@ -150,6 +137,13 @@ static void __init xen_hvm_guest_init(void) | |||
150 | 137 | ||
151 | xen_hvm_init_shared_info(); | 138 | xen_hvm_init_shared_info(); |
152 | 139 | ||
140 | /* | ||
141 | * xen_vcpu is a pointer to the vcpu_info struct in the shared_info | ||
142 | * page, we use it in the event channel upcall and in some pvclock | ||
143 | * related functions. | ||
144 | */ | ||
145 | xen_vcpu_info_reset(0); | ||
146 | |||
153 | xen_panic_handler_init(); | 147 | xen_panic_handler_init(); |
154 | 148 | ||
155 | if (xen_feature(XENFEAT_hvm_callback_vector)) | 149 | if (xen_feature(XENFEAT_hvm_callback_vector)) |
diff --git a/arch/x86/xen/smp_hvm.c b/arch/x86/xen/smp_hvm.c index 9e0fb9a015d4..6c8a805819ff 100644 --- a/arch/x86/xen/smp_hvm.c +++ b/arch/x86/xen/smp_hvm.c | |||
@@ -28,10 +28,20 @@ static void __init xen_hvm_smp_prepare_boot_cpu(void) | |||
28 | 28 | ||
29 | static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus) | 29 | static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus) |
30 | { | 30 | { |
31 | int cpu; | ||
32 | |||
31 | native_smp_prepare_cpus(max_cpus); | 33 | native_smp_prepare_cpus(max_cpus); |
32 | WARN_ON(xen_smp_intr_init(0)); | 34 | WARN_ON(xen_smp_intr_init(0)); |
33 | 35 | ||
34 | xen_init_lock_cpu(0); | 36 | xen_init_lock_cpu(0); |
37 | |||
38 | for_each_possible_cpu(cpu) { | ||
39 | if (cpu == 0) | ||
40 | continue; | ||
41 | |||
42 | /* Set default vcpu_id to make sure that we don't use cpu-0's */ | ||
43 | per_cpu(xen_vcpu_id, cpu) = XEN_VCPU_ID_INVALID; | ||
44 | } | ||
35 | } | 45 | } |
36 | 46 | ||
37 | #ifdef CONFIG_HOTPLUG_CPU | 47 | #ifdef CONFIG_HOTPLUG_CPU |
diff --git a/arch/x86/xen/suspend_hvm.c b/arch/x86/xen/suspend_hvm.c index 01afcadde50a..484999416d8b 100644 --- a/arch/x86/xen/suspend_hvm.c +++ b/arch/x86/xen/suspend_hvm.c | |||
@@ -8,15 +8,10 @@ | |||
8 | 8 | ||
9 | void xen_hvm_post_suspend(int suspend_cancelled) | 9 | void xen_hvm_post_suspend(int suspend_cancelled) |
10 | { | 10 | { |
11 | int cpu; | 11 | if (!suspend_cancelled) { |
12 | |||
13 | if (!suspend_cancelled) | ||
14 | xen_hvm_init_shared_info(); | 12 | xen_hvm_init_shared_info(); |
13 | xen_vcpu_restore(); | ||
14 | } | ||
15 | xen_callback_vector(); | 15 | xen_callback_vector(); |
16 | xen_unplug_emulated_devices(); | 16 | xen_unplug_emulated_devices(); |
17 | if (xen_feature(XENFEAT_hvm_safe_pvclock)) { | ||
18 | for_each_online_cpu(cpu) { | ||
19 | xen_setup_runstate_info(cpu); | ||
20 | } | ||
21 | } | ||
22 | } | 17 | } |
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index c44a2ee8c8f8..218e6aae5433 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h | |||
@@ -15,6 +15,8 @@ static inline uint32_t xen_vcpu_nr(int cpu) | |||
15 | return per_cpu(xen_vcpu_id, cpu); | 15 | return per_cpu(xen_vcpu_id, cpu); |
16 | } | 16 | } |
17 | 17 | ||
18 | #define XEN_VCPU_ID_INVALID U32_MAX | ||
19 | |||
18 | void xen_arch_pre_suspend(void); | 20 | void xen_arch_pre_suspend(void); |
19 | void xen_arch_post_suspend(int suspend_cancelled); | 21 | void xen_arch_post_suspend(int suspend_cancelled); |
20 | 22 | ||