mbox series

[0/5] Fix wrong gfn range of tlb flushing with range

Message ID cover.1656039275.git.houwenlong.hwl@antgroup.com (mailing list archive)
Headers show
Series Fix wrong gfn range of tlb flushing with range | expand

Message

Hou Wenlong June 24, 2022, 3:36 a.m. UTC
Commit c3134ce240eed
("KVM: Replace old tlb flush function with new one to flush a specified range.")
replaces old tlb flush function with kvm_flush_remote_tlbs_with_address()
to do tlb flushing. However, the gfn range of tlb flushing is wrong in
some cases. E.g., when a spte is dropped, the start gfn of tlb flushing
should be the gfn of spte not the base gfn of SP which contains the spte.
So this patchset would fix them and do some cleanups.

Hou Wenlong (5):
  KVM: x86/mmu: Fix wrong gfn range of tlb flushing in
    validate_direct_spte()
  KVM: x86/mmu: Fix wrong gfn range of tlb flushing in
    kvm_set_pte_rmapp()
  KVM: x86/mmu: Reduce gfn range of tlb flushing in
    tdp_mmu_map_handle_target_level()
  KVM: x86/mmu: Fix wrong start gfn of tlb flushing with range
  KVM: x86/mmu: Use 1 as the size of gfn range for tlb flushing in
    FNAME(invlpg)()

 arch/x86/kvm/mmu/mmu.c         | 15 +++++++++------
 arch/x86/kvm/mmu/paging_tmpl.h |  2 +-
 arch/x86/kvm/mmu/tdp_mmu.c     |  4 ++--
 3 files changed, 12 insertions(+), 9 deletions(-)

--
2.31.1

Comments

Sean Christopherson June 24, 2022, 11:06 p.m. UTC | #1
On Fri, Jun 24, 2022, Hou Wenlong wrote:
> Commit c3134ce240eed
> ("KVM: Replace old tlb flush function with new one to flush a specified range.")
> replaces old tlb flush function with kvm_flush_remote_tlbs_with_address()
> to do tlb flushing. However, the gfn range of tlb flushing is wrong in
> some cases. E.g., when a spte is dropped, the start gfn of tlb flushing

Heh, "some" cases.  Looks like KVM is wrong on 7 of 15 cases.  And IIRC, there
were already several rounds of fixes due to passing "end" instead of "nr_pages".

Patches look ok on a quick read through, but I'd have to stare a bunch more to
be confident.

Part of me wonders if we should just revert the whole thing and then only reintroduce
range-based flushing with proper testing and maybe even require performance numbers
to justify the benefits.  Give that almost 50% of the users are broken, it's pretty
obvious that no one running KVM actually tests the behavior.

> should be the gfn of spte not the base gfn of SP which contains the spte.
> So this patchset would fix them and do some cleanups.
> 
> Hou Wenlong (5):
>   KVM: x86/mmu: Fix wrong gfn range of tlb flushing in
>     validate_direct_spte()
>   KVM: x86/mmu: Fix wrong gfn range of tlb flushing in
>     kvm_set_pte_rmapp()
>   KVM: x86/mmu: Reduce gfn range of tlb flushing in
>     tdp_mmu_map_handle_target_level()
>   KVM: x86/mmu: Fix wrong start gfn of tlb flushing with range
>   KVM: x86/mmu: Use 1 as the size of gfn range for tlb flushing in
>     FNAME(invlpg)()
> 
>  arch/x86/kvm/mmu/mmu.c         | 15 +++++++++------
>  arch/x86/kvm/mmu/paging_tmpl.h |  2 +-
>  arch/x86/kvm/mmu/tdp_mmu.c     |  4 ++--
>  3 files changed, 12 insertions(+), 9 deletions(-)
> 
> --
> 2.31.1
>
Paolo Bonzini June 25, 2022, 9:13 a.m. UTC | #2
On 6/25/22 01:06, Sean Christopherson wrote:
>> ("KVM: Replace old tlb flush function with new one to flush a specified range.")
>> replaces old tlb flush function with kvm_flush_remote_tlbs_with_address()
>> to do tlb flushing. However, the gfn range of tlb flushing is wrong in
>> some cases. E.g., when a spte is dropped, the start gfn of tlb flushing
> Heh, "some" cases.  Looks like KVM is wrong on 7 of 15 cases.  And IIRC, there
> were already several rounds of fixes due to passing "end" instead of "nr_pages".
> 
> Patches look ok on a quick read through, but I'd have to stare a bunch more to
> be confident.
> 
> Part of me wonders if we should just revert the whole thing and then only reintroduce
> range-based flushing with proper testing and maybe even require performance numbers
> to justify the benefits.  Give that almost 50% of the users are broken, it's pretty
> obvious that no one running KVM actually tests the behavior.
> 

