From: Lan Tianyu <tianyu....@microsoft.com>

When build tlb range flush list, just add leaf node into flush list in order
to avoid overlap of address range in the list. If parent node and leaf node
are added into flush list, parent node's address range will cover leaf node's.
Otherwise, not all leaf nodes of the parent are actually allocated when flush
tlb. The side affect is that flush list would be overflow and go back to
non-range tlb flush if redundant address ranges was too many. This patch is
to add last_level flag in the struct kvm_mmu_page and set the flag to be true
in the set_spte() and clear the flag when the child node is allocated.

Signed-off-by: Lan Tianyu <tianyu....@microsoft.com>
---
Change since v2:
        - Always set last_level flag to be true in the set_spte().
        - Clear last_level flag when assign child node.
---
 arch/x86/include/asm/kvm_host.h | 1 +
 arch/x86/kvm/mmu.c              | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 3e8bd78940c4..1a0a381c442d 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -327,6 +327,7 @@ struct kvm_mmu_page {
        struct hlist_node hash_link;
        bool unsync;
        bool mmio_cached;
+       bool last_level;
 
        /*
         * The following two entries are used to key the shadow page in the
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 2e13aac28293..f5a33cf71d73 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -2754,6 +2754,7 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm,
         */
        if (kvm_available_flush_tlb_with_range()) {
                list_for_each_entry(sp, invalid_list, link)
+                       if (sp->last_level)
                                hlist_add_head(&sp->flush_link, &flush_list);
 
                kvm_flush_remote_tlbs_with_list(kvm, &flush_list);
@@ -2956,6 +2957,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
 
        if (level > PT_PAGE_TABLE_LEVEL)
                spte |= PT_PAGE_SIZE_MASK;
+
        if (tdp_enabled)
                spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn,
                        kvm_is_mmio_pfn(pfn));
@@ -3010,6 +3012,8 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
        if (speculative)
                spte = mark_spte_for_access_track(spte);
 
+       sp->last_level = true;
+
 set_pte:
        if (mmu_spte_update(sptep, spte))
                ret |= SET_SPTE_NEED_REMOTE_TLB_FLUSH;
@@ -3200,6 +3204,10 @@ static int __direct_map(struct kvm_vcpu *vcpu, int 
write, int map_writable,
                                              iterator.level - 1, 1, ACC_ALL);
 
                        link_shadow_page(vcpu, iterator.sptep, sp);
+
+                       sp = page_header(__pa(iterator.sptep));
+                       if (sp->last_level)
+                               sp->last_level = false;
                }
        }
        return emulate;
-- 
2.14.4

Reply via email to