From: Takuya Yoshikawa <yoshikawa.tak...@oss.ntt.co.jp>

We optimize multi level guest page table walk as follows:

  1. We cache the memslot which, probably, includes the next guest page
     tables to avoid searching for it many times.
  2. We use get_user() instead of copy_from_user().

Note that this is kind of a restricted way of Xiao's more generic
work: "KVM: optimize memslots searching and cache GPN to GFN."

With this patch applied, paging64_walk_addr_generic() has improved
as the following tracing results show.

Before:
  3.169 us   |  paging64_walk_addr_generic();
  1.880 us   |  paging64_walk_addr_generic();
  1.243 us   |  paging64_walk_addr_generic();
  1.517 us   |  paging64_walk_addr_generic();
  3.009 us   |  paging64_walk_addr_generic();
  1.814 us   |  paging64_walk_addr_generic();
  1.340 us   |  paging64_walk_addr_generic();
  1.659 us   |  paging64_walk_addr_generic();
  1.748 us   |  paging64_walk_addr_generic();
  1.488 us   |  paging64_walk_addr_generic();

After:
  1.714 us   |  paging64_walk_addr_generic();
  0.806 us   |  paging64_walk_addr_generic();
  0.664 us   |  paging64_walk_addr_generic();
  0.619 us   |  paging64_walk_addr_generic();
  0.645 us   |  paging64_walk_addr_generic();
  0.605 us   |  paging64_walk_addr_generic();
  1.388 us   |  paging64_walk_addr_generic();
  0.753 us   |  paging64_walk_addr_generic();
  0.594 us   |  paging64_walk_addr_generic();
  0.833 us   |  paging64_walk_addr_generic();

Signed-off-by: Takuya Yoshikawa <yoshikawa.tak...@oss.ntt.co.jp>
---
 arch/x86/kvm/paging_tmpl.h |   37 ++++++++++++++++++++++++++++++++-----
 1 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 109939a..614aa3f 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -109,12 +109,37 @@ static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, 
pt_element_t gpte)
        return access;
 }
 
+/*
+ * Read the guest PTE refered to by table_gfn and offset and put it into ptep.
+ *
+ * *slot_hint, if not NULL, should point to a memslot which probably includes
+ * the guest PTE.  The actual memslot will be put back into this so that
+ * callers can cache it.
+ */
 static int FNAME(read_guest_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
-                                gfn_t table_gfn, int offset, pt_element_t 
*ptep)
+                                gfn_t table_gfn, int offset, pt_element_t 
*ptep,
+                                struct kvm_memory_slot **slot_hint)
 {
-       return kvm_read_guest_page_mmu(vcpu, mmu, table_gfn, ptep,
-                                      offset, sizeof(*ptep),
-                                      PFERR_USER_MASK | PFERR_WRITE_MASK);
+       unsigned long addr;
+       pt_element_t __user *ptep_user;
+       gfn_t real_gfn;
+
+       real_gfn = mmu->translate_gpa(vcpu, gfn_to_gpa(table_gfn),
+                                     PFERR_USER_MASK | PFERR_WRITE_MASK);
+       if (real_gfn == UNMAPPED_GVA)
+               return -EFAULT;
+
+       real_gfn = gpa_to_gfn(real_gfn);
+
+       if (!(*slot_hint) || !gfn_in_memslot(*slot_hint, real_gfn))
+               *slot_hint = gfn_to_memslot(vcpu->kvm, real_gfn);
+
+       addr = gfn_to_hva_memslot(*slot_hint, real_gfn);
+       if (kvm_is_error_hva(addr))
+               return -EFAULT;
+
+       ptep_user = (pt_element_t __user *)((void *)addr + offset);
+       return get_user(*ptep, ptep_user);
 }
 
 /*
@@ -130,6 +155,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker 
*walker,
        gpa_t pte_gpa;
        bool eperm, present, rsvd_fault;
        int offset, write_fault, user_fault, fetch_fault;
+       struct kvm_memory_slot *slot_cache = NULL;
 
        write_fault = access & PFERR_WRITE_MASK;
        user_fault = access & PFERR_USER_MASK;
@@ -168,7 +194,8 @@ walk:
                walker->table_gfn[walker->level - 1] = table_gfn;
                walker->pte_gpa[walker->level - 1] = pte_gpa;
 
-               if (FNAME(read_guest_pte)(vcpu, mmu, table_gfn, offset, &pte)) {
+               if (FNAME(read_guest_pte)(vcpu, mmu, table_gfn,
+                                         offset, &pte, &slot_cache)) {
                        present = false;
                        break;
                }
-- 
1.7.1

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

Reply via email to