I'm pretty sure it's in use on Azure.  Some of the changes are flushing 
less, for the others it's more than likely that Hyper-V treats a 1-page 
flush the same if the address points to a huge page.

Paolo
Hou Wenlong June 27, 2022, 4:15 a.m. UTC | #3
On Sat, Jun 25, 2022 at 05:13:22PM +0800, Paolo Bonzini wrote:
> On 6/25/22 01:06, Sean Christopherson wrote:
> >>("KVM: Replace old tlb flush function with new one to flush a specified range.")
> >>replaces old tlb flush function with kvm_flush_remote_tlbs_with_address()
> >>to do tlb flushing. However, the gfn range of tlb flushing is wrong in
> >>some cases. E.g., when a spte is dropped, the start gfn of tlb flushing
> >Heh, "some" cases.  Looks like KVM is wrong on 7 of 15 cases.  And IIRC, there
> >were already several rounds of fixes due to passing "end" instead of "nr_pages".
> >
> >Patches look ok on a quick read through, but I'd have to stare a bunch more to
> >be confident.
> >
> >Part of me wonders if we should just revert the whole thing and then only reintroduce
> >range-based flushing with proper testing and maybe even require performance numbers
> >to justify the benefits.  Give that almost 50% of the users are broken, it's pretty
> >obvious that no one running KVM actually tests the behavior.
> >
> 
> I'm pretty sure it's in use on Azure.  Some of the changes are
> flushing less, for the others it's more than likely that Hyper-V
> treats a 1-page flush the same if the address points to a huge page.
> 
I lookup hyperv_fill_flush_guest_mapping_list(), gpa_list.page.largepage
is always false. Or the behaviour you said is implemented in Hyper-V not
in KVM ? 

> Paolo
Paolo Bonzini June 28, 2022, 12:59 p.m. UTC | #4
On 6/27/22 06:15, Hou Wenlong wrote:
>> I'm pretty sure it's in use on Azure.  Some of the changes are
>> flushing less, for the others it's more than likely that Hyper-V
>> treats a 1-page flush the same if the address points to a huge page.
>>
> I lookup hyperv_fill_flush_guest_mapping_list(), gpa_list.page.largepage
> is always false. Or the behaviour you said is implemented in Hyper-V not
> in KVM ?
> 

Yes, I mean in Hyper-V (and/or in the processor).

Paolo
David Matlack July 26, 2022, 10:59 p.m. UTC | #5
On Fri, Jun 24, 2022 at 11:36:56AM +0800, Hou Wenlong wrote:
> Commit c3134ce240eed
> ("KVM: Replace old tlb flush function with new one to flush a specified range.")
> replaces old tlb flush function with kvm_flush_remote_tlbs_with_address()
> to do tlb flushing. However, the gfn range of tlb flushing is wrong in
> some cases. E.g., when a spte is dropped, the start gfn of tlb flushing
> should be the gfn of spte not the base gfn of SP which contains the spte.
> So this patchset would fix them and do some cleanups.

One thing that would help prevent future buggy use of
kvm_flush_remote_tlbs_with_address(), and clean up this series, would be to
introduce some helper functions for common operations. In fact, even if
there is only one caller, I still think it would be useful to have helper
functions because it makes it clear the author's intent.

For example, I think the following helpers would be useful in this series:

/* Flush the given page (huge or not) of guest memory. */
static void kvm_flush_remote_tlbs_gfn(struct kvm *kvm, gfn_t gfn, int level)
{
        u64 pages = KVM_PAGES_PER_HPAGE(level);

        kvm_flush_remote_tlbs_with_address(kvm, gfn, pages);
}

/* Flush the range of guest memory mapped by the given SPTE. */
static void kvm_flush_remote_tlbs_sptep(struct kvm *kvm, u64 *sptep)
{
        struct kvm_mmu_page *sp = sptep_to_sp(sptep);
        gfn_t gfn = kvm_mmu_page_get_gfn(sp, spte_index(sptep));

        kvm_flush_remote_tlbs_gfn(kvm, gfn, sp->role.level);
}

