Re: [RFC PATCH v2 22/25] KVM: x86/mmu: Refactor kvm_mmu_invlpg() to allow skipping the gva flush

From: Sean Christopherson

Date: Thu Jul 23 2026 - 21:13:12 EST


On Thu, Jul 23, 2026, Yosry Ahmed wrote:
> On Thu, Jul 23, 2026 at 3:03 PM Sean Christopherson <seanjc@xxxxxxxxxx> wrote:
> >
> > On Thu, Jul 23, 2026, Yosry Ahmed wrote:
> > > > Actually, isn't there a pre-existing over-flush when handling kvm_mmu_invpcid_gva()?
> > > > Oof, and a missed flush?
> > > >
> > > > To fix the over-flush, I think we want this?
> > > >
> > > > diff --git arch/x86/kvm/mmu/mmu.c arch/x86/kvm/mmu/mmu.c
> > > > index 6c13da942bfc..7f3e0eb33b29 100644
> > > > --- arch/x86/kvm/mmu/mmu.c
> > > > +++ arch/x86/kvm/mmu/mmu.c
> > > > @@ -6672,7 +6672,8 @@ void kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_pagewalk *w,
> > > > if (is_noncanonical_invlpg_address(addr, vcpu))
> > > > return;
> > > >
> > > > - kvm_x86_call(flush_tlb_gva)(vcpu, addr);
> > > > + if (roots & KVM_MMU_ROOT_CURRENT)
> > > > + kvm_x86_call(flush_tlb_gva)(vcpu, addr);
> > >
> > > Hmmm why?
> > >
> > > AFAICT, if the gva has a shadow mapping, then the rest of
> > > kvm_mmu_invalidate_addr() will make sure the shadow mapping is
> > > up-to-date and do any necessary TLB flushes in the process. So I am
> > > assuming the flush here is intended to cover some cases where the gva
> > > does not have a shadow mapping. Not sure how this could happen, I
> > > assume we always flush the TLB when a shadow PTE is freed.
> > >
> > > If there are cases where we can have TLB entries but no shadow
> > > mappings, then shouldn't we flush regardless of which cached roots
> > > match the target PCID? I assume if none of the cached roots match the
> > > PCID it's not an issue because KVM will create a new root and flush
> > > the TLB before switching into the new PCID.
> >
> > Gah, I conflated PCIDs and VPIDs.
>
> Disregarding the alleged over-flush, I am actually trying to figure
> out why flush_tlb_gva here is needed in the INVLPG and INVPCID
> emulation paths. I think understanding this will help us figure out
> how to best handle it for INVLPGA.

That emits an actual hardware TLB flush if there are no unsync SPTEs. Everything
below this point:

/* Invalidate shadow pages, whether GPA->GVA or nGPA->GPA. */
if (!mmu->sync_spte)
return;

is specific to unsync SPTEs. __kvm_mmu_invalidate_addr() is one big nop if there
aren't any unsync SPTEs. E.g. before unsync support came along, KVM didn't
intercept INVLPG: a7052897b3bc ("KVM: x86: trap invlpg").

Wwith TDP enabled, KVM definitely needs to flush guest mappings, e.g. if KVM
synthesizes a #PF (which are architecturally guaranteed to flush any relevant
mappings), because KVM isn't controlling GVA=>GPA (obviously). When using
shadow paging, it's less obvious when KVM would need to flush hardware TLBs even
if KVM's SPTEs haven't changed since the last flush. The only things that jumps
to mind are TLB entries that were preserved across a MOV CR3 switch, e.g. global
entries or MOV CR3 with X86_CR3_PCID_NOFLUSH, and the new CR3 contains a stale
mapping (or none at all).