Re: [PATCH 2/3] kvm: x86/mmu: Ensure TDP MMU roots are freed after yield

From: Ben Gardon
Date: Tue Jan 05 2021 - 18:39:07 EST


On Tue, Jan 5, 2021 at 3:31 PM Ben Gardon <bgardon@xxxxxxxxxx> wrote:
>
> Many TDP MMU functions which need to perform some action on all TDP MMU
> roots hold a reference on that root so that they can safely drop the MMU
> lock in order to yield to other threads. However, when releasing the
> reference on the root, there is a bug: the root will not be freed even
> if its reference count (root_count) is reduced to 0. Ensure that these
> roots are properly freed.
>
> Reported-by: Maciej S. Szmigiero <maciej.szmigiero@xxxxxxxxxx>
> Fixes: faaf05b00aec ("kvm: x86/mmu: Support zapping SPTEs in the TDP MMU")
> Fixes: 063afacd8730 ("kvm: x86/mmu: Support invalidate range MMU notifier for TDP MMU")
> Fixes: a6a0b05da9f3 ("kvm: x86/mmu: Support dirty logging for the TDP MMU")
> Fixes: 14881998566d ("kvm: x86/mmu: Support disabling dirty logging for the tdp MMU")
> Signed-off-by: Ben Gardon <bgardon@xxxxxxxxxx>
> ---
> arch/x86/kvm/mmu/tdp_mmu.c | 18 ++++++++++++------
> 1 file changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
> index 75db27fda8f3..5ec6fae36e33 100644
> --- a/arch/x86/kvm/mmu/tdp_mmu.c
> +++ b/arch/x86/kvm/mmu/tdp_mmu.c
> @@ -83,6 +83,12 @@ void kvm_tdp_mmu_free_root(struct kvm *kvm, struct kvm_mmu_page *root)
> kmem_cache_free(mmu_page_header_cache, root);
> }
>
> +static void tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root)
> +{
> + if (kvm_mmu_put_root(kvm, root))
> + kvm_tdp_mmu_free_root(kvm, root);
> +}
> +
> static union kvm_mmu_page_role page_role_for_level(struct kvm_vcpu *vcpu,
> int level)
> {
> @@ -456,7 +462,7 @@ bool kvm_tdp_mmu_zap_gfn_range(struct kvm *kvm, gfn_t start, gfn_t end)
>
> flush |= zap_gfn_range(kvm, root, start, end, true);
>
> - kvm_mmu_put_root(kvm, root);
> + tdp_mmu_put_root(kvm, root);
> }
>
> return flush;
> @@ -648,7 +654,7 @@ static int kvm_tdp_mmu_handle_hva_range(struct kvm *kvm, unsigned long start,
> gfn_end, data);
> }
>
> - kvm_mmu_put_root(kvm, root);
> + tdp_mmu_put_root(kvm, root);
> }
>
> return ret;
> @@ -852,7 +858,7 @@ bool kvm_tdp_mmu_wrprot_slot(struct kvm *kvm, struct kvm_memory_slot *slot,
> spte_set |= wrprot_gfn_range(kvm, root, slot->base_gfn,
> slot->base_gfn + slot->npages, min_level);
>
> - kvm_mmu_put_root(kvm, root);
> + tdp_mmu_put_root(kvm, root);
> }
>
> return spte_set;
> @@ -920,7 +926,7 @@ bool kvm_tdp_mmu_clear_dirty_slot(struct kvm *kvm, struct kvm_memory_slot *slot)
> spte_set |= clear_dirty_gfn_range(kvm, root, slot->base_gfn,
> slot->base_gfn + slot->npages);
>
> - kvm_mmu_put_root(kvm, root);
> + tdp_mmu_put_root(kvm, root);
> }
>
> return spte_set;
> @@ -1043,7 +1049,7 @@ bool kvm_tdp_mmu_slot_set_dirty(struct kvm *kvm, struct kvm_memory_slot *slot)
> spte_set |= set_dirty_gfn_range(kvm, root, slot->base_gfn,
> slot->base_gfn + slot->npages);
>
> - kvm_mmu_put_root(kvm, root);
> + tdp_mmu_put_root(kvm, root);
> }
> return spte_set;
> }
> @@ -1103,7 +1109,7 @@ void kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm,
> zap_collapsible_spte_range(kvm, root, slot->base_gfn,
> slot->base_gfn + slot->npages);
>
> - kvm_mmu_put_root(kvm, root);
> + tdp_mmu_put_root(kvm, root);
> }
> }
>
> --
> 2.29.2.729.g45daf8777d-goog
>

+Sean Christopherson, for whom I used a stale email address.
.
I tested this series by running kvm-unit-tests on an Intel Skylake
machine. It did not introduce any new failures. I also ran the
set_memory_region_test, but was unable to reproduce Maciej's problem.
Maciej, if you'd be willing to confirm this series solves the problem
you observed, or provide more details on the setup in which you
observed it, I'd appreciate it.