/* Flush all memory mapped by the given direct SP. */
static void kvm_flush_remote_tlbs_direct_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
{
        WARN_ON_ONCE(!sp->role.direct);
        kvm_flush_remote_tlbs_gfn(kvm, sp->gfn, sp->role.level + 1);
}

> 
> Hou Wenlong (5):
>   KVM: x86/mmu: Fix wrong gfn range of tlb flushing in
>     validate_direct_spte()
>   KVM: x86/mmu: Fix wrong gfn range of tlb flushing in
>     kvm_set_pte_rmapp()
>   KVM: x86/mmu: Reduce gfn range of tlb flushing in
>     tdp_mmu_map_handle_target_level()
>   KVM: x86/mmu: Fix wrong start gfn of tlb flushing with range
>   KVM: x86/mmu: Use 1 as the size of gfn range for tlb flushing in
>     FNAME(invlpg)()
> 
>  arch/x86/kvm/mmu/mmu.c         | 15 +++++++++------
>  arch/x86/kvm/mmu/paging_tmpl.h |  2 +-
>  arch/x86/kvm/mmu/tdp_mmu.c     |  4 ++--
>  3 files changed, 12 insertions(+), 9 deletions(-)
> 
> --
> 2.31.1
>
Hou Wenlong July 27, 2022, 12:14 p.m. UTC | #6
On Wed, Jul 27, 2022 at 06:59:20AM +0800, David Matlack wrote:
> On Fri, Jun 24, 2022 at 11:36:56AM +0800, Hou Wenlong wrote:
> > Commit c3134ce240eed
> > ("KVM: Replace old tlb flush function with new one to flush a specified range.")
> > replaces old tlb flush function with kvm_flush_remote_tlbs_with_address()
> > to do tlb flushing. However, the gfn range of tlb flushing is wrong in
> > some cases. E.g., when a spte is dropped, the start gfn of tlb flushing
> > should be the gfn of spte not the base gfn of SP which contains the spte.
> > So this patchset would fix them and do some cleanups.
> 
> One thing that would help prevent future buggy use of
> kvm_flush_remote_tlbs_with_address(), and clean up this series, would be to
> introduce some helper functions for common operations. In fact, even if
> there is only one caller, I still think it would be useful to have helper
> functions because it makes it clear the author's intent.
> 
> For example, I think the following helpers would be useful in this series:
> 
> /* Flush the given page (huge or not) of guest memory. */
> static void kvm_flush_remote_tlbs_gfn(struct kvm *kvm, gfn_t gfn, int level)
> {
>         u64 pages = KVM_PAGES_PER_HPAGE(level);
> 
>         kvm_flush_remote_tlbs_with_address(kvm, gfn, pages);
> }
> 
> /* Flush the range of guest memory mapped by the given SPTE. */
> static void kvm_flush_remote_tlbs_sptep(struct kvm *kvm, u64 *sptep)
> {
>         struct kvm_mmu_page *sp = sptep_to_sp(sptep);
>         gfn_t gfn = kvm_mmu_page_get_gfn(sp, spte_index(sptep));
> 
>         kvm_flush_remote_tlbs_gfn(kvm, gfn, sp->role.level);
> }
> 
> /* Flush all memory mapped by the given direct SP. */
> static void kvm_flush_remote_tlbs_direct_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
> {
>         WARN_ON_ONCE(!sp->role.direct);
>         kvm_flush_remote_tlbs_gfn(kvm, sp->gfn, sp->role.level + 1);
> }
>
Thanks for your good suggestions, I'll add those helpers in the next version.

> > 
> > Hou Wenlong (5):
> >   KVM: x86/mmu: Fix wrong gfn range of tlb flushing in
> >     validate_direct_spte()
> >   KVM: x86/mmu: Fix wrong gfn range of tlb flushing in
> >     kvm_set_pte_rmapp()
> >   KVM: x86/mmu: Reduce gfn range of tlb flushing in
> >     tdp_mmu_map_handle_target_level()
> >   KVM: x86/mmu: Fix wrong start gfn of tlb flushing with range
> >   KVM: x86/mmu: Use 1 as the size of gfn range for tlb flushing in
> >     FNAME(invlpg)()
> > 
> >  arch/x86/kvm/mmu/mmu.c         | 15 +++++++++------
> >  arch/x86/kvm/mmu/paging_tmpl.h |  2 +-
> >  arch/x86/kvm/mmu/tdp_mmu.c     |  4 ++--
> >  3 files changed, 12 insertions(+), 9 deletions(-)
> > 
> > --
> > 2.31.1
> >