Cache the unsynced children information in a per-page bitmap.

Signed-off-by: Marcelo Tosatti <[EMAIL PROTECTED]>

Index: kvm/arch/x86/kvm/mmu.c
===================================================================
--- kvm.orig/arch/x86/kvm/mmu.c
+++ kvm/arch/x86/kvm/mmu.c
@@ -927,6 +927,52 @@ static void mmu_parent_walk(struct kvm_v
        } while (level > start_level-1);
 }
 
+static void kvm_mmu_update_unsync_bitmap(u64 *spte)
+{
+       unsigned int index;
+       struct kvm_mmu_page *sp = page_header(__pa(spte));
+
+       index = spte - sp->spt;
+       __set_bit(index, sp->unsync_child_bitmap);
+       sp->unsync_children = 1;
+}
+
+static void kvm_mmu_update_parents_unsync(struct kvm_mmu_page *sp)
+{
+       struct kvm_pte_chain *pte_chain;
+       struct hlist_node *node;
+       int i;
+
+       if (!sp->parent_pte)
+               return;
+
+       if (!sp->multimapped) {
+               kvm_mmu_update_unsync_bitmap(sp->parent_pte);
+               return;
+       }
+
+       hlist_for_each_entry(pte_chain, node, &sp->parent_ptes, link)
+               for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) {
+                       if (!pte_chain->parent_ptes[i])
+                               break;
+                       kvm_mmu_update_unsync_bitmap(pte_chain->parent_ptes[i]);
+               }
+}
+
+static int unsync_walk_fn(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
+{
+       sp->unsync_children = 1;
+       kvm_mmu_update_parents_unsync(sp);
+       return 1;
+}
+
+static void kvm_mmu_mark_parents_unsync(struct kvm_vcpu *vcpu,
+                                       struct kvm_mmu_page *sp)
+{
+       mmu_parent_walk(vcpu, sp, unsync_walk_fn);
+       kvm_mmu_update_parents_unsync(sp);
+}
+
 static void nonpaging_prefetch_page(struct kvm_vcpu *vcpu,
                                    struct kvm_mmu_page *sp)
 {
@@ -949,33 +995,57 @@ static void nonpaging_invlpg(struct kvm_
 static int mmu_unsync_walk(struct kvm_mmu_page *parent,
                           struct kvm_unsync_walk *walker)
 {
-       int i, ret;
-       struct kvm_mmu_page *sp = parent;
+       int ret, level, i;
+       u64 ent;
+       struct kvm_mmu_page *sp, *child;
+       struct walk {
+               struct kvm_mmu_page *sp;
+               int pos;
+       } walk[PT64_ROOT_LEVEL];
 
-       while (parent->unsync_children) {
-               for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
-                       u64 ent = sp->spt[i];
+       WARN_ON(parent->role.level == PT_PAGE_TABLE_LEVEL);
+
+       if (!parent->unsync_children)
+               return 0;
+
+       memset(&walk, 0, sizeof(walk));
+       level = parent->role.level;
+       walk[level-1].sp = parent;
+
+       do {
+               sp = walk[level-1].sp;
+               i = find_next_bit(sp->unsync_child_bitmap, 512, 
walk[level-1].pos);
+               if (i < 512) {
+                       walk[level-1].pos = i+1;
+                       ent = sp->spt[i];
 
                        if (is_shadow_present_pte(ent)) {
-                               struct kvm_mmu_page *child;
                                child = page_header(ent & PT64_BASE_ADDR_MASK);
 
                                if (child->unsync_children) {
-                                       sp = child;
-                                       break;
+                                       --level;
+                                       walk[level-1].sp = child;
+                                       walk[level-1].pos = 0;
+                                       continue;
                                }
                                if (child->unsync) {
                                        ret = walker->entry(child, walker);
+                                       __clear_bit(i, sp->unsync_child_bitmap);
                                        if (ret)
                                                return ret;
                                }
                        }
+                       __clear_bit(i, sp->unsync_child_bitmap);
+               } else {
+                       ++level;
+                       if (find_first_bit(sp->unsync_child_bitmap, 512) == 
512) {
+                               sp->unsync_children = 0;
+                               if (level-1 < PT64_ROOT_LEVEL)
+                                       walk[level-1].pos = 0;
+                       }
                }
-               if (i == PT64_ENT_PER_PAGE) {
-                       sp->unsync_children = 0;
-                       sp = parent;
-               }
-       }
+       } while (level <= parent->role.level);
+
        return 0;
 }
 
@@ -1090,10 +1160,11 @@ static struct kvm_mmu_page *kvm_mmu_get_
                        if (sp->role.word != role.word)
                                continue;
 
-                       if (sp->unsync_children)
-                               set_bit(KVM_REQ_MMU_SYNC, &vcpu->requests);
-
                        mmu_page_add_parent_pte(vcpu, sp, parent_pte);
+                       if (sp->unsync_children) {
+                               set_bit(KVM_REQ_MMU_SYNC, &vcpu->requests);
+                               kvm_mmu_mark_parents_unsync(vcpu, sp);
+                       }
                        pgprintk("%s: found\n", __func__);
                        return sp;
                }
@@ -1368,12 +1439,6 @@ struct page *gva_to_page(struct kvm_vcpu
        return page;
 }
 
-static int unsync_walk_fn(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
-{
-       sp->unsync_children = 1;
-       return 1;
-}
-
 static int kvm_unsync_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
 {
        unsigned index;
@@ -1390,7 +1455,7 @@ static int kvm_unsync_page(struct kvm_vc
                if (s->role.word != sp->role.word)
                        return 1;
        }
-       mmu_parent_walk(vcpu, sp, unsync_walk_fn);
+       kvm_mmu_mark_parents_unsync(vcpu, sp);
        ++vcpu->kvm->stat.mmu_unsync;
        sp->unsync = 1;
        mmu_convert_notrap(sp);
Index: kvm/include/asm-x86/kvm_host.h
===================================================================
--- kvm.orig/include/asm-x86/kvm_host.h
+++ kvm/include/asm-x86/kvm_host.h
@@ -201,6 +201,7 @@ struct kvm_mmu_page {
                u64 *parent_pte;               /* !multimapped */
                struct hlist_head parent_ptes; /* multimapped, kvm_pte_chain */
        };
+       DECLARE_BITMAP(unsync_child_bitmap, 512);
 };
 
 struct kvm_pv_mmu_op_buffer {

-- 

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to