KVM: x86/mmu: Fix wrong gfn range of tlb flushing in kvm_set_pte_rmapp()
authorHou Wenlong <houwenlong.hwl@antgroup.com>
Mon, 10 Oct 2022 12:19:13 +0000 (20:19 +0800)
committerSean Christopherson <seanjc@google.com>
Tue, 24 Jan 2023 18:05:46 +0000 (10:05 -0800)
When the spte of hupe page is dropped in kvm_set_pte_rmapp(), the whole
gfn range covered by the spte should be flushed. However,
rmap_walk_init_level() doesn't align down the gfn for new level like tdp
iterator does, then the gfn used in kvm_set_pte_rmapp() is not the base
gfn of huge page. And the size of gfn range is wrong too for huge page.
Use the base gfn of huge page and the size of huge page for flushing
tlbs for huge page. Also introduce a helper function to flush the given
page (huge or not) of guest memory, which would help prevent future
buggy use of kvm_flush_remote_tlbs_with_address() in such case.

Fixes: c3134ce240eed ("KVM: Replace old tlb flush function with new one to flush a specified range.")
Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
Link: https://lore.kernel.org/r/0ce24d7078fa5f1f8d64b0c59826c50f32f8065e.1665214747.git.houwenlong.hwl@antgroup.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/mmu/mmu_internal.h

index f3bef56a89a33dc3e9fec9bf47d52cf4108b20a3..52be98e0102ac0d5ebdcee03e0473901d2e6c100 100644 (file)
@@ -1469,7 +1469,7 @@ restart:
        }
 
        if (need_flush && kvm_available_flush_tlb_with_range()) {
-               kvm_flush_remote_tlbs_with_address(kvm, gfn, 1);
+               kvm_flush_remote_tlbs_gfn(kvm, gfn, level);
                return false;
        }
 
index 486be0f9fe16456d04d72191dbbf4126082f74a8..cc58631e233682c103a1549f6a79b4e50d01222e 100644 (file)
@@ -169,8 +169,17 @@ void kvm_mmu_gfn_allow_lpage(const struct kvm_memory_slot *slot, gfn_t gfn);
 bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm,
                                    struct kvm_memory_slot *slot, u64 gfn,
                                    int min_level);
+
 void kvm_flush_remote_tlbs_with_address(struct kvm *kvm,
                                        u64 start_gfn, u64 pages);
+
+/* Flush the given page (huge or not) of guest memory. */
+static inline void kvm_flush_remote_tlbs_gfn(struct kvm *kvm, gfn_t gfn, int level)
+{
+       kvm_flush_remote_tlbs_with_address(kvm, gfn_round_for_level(gfn, level),
+                                          KVM_PAGES_PER_HPAGE(level));
+}
+
 unsigned int pte_list_count(struct kvm_rmap_head *rmap_head);
 
 extern int nx_huge_pages;