Re: [PATCH] KVM: nVMX: Only update last_vpid on a successful nested VM-Enter

From: Sean Christopherson

Date: Wed Jul 22 2026 - 17:43:05 EST


On Fri, Jul 17, 2026, Yosry Ahmed wrote:
> ---
> arch/x86/kvm/vmx/nested.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
> index b5460de4b1a72..0a4ea410b0483 100644
> --- a/arch/x86/kvm/vmx/nested.c
> +++ b/arch/x86/kvm/vmx/nested.c
> @@ -2818,8 +2818,6 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
> if (kvm_caps.has_tsc_control)
> vmcs_write64(TSC_MULTIPLIER, vcpu->arch.tsc_scaling_ratio);
>
> - nested_vmx_transition_tlb_flush(vcpu, vmcs12, true);
> -
> if (nested_cpu_has_ept(vmcs12))
> nested_ept_init_mmu_context(vcpu);
>
> @@ -3739,6 +3737,8 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
> vmx_start_preemption_timer(vcpu, timer_value);
> }
>
> + nested_vmx_transition_tlb_flush(vcpu, vmcs12, true);

Hmm, so the SDM doesn't explicitly say _when_ TLB flushes happen, but I suspect
this doesn't match how hardware behaves. My guess is that any TLB flushes happen
once VM-Enter has gotten past the VM-Fail consistency checks, i.e. once a VM-Exit
is guaranteed.

The SDM doesn't actually say anything about VM-Enter, so I don't think KVM *must*
implement *that* specific behavior, but I do think we should leave the call to
nested_vmx_transition_tlb_flush() where it's at, and instead service the local
pending flushes in the pseudo-VM-Exit path. Because the other way the TLB flushes
can be queued during VM-Enter is via the MSR load lists:

If any MSR is being loaded in such a way that would architecturally require
a TLB flush, the TLBs are updated so that, after VM entry, the logical
processor will not use any translations that were cached before the transition.

E.g. if L1 successfully loads one or more MTRRs on VM-Enter to L2[*], then fails
on a subsequent MSR, architecturally I believe L2 TLB entries are guaranteed to
be flushed.

I'm speculatingly heavily on all of this, but even if I'm wrong (or it's uarch-
specific behavior), explicitly servicing pending flushes in the VM-Exit(ish) path
feels safe in the long run:

diff --git arch/x86/kvm/vmx/nested.c arch/x86/kvm/vmx/nested.c
index 3266c63046ee..49aeecc2f093 100644
--- arch/x86/kvm/vmx/nested.c
+++ arch/x86/kvm/vmx/nested.c
@@ -3760,6 +3760,14 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
vmentry_fail_vmexit_guest_mode:
if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING)
vcpu->arch.tsc_offset -= vmcs12->tsc_offset;
+
+ /*
+ * Handle any TLB flush requests that were queued for L2 if KVM made it
+ * far enough along to switch to L2 context. Note, loading host state
+ * will generate any flushes for L1 required by VM-Exit.
+ */
+ kvm_service_local_tlb_flush_requests(vcpu);
+
leave_guest_mode(vcpu);

vmentry_fail_vmexit:


[*] https://lore.kernel.org/all/20260717230542.3555587-4-jmattson@xxxxxxxxxx

> +
> /*
> * Note no nested_vmx_succeed or nested_vmx_fail here. At this point
> * we are no longer running L1, and VMLAUNCH/VMRESUME has not yet
>
> base-commit: 6bc96b971766fbbbbdd9fb2642cedacaf02da957
> --
> 2.55.0.229.g6434b31f56-goog
>