# HG changeset patch
# Parent 4019436855ff3d44228c8eb3e78a9133a9caf870
xenpaging: map gfn before nomination

If the gfn is mapped before nomination, all special cases in do_mmu_update()
for paged gfns can be removed. If a gfn is actually in any of the paging
states the caller has to try again.

Bump interface age.

Signed-off-by: Olaf Hering <olaf@aepfle.de>

Index: xen-4.1.3-testing/tools/xenpaging/xenpaging.c
===================================================================
--- xen-4.1.3-testing.orig/tools/xenpaging/xenpaging.c
+++ xen-4.1.3-testing/tools/xenpaging/xenpaging.c
@@ -573,7 +573,7 @@ static int xenpaging_evict_page(xenpagin
 
     DECLARE_DOMCTL;
 
-    /* Map page */
+    /* Map page to get a handle */
     gfn = victim->gfn;
     ret = -EFAULT;
     page = xc_map_foreign_pages(xch, paging->mem_event.domain_id,
@@ -584,16 +584,21 @@ static int xenpaging_evict_page(xenpagin
         goto out;
     }
 
+    /* Nominate the page */
+    ret = xc_mem_paging_nominate(xch, paging->mem_event.domain_id, gfn);
+    if ( ret != 0 )
+        goto out;
+
     /* Copy page */
     ret = write_page(fd, page, i);
     if ( ret != 0 )
     {
         PERROR("Error copying page %lx", victim->gfn);
-        munmap(page, PAGE_SIZE);
         goto out;
     }
 
     munmap(page, PAGE_SIZE);
+    page = NULL;
 
     /* Tell Xen to evict page */
     ret = xc_mem_paging_evict(xch, paging->mem_event.domain_id,
@@ -612,6 +617,8 @@ static int xenpaging_evict_page(xenpagin
     paging->num_paged_out++;
 
  out:
+    if (page)
+        munmap(page, PAGE_SIZE);
     return ret;
 }
 
@@ -735,14 +742,11 @@ static int evict_victim(xenpaging_t *pag
             ret = -EINTR;
             goto out;
         }
-        ret = xc_mem_paging_nominate(xch, paging->mem_event.domain_id, victim->gfn);
-        if ( ret == 0 )
-            ret = xenpaging_evict_page(paging, victim, fd, i);
-        else
+        ret = xenpaging_evict_page(paging, victim, fd, i);
+        if ( ret && j++ % 1000 == 0 )
         {
-            if ( j++ % 1000 == 0 )
-                if ( xenpaging_mem_paging_flush_ioemu_cache(paging) )
-                    PERROR("Error flushing ioemu cache");
+            if ( xenpaging_mem_paging_flush_ioemu_cache(paging) )
+                PERROR("Error flushing ioemu cache");
         }
     }
     while ( ret );
Index: xen-4.1.3-testing/xen/arch/x86/mm/p2m.c
===================================================================
--- xen-4.1.3-testing.orig/xen/arch/x86/mm/p2m.c
+++ xen-4.1.3-testing/xen/arch/x86/mm/p2m.c
@@ -2855,7 +2855,7 @@ set_shared_p2m_entry(struct p2m_domain *
  * - the gfn is backed by a mfn
  * - the p2mt of the gfn is pageable
  * - the mfn is not used for IO
- * - the mfn has exactly one user and has no special meaning
+ * - the mfn has exactly two users (guest+pager) and has no special meaning
  *
  * Once the p2mt is changed the page is readonly for the guest.  On success the
  * pager can write the page contents to disk and later evict the page.
@@ -2889,7 +2889,7 @@ int p2m_mem_paging_nominate(struct p2m_d
     /* Check page count and type */
     page = mfn_to_page(mfn);
     if ( (page->count_info & (PGC_count_mask | PGC_allocated)) !=
-         (1 | PGC_allocated) )
+         (2 | PGC_allocated) )
         goto out;
 
     if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_none )
@@ -2917,7 +2917,7 @@ int p2m_mem_paging_nominate(struct p2m_d
  * freed:
  * - the gfn is backed by a mfn
  * - the gfn was nominated
- * - the mfn has still exactly one user and has no special meaning
+ * - the mfn has still exactly one user (the guest) and has no special meaning
  *
  * After successful nomination some other process could have mapped the page. In
  * this case eviction can not be done. If the gfn was populated before the pager
Index: xen-4.1.3-testing/xen/include/public/mem_event.h
===================================================================
--- xen-4.1.3-testing.orig/xen/include/public/mem_event.h
+++ xen-4.1.3-testing/xen/include/public/mem_event.h
@@ -49,7 +49,7 @@
 #define MEM_EVENT_REASON_INT3        5    /* int3 was hit: gla/gfn are RIP */
 #define MEM_EVENT_REASON_SINGLESTEP  6    /* single step was invoked: gla/gfn are RIP */
 
-#define MEM_EVENT_PAGING_AGE         1UL  /* Number distinguish the mem_paging <-> pager interface */
+#define MEM_EVENT_PAGING_AGE         2UL  /* Number distinguish the mem_paging <-> pager interface */
 
 typedef struct mem_event_shared_page {
     uint32_t port;
