Skip to content

Commit ee68154

Browse files
vittyvkliuw
authored andcommitted
x86/hyperv: Restore VP assist page after cpu offlining/onlining
Commit e5d9b71 ("x86/hyperv: fix root partition faults when writing to VP assist page MSR") moved 'wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE)' under 'if (*hvp)' condition. This works for root partition as hv_cpu_die() does memunmap() and sets 'hv_vp_assist_page[cpu]' to NULL but breaks non-root partitions as hv_cpu_die() doesn't free 'hv_vp_assist_page[cpu]' for them. This causes VP assist page to remain unset after CPU offline/online cycle: $ rdmsr -p 24 0x40000073 10212f001 $ echo 0 > /sys/devices/system/cpu/cpu24/online $ echo 1 > /sys/devices/system/cpu/cpu24/online $ rdmsr -p 24 0x40000073 0 Fix the issue by always writing to HV_X64_MSR_VP_ASSIST_PAGE in hv_cpu_init(). Note, checking 'if (!*hvp)', for root partition is pointless as hv_cpu_die() always sets 'hv_vp_assist_page[cpu]' to NULL (and it's also NULL initially). Note: the fact that 'hv_vp_assist_page[cpu]' is reset to NULL may present a (potential) issue for KVM. While Hyper-V uses CPUHP_AP_ONLINE_DYN stage in CPU hotplug, KVM uses CPUHP_AP_KVM_STARTING which comes earlier in CPU teardown sequence. It is theoretically possible that Enlightened VMCS is still in use. It is unclear if the issue is real and if using KVM with Hyper-V root partition is even possible. While on it, drop the unneeded smp_processor_id() call from hv_cpu_init(). Fixes: e5d9b71 ("x86/hyperv: fix root partition faults when writing to VP assist page MSR") Signed-off-by: Vitaly Kuznetsov <[email protected]> Reviewed-by: Michael Kelley <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Wei Liu <[email protected]>
1 parent e70af8d commit ee68154

File tree

1 file changed

+26
-28
lines changed

1 file changed

+26
-28
lines changed

arch/x86/hyperv/hv_init.c

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static int hyperv_init_ghcb(void)
7777
static int hv_cpu_init(unsigned int cpu)
7878
{
7979
union hv_vp_assist_msr_contents msr = { 0 };
80-
struct hv_vp_assist_page **hvp = &hv_vp_assist_page[smp_processor_id()];
80+
struct hv_vp_assist_page **hvp = &hv_vp_assist_page[cpu];
8181
int ret;
8282

8383
ret = hv_common_cpu_init(cpu);
@@ -87,34 +87,32 @@ static int hv_cpu_init(unsigned int cpu)
8787
if (!hv_vp_assist_page)
8888
return 0;
8989

90-
if (!*hvp) {
91-
if (hv_root_partition) {
92-
/*
93-
* For root partition we get the hypervisor provided VP assist
94-
* page, instead of allocating a new page.
95-
*/
96-
rdmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
97-
*hvp = memremap(msr.pfn <<
98-
HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT,
99-
PAGE_SIZE, MEMREMAP_WB);
100-
} else {
101-
/*
102-
* The VP assist page is an "overlay" page (see Hyper-V TLFS's
103-
* Section 5.2.1 "GPA Overlay Pages"). Here it must be zeroed
104-
* out to make sure we always write the EOI MSR in
105-
* hv_apic_eoi_write() *after* the EOI optimization is disabled
106-
* in hv_cpu_die(), otherwise a CPU may not be stopped in the
107-
* case of CPU offlining and the VM will hang.
108-
*/
90+
if (hv_root_partition) {
91+
/*
92+
* For root partition we get the hypervisor provided VP assist
93+
* page, instead of allocating a new page.
94+
*/
95+
rdmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
96+
*hvp = memremap(msr.pfn << HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT,
97+
PAGE_SIZE, MEMREMAP_WB);
98+
} else {
99+
/*
100+
* The VP assist page is an "overlay" page (see Hyper-V TLFS's
101+
* Section 5.2.1 "GPA Overlay Pages"). Here it must be zeroed
102+
* out to make sure we always write the EOI MSR in
103+
* hv_apic_eoi_write() *after* the EOI optimization is disabled
104+
* in hv_cpu_die(), otherwise a CPU may not be stopped in the
105+
* case of CPU offlining and the VM will hang.
106+
*/
107+
if (!*hvp)
109108
*hvp = __vmalloc(PAGE_SIZE, GFP_KERNEL | __GFP_ZERO);
110-
if (*hvp)
111-
msr.pfn = vmalloc_to_pfn(*hvp);
112-
}
113-
WARN_ON(!(*hvp));
114-
if (*hvp) {
115-
msr.enable = 1;
116-
wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
117-
}
109+
if (*hvp)
110+
msr.pfn = vmalloc_to_pfn(*hvp);
111+
112+
}
113+
if (!WARN_ON(!(*hvp))) {
114+
msr.enable = 1;
115+
wrmsrl(HV_X64_MSR_VP_ASSIST_PAGE, msr.as_uint64);
118116
}
119117

120118
return hyperv_init_ghcb();

0 commit comments

Comments
 (0)