From: David Woodhouse <[email protected]>

KVM_REQ_MMU_FREE_OBSOLETE_ROOTS lives in the request set shared by all
planes of a vCPU. A fast zap (e.g. memslot deletion) invalidates
*every* plane's TDP roots and raises the request once per vCPU, but
whichever plane enters the guest next consumes the shared bit and
frees only its own obsolete roots. The other planes keep an obsolete
root with a valid-looking root.hpa, kvm_mmu_reload() does nothing for
them, and every page fault bails out in is_page_fault_stale() with
RET_PF_RETRY: the vCPU livelocks taking the same EPT violation
forever. Observed with a Windows VSM guest spinning at ~18k EPT
violations/s after a memslot update during boot, the root obsolete
(inv=1 obs=1) and the request already consumed (req=0).

Service every plane twin in kvm_mmu_free_obsolete_roots(). The
inactive twins cannot be running (all planes of a vCPU share one
thread), so their MMUs are stable.

Signed-off-by: David Woodhouse <[email protected]>
Assisted-by: LLM
---
 arch/x86/kvm/mmu/mmu.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 177b2e71bf35..cdebb5c324fe 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -6234,8 +6234,23 @@ static void __kvm_mmu_free_obsolete_roots(struct kvm 
*kvm, struct kvm_mmu *mmu)
 
 void kvm_mmu_free_obsolete_roots(struct kvm_vcpu *vcpu)
 {
-       __kvm_mmu_free_obsolete_roots(vcpu->kvm, &vcpu->arch.root_mmu);
-       __kvm_mmu_free_obsolete_roots(vcpu->kvm, &vcpu->arch.guest_mmu);
+       struct kvm_vcpu *v;
+       int i;
+
+       /*
+        * KVM_REQ_MMU_FREE_OBSOLETE_ROOTS is tracked in the request set
+        * shared by all of the vCPU's planes, so the plane that consumes
+        * the request is not necessarily the plane whose root is obsolete.
+        * Service every plane: the inactive twins cannot be running (all
+        * planes of a vCPU share one thread), so their MMUs are stable.
+        */
+       for (i = 0; i < KVM_MAX_PLANES; i++) {
+               v = vcpu->common->vcpus[i];
+               if (!v)
+                       continue;
+               __kvm_mmu_free_obsolete_roots(v->kvm, &v->arch.root_mmu);
+               __kvm_mmu_free_obsolete_roots(v->kvm, &v->arch.guest_mmu);
+       }
 }
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_mmu_free_obsolete_roots);
 
-- 
2.50.1


Reply via email to