KVM: x86/mmu: do not allow readers to acquire references to invalid roots
authorPaolo Bonzini <pbonzini@redhat.com>
Wed, 2 Mar 2022 13:51:05 +0000 (08:51 -0500)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 8 Mar 2022 14:31:50 +0000 (09:31 -0500)
Remove the "shared" argument of for_each_tdp_mmu_root_yield_safe, thus ensuring
that readers do not ever acquire a reference to an invalid root.  After this
patch, all readers except kvm_tdp_mmu_zap_invalidated_roots() treat
refcount=0/valid, refcount=0/invalid and refcount=1/invalid in exactly the
same way.  kvm_tdp_mmu_zap_invalidated_roots() is different but it also
does not acquire a reference to the invalid root, and it cannot see
refcount=0/invalid because it is guaranteed to run after
kvm_tdp_mmu_invalidate_all_roots().

Opportunistically add a lockdep assertion to the yield-safe iterator.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/mmu/tdp_mmu.c

index d39593b9ac9e0da93f7c26c9d3c7d1c79433885f..79bc48ddb69df6049c4e252891bfaef99f8ceb31 100644 (file)
@@ -166,14 +166,15 @@ static struct kvm_mmu_page *tdp_mmu_next_root(struct kvm *kvm,
        for (_root = tdp_mmu_next_root(_kvm, NULL, _shared, _only_valid);       \
             _root;                                                             \
             _root = tdp_mmu_next_root(_kvm, _root, _shared, _only_valid))      \
-               if (kvm_mmu_page_as_id(_root) != _as_id) {                      \
+               if (kvm_lockdep_assert_mmu_lock_held(_kvm, _shared) &&          \
+                   kvm_mmu_page_as_id(_root) != _as_id) {                      \
                } else
 
 #define for_each_valid_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared)   \
        __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared, true)
 
-#define for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared)         \
-       __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared, false)
+#define for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id)                  \
+       __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, false, false)
 
 /*
  * Iterate over all TDP MMU roots.  Requires that mmu_lock be held for write,
@@ -808,7 +809,7 @@ bool __kvm_tdp_mmu_zap_gfn_range(struct kvm *kvm, int as_id, gfn_t start,
 {
        struct kvm_mmu_page *root;
 
-       for_each_tdp_mmu_root_yield_safe(kvm, root, as_id, false)
+       for_each_tdp_mmu_root_yield_safe(kvm, root, as_id)
                flush = zap_gfn_range(kvm, root, start, end, can_yield, flush,
                                      false);