Merge branch 'linus' into x86/xsave
[pandora-kernel.git] / drivers / lguest / page_tables.c
index a7f64a9..81d0c60 100644 (file)
@@ -2,8 +2,8 @@
  * previous encounters.  It's functional, and as neat as it can be in the
  * circumstances, but be wary, for these things are subtle and break easily.
  * The Guest provides a virtual to physical mapping, but we can neither trust
- * it nor use it: we verify and convert it here to point the hardware to the
- * actual Guest pages when running the Guest. :*/
+ * it nor use it: we verify and convert it here then point the CPU to the
+ * converted Guest pages when running the Guest. :*/
 
 /* Copyright (C) Rusty Russell IBM Corporation 2006.
  * GPL v2 and any later version */
@@ -106,6 +106,10 @@ static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr)
        BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT));
        return gpage + ((vaddr>>PAGE_SHIFT) % PTRS_PER_PTE) * sizeof(pte_t);
 }
+/*:*/
+
+/*M:014 get_pfn is slow: we could probably try to grab batches of pages here as
+ * an optimization (ie. pre-faulting). :*/
 
 /*H:350 This routine takes a page number given by the Guest and converts it to
  * an actual, physical page number.  It can fail for several reasons: the
@@ -113,24 +117,18 @@ static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr)
  * and the page is read-only, or the write flag was set and the page was
  * shared so had to be copied, but we ran out of memory.
  *
- * This holds a reference to the page, so release_pte() is careful to
- * put that back. */
+ * This holds a reference to the page, so release_pte() is careful to put that
+ * back. */
 static unsigned long get_pfn(unsigned long virtpfn, int write)
 {
        struct page *page;
-       /* This value indicates failure. */
-       unsigned long ret = -1UL;
 
-       /* get_user_pages() is a complex interface: it gets the "struct
-        * vm_area_struct" and "struct page" assocated with a range of pages.
-        * It also needs the task's mmap_sem held, and is not very quick.
-        * It returns the number of pages it got. */
-       down_read(&current->mm->mmap_sem);
-       if (get_user_pages(current, current->mm, virtpfn << PAGE_SHIFT,
-                          1, write, 1, &page, NULL) == 1)
-               ret = page_to_pfn(page);
-       up_read(&current->mm->mmap_sem);
-       return ret;
+       /* gup me one page at this address please! */
+       if (get_user_pages_fast(virtpfn << PAGE_SHIFT, 1, write, &page) == 1)
+               return page_to_pfn(page);
+
+       /* This value indicates failure. */
+       return -1UL;
 }
 
 /*H:340 Converting a Guest page table entry to a shadow (ie. real) page table
@@ -169,7 +167,7 @@ static pte_t gpte_to_spte(struct lg_cpu *cpu, pte_t gpte, int write)
 /*H:460 And to complete the chain, release_pte() looks like this: */
 static void release_pte(pte_t pte)
 {
-       /* Remember that get_user_pages() took a reference to the page, in
+       /* Remember that get_user_pages_fast() took a reference to the page, in
         * get_pfn()?  We have to put it back now. */
        if (pte_flags(pte) & _PAGE_PRESENT)
                put_page(pfn_to_page(pte_pfn(pte)));
@@ -532,13 +530,13 @@ static void do_set_pte(struct lg_cpu *cpu, int idx,
  * all processes.  So when the page table above that address changes, we update
  * all the page tables, not just the current one.  This is rare.
  *
- * The benefit is that when we have to track a new page table, we can copy keep
- * all the kernel mappings.  This speeds up context switch immensely. */
+ * The benefit is that when we have to track a new page table, we can keep all
+ * the kernel mappings.  This speeds up context switch immensely. */
 void guest_set_pte(struct lg_cpu *cpu,
                   unsigned long gpgdir, unsigned long vaddr, pte_t gpte)
 {
-       /* Kernel mappings must be changed on all top levels.  Slow, but
-        * doesn't happen often. */
+       /* Kernel mappings must be changed on all top levels.  Slow, but doesn't
+        * happen often. */
        if (vaddr >= cpu->lg->kernel_address) {
                unsigned int i;
                for (i = 0; i < ARRAY_SIZE(cpu->lg->pgdirs); i++)
@@ -704,12 +702,11 @@ static __init void populate_switcher_pte_page(unsigned int cpu,
 /* We've made it through the page table code.  Perhaps our tired brains are
  * still processing the details, or perhaps we're simply glad it's over.
  *
- * If nothing else, note that all this complexity in juggling shadow page
- * tables in sync with the Guest's page tables is for one reason: for most
- * Guests this page table dance determines how bad performance will be.  This
- * is why Xen uses exotic direct Guest pagetable manipulation, and why both
- * Intel and AMD have implemented shadow page table support directly into
- * hardware.
+ * If nothing else, note that all this complexity in juggling shadow page tables
+ * in sync with the Guest's page tables is for one reason: for most Guests this
+ * page table dance determines how bad performance will be.  This is why Xen
+ * uses exotic direct Guest pagetable manipulation, and why both Intel and AMD
+ * have implemented shadow page table support directly into hardware.
  *
  * There is just one file remaining in the Host. */