* Re: [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled [not found] <20260723094419.630204-1-pbonzini@redhat.com> @ 2026-07-24 22:36 ` Sean Christopherson 2026-07-25 13:37 ` Paolo Bonzini 2026-07-24 23:42 ` Yosry Ahmed 2026-07-27 19:23 ` Tycho Andersen 2 siblings, 1 reply; 10+ messages in thread From: Sean Christopherson @ 2026-07-24 22:36 UTC (permalink / raw) To: Paolo Bonzini Cc: linux-kernel, kvm, Vitaly Kuznetsov, Alexander Lougovski, Yosry Ahmed +Yosry, who has been digging deep on SVM TLB crud. On Thu, Jul 23, 2026, Paolo Bonzini wrote: > The flush is issued from kvm_hv_vcpu_flush_tlb(), which receives the > cross-CPU requests from the Hyper-V TLB flush hypercalls via a kfifo > and is invoked by the KVM_REQ_HV_TLB_FLUSH request. The mechanism is > the same for both Intel and AMD, and the handler for both vendors is > a simple INVVPID(ADDR)/INVLPGA instruction. > > Because the request is handled on the destination CPU, there is a question > of what happens if the VM is migrated across physical CPUs. In that case, > the INVLPGA instruction would use a stale svm->vmcb->control.asid; but > if anything that might do an *unnecessary* flush (on an asid that's being > used for another VM) and then pre_svm_run() would force a full TLB rebuild. > > So, for lack of better ideas, this patch forces a full ASID bump in > svm_flush_tlb_gva(). To avoid paying the price on Intel and also to > avoid unnecessary loops on AMD, the flush_tlb_gva op now returns whether > it did a full flush or not; kvm_hv_vcpu_flush_tlb() takes note and exits > its loops immediately. While there is an obvious performance impact, > about half of the benefit from Hyper-V tlbflush is preserved (10% vs. 20% > on the SQL Server workload). > > kvm_mmu_invalidate_addr() is the only other caller of the flush_tlb_gva op. > The change would have a performance impact on every intercepted INVLPG and, > for nested SVM, on every L1 INVLPGA. For INVLPGA specifically, this covers > the same suspected issue but for nested hypervisors, so it is correct to > apply the workaround; for INVLPG on shadow paging, instead, the impact > would be stronger and, due to lack of data, for now the use of INVLPGA is > left in place in svm_flush_tlb_gva(). > > Analyzed-by: Vitaly Kuznetsov <vkuznets@redhat.com> > Analyzed-by: Alexander Lougovski <alougovsk@redhat.com> > Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> > --- > arch/x86/include/asm/kvm_host.h | 2 +- > arch/x86/kvm/hyperv.c | 7 ++++--- > arch/x86/kvm/mmu/mmu.c | 2 +- > arch/x86/kvm/svm/svm.c | 27 ++++++++++++++++++++------- > arch/x86/kvm/vmx/main.c | 4 ++-- > arch/x86/kvm/vmx/vmx.c | 2 +- > arch/x86/kvm/vmx/x86_ops.h | 2 +- > 7 files changed, 30 insertions(+), 16 deletions(-) > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index b517257a6315..eca04d4b974e 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -1751,7 +1751,7 @@ struct kvm_x86_ops { > * Can potentially get non-canonical addresses through INVLPGs, which > * the implementation may choose to ignore if appropriate. > */ > - void (*flush_tlb_gva)(struct kvm_vcpu *vcpu, gva_t addr); > + void (*flush_tlb_gva)(struct kvm_vcpu *vcpu, gva_t addr, bool *full); LOL, why on earth are you using an out-param? If we do this at runtime, just return a bool, at least that way we don't have to churn every call-site. But I would much rather handle this by nuking .flush_tlb_gva at setup, e.g. diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 3776cf5382a2..4235331b71a0 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -61,7 +61,7 @@ KVM_X86_OP(flush_tlb_current) KVM_X86_OP_OPTIONAL(flush_remote_tlbs) KVM_X86_OP_OPTIONAL(flush_remote_tlbs_range) #endif -KVM_X86_OP(flush_tlb_gva) +KVM_X86_OP_OPTIONAL(flush_tlb_gva) KVM_X86_OP(flush_tlb_guest) KVM_X86_OP(vcpu_pre_run) KVM_X86_OP(vcpu_run) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 4438ecac9a89..7b1c6391f878 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1978,7 +1978,8 @@ int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu) count = kfifo_out(&tlb_flush_fifo->entries, entries, KVM_HV_TLB_FLUSH_FIFO_SIZE); for (i = 0; i < count; i++) { - if (entries[i] == KVM_HV_TLB_FLUSHALL_ENTRY) + if (entries[i] == KVM_HV_TLB_FLUSHALL_ENTRY || + !kvm_x86_ops.flush_tlb_gva) goto out_flush_all; /* diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index f0144ae8d891..bf16119640dc 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -6555,7 +6555,10 @@ void kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, if (is_noncanonical_invlpg_address(addr, vcpu)) return; - kvm_x86_call(flush_tlb_gva)(vcpu, addr); + if (kvm_x86_ops.flush_tlb_gva) + kvm_x86_call(flush_tlb_gva)(vcpu, addr); + else + kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu); } if (!mmu->sync_spte) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index c46a34aeb3df..9e04f016d939 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -5688,6 +5688,15 @@ static __init int svm_hardware_setup(void) if (!enable_pmu) pr_info("PMU virtualization is disabled\n"); + /* + * INVLPGA has had errata on Genoa and Turin, and even on older + * generations there were reports of Windows BSODs if INVLPGA + * was used for Hyper-V tlbflush. Use it only for shadow paging + * where it seems to be okay. + */ + if (npt_enabled) + svm_x86_ops.flush_tlb_gva = NULL; + svm_set_cpu_caps(); kvm_caps.inapplicable_quirks &= ~KVM_X86_QUIRK_CD_NW_CLEARED; ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled 2026-07-24 22:36 ` [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled Sean Christopherson @ 2026-07-25 13:37 ` Paolo Bonzini 0 siblings, 0 replies; 10+ messages in thread From: Paolo Bonzini @ 2026-07-25 13:37 UTC (permalink / raw) To: Sean Christopherson Cc: Kernel Mailing List, Linux, kvm, Vitaly Kuznetsov, Alexander Lougovski, Yosry Ahmed Il sab 25 lug 2026, 00:36 Sean Christopherson <seanjc@google.com> ha scritto: > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > > index b517257a6315..eca04d4b974e 100644 > > --- a/arch/x86/include/asm/kvm_host.h > > +++ b/arch/x86/include/asm/kvm_host.h > > @@ -1751,7 +1751,7 @@ struct kvm_x86_ops { > > * Can potentially get non-canonical addresses through INVLPGs, which > > * the implementation may choose to ignore if appropriate. > > */ > > - void (*flush_tlb_gva)(struct kvm_vcpu *vcpu, gva_t addr); > > + void (*flush_tlb_gva)(struct kvm_vcpu *vcpu, gva_t addr, bool *full); > > LOL, why on earth are you using an out-param? If we do this at runtime, just > return a bool, at least that way we don't have to churn every call-site. To be precise the churn is only one call site out of two, and in fact it's the one which is mangled even more by your proposal below. :) More seriously, I used an out parameter because returning 0/1 or false/true is impenetrable for the Hyper-V call site, while 0/-EOPNOTSUPP (i.e. do not flush at all on NPT) would force changes in kvm_mmu_invalidate_addr(). So, instead of making things good for one call site at the expense of the other, the optional out param is more self documenting in svm.c and is either good or bearable for the callers: Hyper-V doesn't care either way (it doesn't e.g. need the return value within an "if" or "while"), and kvm_mmu_invalidate_addr() just gets an extra NULL argument. Overall it's a matter of taste, I understand if you're not convinced but I can say it wasn't out of a whim. In your defense maybe I should have put this argument in the commit message somewhere? AI also complained, but I shelved it because "Sean surely has better taste than the AI"... :) > But I would much rather handle this by nuking .flush_tlb_gva at setup, e.g. > > diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c > index f0144ae8d891..bf16119640dc 100644 > --- a/arch/x86/kvm/mmu/mmu.c > +++ b/arch/x86/kvm/mmu/mmu.c > @@ -6555,7 +6555,10 @@ void kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, > if (is_noncanonical_invlpg_address(addr, vcpu)) > return; > > - kvm_x86_call(flush_tlb_gva)(vcpu, addr); > + if (kvm_x86_ops.flush_tlb_gva) > + kvm_x86_call(flush_tlb_gva)(vcpu, addr); > + else > + kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu); > } > > if (!mmu->sync_spte) This is a variation on the -EOPNOTSUPP convention, for which I didn't like having this "else" in the caller that doesn't already have a full-flush fallback. If you insist, I guess I would be fine with adding a kvm_flush_tlb_gva() wrapper, use it in mmu.c, and check for NULL in hyperv.c... but in the end is it really better than the out param version? In fact I am not even sure it is better than returning -EOPNOTSUPP. From the svm.c point of view it certainly is very clean, but for everyone else it's super easy to forget about checking the callback; and you don't even have __must_check to save you. Paolo ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled [not found] <20260723094419.630204-1-pbonzini@redhat.com> 2026-07-24 22:36 ` [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled Sean Christopherson @ 2026-07-24 23:42 ` Yosry Ahmed 2026-07-24 23:50 ` Yosry Ahmed 2026-07-25 13:32 ` Paolo Bonzini 2026-07-27 19:23 ` Tycho Andersen 2 siblings, 2 replies; 10+ messages in thread From: Yosry Ahmed @ 2026-07-24 23:42 UTC (permalink / raw) To: Paolo Bonzini; +Cc: linux-kernel, kvm, Vitaly Kuznetsov, Alexander Lougovski On Thu, Jul 23, 2026 at 2:44 AM Paolo Bonzini <pbonzini@redhat.com> wrote: > > Red Hat is seeing multiple reports of Windows memory corruptions > (and consequent BSODs) with hv-tlbflush=on, on AMD processors only. > The crashes, while extremely rare, happen even with a stock configuration, > but with Driver Verifier enabled they can be detected after approximately > 200 VM hours. In particular, Alexander Lougovski measured the following: > > - on AMD Turin, 15 crashes in 3300 VM hours > > - on AMD Milan, 2 crashes in 500 VM hours (there are fewer hours > here due to the host being smaller) > > - on Intel Sapphire Rapids, 0 crashes in 8000 VM hours > > - on AMD Turin with full TLB flush (not exactly this patch but > similar), no crashes in ~2 weeks of run time which should also > be ~7000 VM hours > > For Turin, the microcode version was 0x0b002162, which (assuming > this is the same issue) should not be affected by the problem listed in > https://knowledge.broadcom.com/external/article/419026/bsod-on-virtual-machines-running-on-amd.html; > on the other hand that problem should not apply to earlier processors. > AMD has not provided any information or analysis yet, and when we asked > we didn't know yet that it reproduced on Milan as well. > > As to the workload, Alexander threw more or less everything at the same > time at the VM: > > - a full Windows Defender scan every 30 minutes > > - a disk I/O job > > - a loop doing repeated mmap of system files (mostly to hope that > it triggers some consistency check in the Windows memory manager) > > - SQL Express 2022 + StressDB (1.6M rows), with the host doing queries > (75% write/25% read) via sqlcmd > > Driver Verifier is able to detect BSODs more or less at the same time as > the pages are freed. They mostly happen in the Windows Defender filter > driver, but occasionally also in the networking stack (e.g., afd.sys) > or elsewhere in the filesystem stack (e.g., fltmgr.sys). > > The flush is issued from kvm_hv_vcpu_flush_tlb(), which receives the > cross-CPU requests from the Hyper-V TLB flush hypercalls via a kfifo > and is invoked by the KVM_REQ_HV_TLB_FLUSH request. The mechanism is > the same for both Intel and AMD, and the handler for both vendors is > a simple INVVPID(ADDR)/INVLPGA instruction. > > Because the request is handled on the destination CPU, there is a question > of what happens if the VM is migrated across physical CPUs. In that case, > the INVLPGA instruction would use a stale svm->vmcb->control.asid; but > if anything that might do an *unnecessary* flush (on an asid that's being > used for another VM) and then pre_svm_run() would force a full TLB rebuild. > > So, for lack of better ideas, this patch forces a full ASID bump in > svm_flush_tlb_gva(). To avoid paying the price on Intel and also to > avoid unnecessary loops on AMD, the flush_tlb_gva op now returns whether > it did a full flush or not; kvm_hv_vcpu_flush_tlb() takes note and exits > its loops immediately. While there is an obvious performance impact, > about half of the benefit from Hyper-V tlbflush is preserved (10% vs. 20% > on the SQL Server workload). > > kvm_mmu_invalidate_addr() is the only other caller of the flush_tlb_gva op. > The change would have a performance impact on every intercepted INVLPG and, > for nested SVM, on every L1 INVLPGA. For INVLPGA specifically, this covers > the same suspected issue but for nested hypervisors, so it is correct to > apply the workaround; for INVLPG on shadow paging, instead, the impact > would be stronger and, due to lack of data, for now the use of INVLPGA is > left in place in svm_flush_tlb_gva(). > > Analyzed-by: Vitaly Kuznetsov <vkuznets@redhat.com> > Analyzed-by: Alexander Lougovski <alougovsk@redhat.com> > Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> [..] > +static void svm_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva, bool *full) > +{ > + struct vcpu_svm *svm = to_svm(vcpu); > + > + /* > + * INVLPGA has had errata on Genoa and Turin, and even on older > + * generations there were reports of Windows BSODs if INVLPGA > + * was used for Hyper-V tlbflush. Use it only for shadow paging > + * where it seems to be okay. Is this an actual errata documented by AMD, or is this just an empirical observation? I ask because the APM says: --- The input address is always interpreted as a guest virtual address, so INVLPGA is typically meaningful only when used with shadow page tables; it does not provide a means to invalidate a nested translation by guest physical address --- While this is terrible wording, it seems like KVM should *not* be using INVLPGA when TDP is enabled. Looks like kvm_mmu_invalidate_addr() might be doing the right thing, but it seems like kvm_hv_vcpu_flush_tlb() shouldn't be calling flush_tlb_gva() with TDP enabled to begin with, at least on AMD? I don't have enough context about what kvm_hv_vcpu_flush_tlb() is doing to know if flush_tlb_gva() makes sense on Intel. But at least on AMD, looks like it should always just do a full ASID flush (since it falls back to a full flush with TDP disabled anyway)? So maybe something like: int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu) { ... if (AMD CPU) goto out_flush_all; ... } I also love Sean's idea, I think it's good to harden against this by nullifying flush_tlb_gva, and maybe add a helper that does the fallback: static void kvm_vcpu_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva) { if (kvm_x86_ops.flush_tlb_gva) kvm_x86_call(flush_tlb_gva)(vcpu, addr); else kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu); } Hmm actually we check KVM_REQ_TLB_FLUSH_GUEST before KVM_REQ_HV_TLB_FLUSH, so maybe just call kvm_vcpu_flush_tlb_guest() directly for the fallback: static void kvm_vcpu_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva) { if (kvm_x86_ops.flush_tlb_gva) kvm_x86_call(flush_tlb_gva)(vcpu, addr); else kvm_vcpu_flush_tlb_guest(vcpu); } And if we go this route, I think we can key off the presence of flush_tlb_gva in kvm_hv_vcpu_flush_tlb() instead of checking for an AMD CPU. We can probably break it down into a stable-friendly fix that just jumps to out_flush_all on AMD CPUs, then the hardening on top. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled 2026-07-24 23:42 ` Yosry Ahmed @ 2026-07-24 23:50 ` Yosry Ahmed 2026-07-25 13:32 ` Paolo Bonzini 1 sibling, 0 replies; 10+ messages in thread From: Yosry Ahmed @ 2026-07-24 23:50 UTC (permalink / raw) To: Paolo Bonzini; +Cc: linux-kernel, kvm, Vitaly Kuznetsov, Alexander Lougovski > I also love Sean's idea, I think it's good to harden against this by > nullifying flush_tlb_gva, and maybe add a helper that does the > fallback: > > static void kvm_vcpu_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva) > { > if (kvm_x86_ops.flush_tlb_gva) > kvm_x86_call(flush_tlb_gva)(vcpu, addr); > else > kvm_make_request(KVM_REQ_TLB_FLUSH_GUEST, vcpu); > } > > Hmm actually we check KVM_REQ_TLB_FLUSH_GUEST before > KVM_REQ_HV_TLB_FLUSH, so maybe just call kvm_vcpu_flush_tlb_guest() > directly for the fallback: > > static void kvm_vcpu_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t gva) > { > if (kvm_x86_ops.flush_tlb_gva) > kvm_x86_call(flush_tlb_gva)(vcpu, addr); > else > kvm_vcpu_flush_tlb_guest(vcpu); > } > > And if we go this route, I think we can key off the presence of > flush_tlb_gva in kvm_hv_vcpu_flush_tlb() instead of checking for an > AMD CPU. We can probably break it down into a stable-friendly fix that > just jumps to out_flush_all on AMD CPUs, then the hardening on top. Although it could be less crud if we just made svm_flush_tlb_gva() do the fallback. kvm_hv_vcpu_flush_tlb() would need to key-off AMD CPU though instead of the presence of flush_tlb_gva. Pick your poison, I guess. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled 2026-07-24 23:42 ` Yosry Ahmed 2026-07-24 23:50 ` Yosry Ahmed @ 2026-07-25 13:32 ` Paolo Bonzini 2026-07-25 21:33 ` Yosry Ahmed 1 sibling, 1 reply; 10+ messages in thread From: Paolo Bonzini @ 2026-07-25 13:32 UTC (permalink / raw) To: Yosry Ahmed Cc: Kernel Mailing List, Linux, kvm, Vitaly Kuznetsov, Alexander Lougovski Il sab 25 lug 2026, 01:44 Yosry Ahmed <yosry@kernel.org> ha scritto: > > + /* > > + * INVLPGA has had errata on Genoa and Turin, and even on older > > + * generations there were reports of Windows BSODs if INVLPGA > > + * was used for Hyper-V tlbflush. Use it only for shadow paging > > + * where it seems to be okay. > > Is this an actual errata documented by AMD, or is this just an > empirical observation? There is the VMware knowledge base in the commit message that requires new microcode: > > For Turin, the microcode version was 0x0b002162, which (assuming > > this is the same issue) should not be affected by the problem listed in > > https://knowledge.broadcom.com/external/article/419026/bsod-on-virtual-machines-running-on-amd.html; > > on the other hand that problem should not apply to earlier processors. > > AMD has not provided any information or analysis yet, and when we asked > > we didn't know yet that it reproduced on Milan as well. and I interpreted that as an erratum. But we reproduced it also on Milan and with supposedly fixed microcode. > I ask because the APM says: > --- > The input address is always interpreted as a guest virtual address, so > INVLPGA is typically meaningful only when used with shadow page > tables; it does not provide a means to invalidate a nested translation > by guest physical address > --- > > While this is terrible wording, it seems like KVM should *not* be > using INVLPGA when TDP is enabled While it is certainly an odd case, here the guest has requested to do an invalidation by GVA on its behalf, so INVLPGA should have worked. "Not typically meaningful" is a friendly hint to read the manual twice, but reality seems to be more like "doesn't actually flush the right entries" when NPT is in use. Especially since Intel has INVVPID for the exact same operation and it works just fine. Paolo ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled 2026-07-25 13:32 ` Paolo Bonzini @ 2026-07-25 21:33 ` Yosry Ahmed 0 siblings, 0 replies; 10+ messages in thread From: Yosry Ahmed @ 2026-07-25 21:33 UTC (permalink / raw) To: Paolo Bonzini Cc: Kernel Mailing List, Linux, kvm, Vitaly Kuznetsov, Alexander Lougovski On Sat, Jul 25, 2026 at 6:32 AM Paolo Bonzini <pbonzini@redhat.com> wrote: > > Il sab 25 lug 2026, 01:44 Yosry Ahmed <yosry@kernel.org> ha scritto: > > > + /* > > > + * INVLPGA has had errata on Genoa and Turin, and even on older > > > + * generations there were reports of Windows BSODs if INVLPGA > > > + * was used for Hyper-V tlbflush. Use it only for shadow paging > > > + * where it seems to be okay. > > > > Is this an actual errata documented by AMD, or is this just an > > empirical observation? > > There is the VMware knowledge base in the commit message that requires > new microcode: > > > > For Turin, the microcode version was 0x0b002162, which (assuming > > > this is the same issue) should not be affected by the problem listed in > > > https://knowledge.broadcom.com/external/article/419026/bsod-on-virtual-machines-running-on-amd.html; > > > on the other hand that problem should not apply to earlier processors. > > > AMD has not provided any information or analysis yet, and when we asked > > > we didn't know yet that it reproduced on Milan as well. > > and I interpreted that as an erratum. But we reproduced it also on > Milan and with supposedly fixed microcode. > > > I ask because the APM says: > > --- > > The input address is always interpreted as a guest virtual address, so > > INVLPGA is typically meaningful only when used with shadow page > > tables; it does not provide a means to invalidate a nested translation > > by guest physical address > > --- > > > > While this is terrible wording, it seems like KVM should *not* be > > using INVLPGA when TDP is enabled > > While it is certainly an odd case, here the guest has requested to do > an invalidation by GVA on its behalf, so INVLPGA should have worked. > > "Not typically meaningful" is a friendly hint to read the manual > twice, but reality seems to be more like "doesn't actually flush the > right entries" when NPT is in use. Especially since Intel has INVVPID > for the exact same operation and it works just fine. Yeah I agree that it makes sense that INVLPGA should work if we are just flushing a GVA on behalf of the guest (e.g. guest making a hypercall instead of INVLPG). I think we probably need clarification from AMD about what the intention is. Is INVLPGA expected to be broken when NPT is enabled (in which case the wording in the APM needs fixing), or is INVLPGA expected to work but is actually broken. IIUC the erratum you referred to should already be fixed with the new microcode, so maybe there's another problem with INVLPGA? The third possibility is that INVLPGA works as intended but the Hyper-V code in KVM is broken in some other way. I am not sure if we can ask, or if people at Microsoft can answer, but it would definitely help to know how Hyper-V handles these cases. Does it actually use INVLPGA to flush GVAs on behalf of the guest with NPT enabeld? If yes, there's a good chance it's KVM that's broken here? ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled [not found] <20260723094419.630204-1-pbonzini@redhat.com> 2026-07-24 22:36 ` [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled Sean Christopherson 2026-07-24 23:42 ` Yosry Ahmed @ 2026-07-27 19:23 ` Tycho Andersen 2026-07-27 19:58 ` Yosry Ahmed 2026-07-28 17:13 ` Alexander Lougovski 2 siblings, 2 replies; 10+ messages in thread From: Tycho Andersen @ 2026-07-27 19:23 UTC (permalink / raw) To: Paolo Bonzini Cc: linux-kernel, kvm, Vitaly Kuznetsov, Alexander Lougovski, Tom Lendacky, Borislav Petkov Hi all, On Thu, Jul 23, 2026 at 11:44:19AM +0200, Paolo Bonzini wrote: > As to the workload, Alexander threw more or less everything at the same > time at the VM: > > - a full Windows Defender scan every 30 minutes > > - a disk I/O job > > - a loop doing repeated mmap of system files (mostly to hope that > it triggers some consistency check in the Windows memory manager) > > - SQL Express 2022 + StressDB (1.6M rows), with the host doing queries > (75% write/25% read) via sqlcmd Can you share the code for the mmap + disk io + DB content generator? We're looking at this and would like to reproduce. Thanks, Tycho ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled 2026-07-27 19:23 ` Tycho Andersen @ 2026-07-27 19:58 ` Yosry Ahmed 2026-07-28 17:13 ` Alexander Lougovski 1 sibling, 0 replies; 10+ messages in thread From: Yosry Ahmed @ 2026-07-27 19:58 UTC (permalink / raw) To: Tycho Andersen, Paolo Bonzini Cc: linux-kernel, kvm, Vitaly Kuznetsov, Alexander Lougovski, Tom Lendacky, Borislav Petkov, Sean Christopherson On Mon, Jul 27, 2026 at 12:23 PM Tycho Andersen <tycho@kernel.org> wrote: > > Hi all, > > On Thu, Jul 23, 2026 at 11:44:19AM +0200, Paolo Bonzini wrote: > > As to the workload, Alexander threw more or less everything at the same > > time at the VM: > > > > - a full Windows Defender scan every 30 minutes > > > > - a disk I/O job > > > > - a loop doing repeated mmap of system files (mostly to hope that > > it triggers some consistency check in the Windows memory manager) > > > > - SQL Express 2022 + StressDB (1.6M rows), with the host doing queries > > (75% write/25% read) via sqlcmd > > Can you share the code for the mmap + disk io + DB content generator? > > We're looking at this and would like to reproduce. Not sure if this is relevant, but I see that hyperv_tlb_flush is flaky with npt=0 on Turin at the tip of kvm-x86/next (commit 567329869b9c7). It's not likely because the problem fixed by this patch happens specifically with npt=1 and not npt=0 AFAICT, but it is a weird coincidence :) Maybe something is wrong in the Hyper-V code that manifests differently with npt=0/1? ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled 2026-07-27 19:23 ` Tycho Andersen 2026-07-27 19:58 ` Yosry Ahmed @ 2026-07-28 17:13 ` Alexander Lougovski 2026-07-28 21:34 ` Tycho Andersen 1 sibling, 1 reply; 10+ messages in thread From: Alexander Lougovski @ 2026-07-28 17:13 UTC (permalink / raw) To: tycho Cc: Alexander Lougovski, bp, kvm, linux-kernel, pbonzini, thomas.lendacky, vkuznets On Mon, Jul 27, 2026 at 01:23:03PM -0600, Tycho Andersen wrote: > Can you share the code for the mmap + disk io + DB content generator? > > We're looking at this and would like to reproduce. Hi Tycho, Sure, here's everything below. The setup is a Windows Server 2022 guest on QEMU/KVM with Driver Verifier enabled (/standard /all, which includes Special Pool). All three workloads run concurrently inside the guest. 1) Memory-mapped file workload (PowerShell, runs as a scheduled task) Two concurrent background jobs, each in an infinite loop: pick a random system DLL, read it into a byte array, create a memory-mapped file from it, touch pages through the view accessor, then dispose. Every 50 iterations, GC.Collect() forces the CLR to finalize all the disposed mappings at once, which triggers a burst of PTE teardowns in the Windows memory manager - in theory that should put some pressure on the TLB. --- 8< --- workload-1582.ps1 --- $ErrorActionPreference = 'Stop' $logFile = "C:\drivers\workload-1582-errors.log" $files = @( "$env:SystemRoot\System32\ntdll.dll", "$env:SystemRoot\System32\kernel32.dll", "$env:SystemRoot\System32\user32.dll", "$env:SystemRoot\System32\advapi32.dll", "$env:SystemRoot\System32\ole32.dll", "$env:SystemRoot\System32\shell32.dll", "$env:SystemRoot\System32\comctl32.dll", "$env:SystemRoot\System32\msvcrt.dll" ) $block = { param($files, $logFile) $i = 0 while ($true) { $f = $files[(Get-Random -Maximum $files.Count)] try { $bytes = [System.IO.File]::ReadAllBytes($f) $ms = [System.IO.MemoryStream]::new($bytes) $mmf = [System.IO.MemoryMappedFiles.MemoryMappedFile]::CreateFromFile( $f, [System.IO.FileMode]::Open, $null, 0, [System.IO.MemoryMappedFiles.MemoryMappedFileAccess]::Read) $view = $mmf.CreateViewAccessor(0, 0, [System.IO.MemoryMappedFiles.MemoryMappedFileAccess]::Read) for ($p = 0; $p -lt [Math]::Min($view.Capacity, 65536); $p += 4096) { $null = $view.ReadByte($p) } $view.Dispose() $mmf.Dispose() $ms.Dispose() } catch { "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') iter=$i file=$f error=$($_.Exception.Message)" | Out-File -Append $logFile } $i++ if ($i % 50 -eq 0) { try { [GC]::Collect() [GC]::WaitForPendingFinalizers() } catch { "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') iter=$i GC error=$($_.Exception.Message)" | Out-File -Append $logFile } } } } "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') Workload1582 starting" | Out-File -Append $logFile 1..2 | ForEach-Object { Start-Job -ScriptBlock $block -ArgumentList (,$files), $logFile } while ($true) { $jobs = Get-Job $failed = $jobs | Where-Object { $_.State -eq 'Failed' } if ($failed) { foreach ($j in $failed) { "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') Job $($j.Id) FAILED: $($j.ChildJobs[0].JobStateInfo.Reason)" | Out-File -Append $logFile Remove-Job $j -Force Start-Job -ScriptBlock $block -ArgumentList (,$files), $logFile } } Start-Sleep -Seconds 60 } --- 8< --- Register as a startup task: schtasks /create /tn Workload1582 /sc onstart /ru SYSTEM /f ^ /tr "powershell.exe -ExecutionPolicy Bypass -File C:\workload-1582.ps1" 2) Disk I/O (DiskSpd, runs as a scheduled task) Single-threaded, 32 outstanding I/Os, 64K block size, 50/50 read/write, 128MB file, loop forever. --- 8< --- diskspd-loop.cmd --- :loop C:\drivers\diskspd.exe -d604800 -t1 -o32 -b64K -w50 -Sh -c128M C:\diskspd-io.dat goto loop --- 8< --- DiskSpd binary: https://github.com/microsoft/diskspd/releases Register: schtasks /create /tn DiskSpdIO /sc onstart /ru SYSTEM /f ^ /tr "C:\drivers\diskspd-loop.cmd" 3) SQL stress (host-side script, drives queries into the guest) SQL Server Express 2022 runs inside the guest. The database (StressDB, SIMPLE recovery model) has a single table with ~1.6M rows: RandomData ( ID INT IDENTITY PRIMARY KEY, Col1 UNIQUEIDENTIFIER, Col2 NVARCHAR(100), Col3 NVARCHAR(100), Col4 NVARCHAR(100), Col5 DATETIME2, Col6 FLOAT, Col7 BIGINT, Col8 VARBINARY(200) ) In our setup the database is baked into the golden VM image, so we don't have a standalone creation script. To reproduce, seed random data and double via INSERT...SELECT until you reach ~1.6M rows. The exact count doesn't matter much — it just needs to be larger than the SQL Express buffer pool (1.4 GB) so that queries cause constant cache misses and disk I/O. The host runs 3 sqlcmd streams per VM, 75% writes / 25% reads: --- 8< --- sql-stress-75w.sh --- #!/usr/bin/env bash SQLCMD=/opt/mssql-tools18/bin/sqlcmd query_stream() { local TARGET=$1 while true; do case $((RANDOM % 4)) in 0) Q="SET NOCOUNT ON; DECLARE @s INT = ABS(CHECKSUM(NEWID())) % 2800000 + 1; UPDATE StressDB.dbo.RandomData SET Col2 = REPLICATE(N'X', 90 + ABS(CHECKSUM(NEWID())) % 10), Col3 = REPLICATE(N'Y', 90 + ABS(CHECKSUM(NEWID())) % 10), Col5 = SYSDATETIME(), Col7 = ABS(CHECKSUM(NEWID())) WHERE ID BETWEEN @s AND @s + 50000" ;; 1) Q="SET NOCOUNT ON; DECLARE @s INT = ABS(CHECKSUM(NEWID())) % 2800000 + 1; UPDATE StressDB.dbo.RandomData SET Col4 = REPLICATE(N'Z', 90 + ABS(CHECKSUM(NEWID())) % 10), Col6 = RAND(CHECKSUM(NEWID())) * 1000, Col8 = CAST(REPLICATE(0x42, 100 + ABS(CHECKSUM(NEWID())) % 100) AS VARBINARY(200)) WHERE ID BETWEEN @s AND @s + 50000" ;; 2) Q="SET NOCOUNT ON; DECLARE @s INT = ABS(CHECKSUM(NEWID())) % 2800000 + 1; UPDATE StressDB.dbo.RandomData SET Col2 = REPLICATE(N'W', 90 + ABS(CHECKSUM(NEWID())) % 10), Col5 = SYSDATETIME(), Col7 = ABS(CHECKSUM(NEWID())), Col8 = CAST(REPLICATE(0x43, 150) AS VARBINARY(200)) WHERE ID BETWEEN @s AND @s + 50000; CHECKPOINT" ;; 3) Q="SET NOCOUNT ON; DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS; CHECKPOINT; SELECT TOP 5000 ID, Col2, Col3, Col4, Col8 FROM StressDB.dbo.RandomData WITH (NOLOCK) WHERE Col7 > ABS(CHECKSUM(NEWID())) % 2000000000 ORDER BY Col5 DESC" ;; esac $SQLCMD -S "$TARGET" -U sa -P 'TestPass123!' -C -Q "$Q" -t 120 > /dev/null 2>&1 done } echo "Starting 3 streams per VM (42 VMs = 126 streams)..." echo "75% writes (cases 0,1,2): UPDATE 50K rows with wide columns + CHECKPOINT on case 2" echo "25% reads (case 3): DROPCLEANBUFFERS + CHECKPOINT + table scan" for N in $(seq 1 42); do IP="192.168.100.$((10 + N))" query_stream "$IP,1433" & query_stream "$IP,1433" & query_stream "$IP,1433" & done wait --- 8< --- On top of all that, Windows Defender runs a full scan of all drives every 30 minutes via a scheduled task. Al ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled 2026-07-28 17:13 ` Alexander Lougovski @ 2026-07-28 21:34 ` Tycho Andersen 0 siblings, 0 replies; 10+ messages in thread From: Tycho Andersen @ 2026-07-28 21:34 UTC (permalink / raw) To: Alexander Lougovski Cc: bp, kvm, linux-kernel, pbonzini, thomas.lendacky, vkuznets Hi Alexander, On Tue, Jul 28, 2026 at 07:13:56PM +0200, Alexander Lougovski wrote: > On Mon, Jul 27, 2026 at 01:23:03PM -0600, Tycho Andersen wrote: > > Can you share the code for the mmap + disk io + DB content generator? > > > > We're looking at this and would like to reproduce. > > Hi Tycho, > > Sure, here's everything below. Thanks for this, I think I've got everything set up the way you've described on top of 7.2-rc5. One question, > query_stream() { > local TARGET=$1 > while true; do > case $((RANDOM % 4)) in > 0) Q="SET NOCOUNT ON; DECLARE @s INT = ABS(CHECKSUM(NEWID())) % 2800000 + 1; UPDATE StressDB.dbo.RandomData SET Col2 = REPLICATE(N'X', 90 + ABS(CHECKSUM(NEWID())) % 10), Col3 = REPLICATE(N'Y', 90 + ABS(CHECKSUM(NEWID())) % 10), Col5 = SYSDATETIME(), Col7 = ABS(CHECKSUM(NEWID())) WHERE ID BETWEEN @s AND @s + 50000" ;; my LLM complained about the '% 2800000', looks like it's selecting from 1..2.8M in a 1.6M table, so the updates above 1.6M don't affect any rows. I'll leave these grinding for now, I'm trying to scare up more hardware to run more copies since it's so rare. Tycho ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-28 21:34 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260723094419.630204-1-pbonzini@redhat.com>
2026-07-24 22:36 ` [PATCH] KVM: SVM: make svm_flush_tlb_gva do a full asid flush if NPT enabled Sean Christopherson
2026-07-25 13:37 ` Paolo Bonzini
2026-07-24 23:42 ` Yosry Ahmed
2026-07-24 23:50 ` Yosry Ahmed
2026-07-25 13:32 ` Paolo Bonzini
2026-07-25 21:33 ` Yosry Ahmed
2026-07-27 19:23 ` Tycho Andersen
2026-07-27 19:58 ` Yosry Ahmed
2026-07-28 17:13 ` Alexander Lougovski
2026-07-28 21:34 ` Tycho Andersen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox