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

