Subject: xenpaging: drop paged pages in guest_remove_page

Simply drop paged-pages in guest_remove_page(), and notify xenpaging to
drop reference to the gfn.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
---
 tools/xenpaging/xenpaging.c    |   17 +++++++---
 xen/arch/x86/mm/p2m.c          |   65 +++++++++++++++++++++++++++++++----------
 xen/common/memory.c            |    6 +++
 xen/include/asm-x86/p2m.h      |    4 ++
 xen/include/public/mem_event.h |    1 
 5 files changed, 73 insertions(+), 20 deletions(-)

--- xen-4.0.1-testing.orig/tools/xenpaging/xenpaging.c
+++ xen-4.0.1-testing/tools/xenpaging/xenpaging.c
@@ -598,12 +598,19 @@ int main(int argc, char *argv[])
                     goto out;
                 }
                 
-                /* Populate the page */
-                rc = xenpaging_populate_page(paging, &req.gfn, fd, i);
-                if ( rc != 0 )
+                if ( req.flags & MEM_EVENT_FLAG_DROP_PAGE )
                 {
-                    ERROR("Error populating page");
-                    goto out;
+                    DPRINTF("Dropping page %"PRIx64" p2mt %x\n", req.gfn, req.p2mt);
+                }
+                else
+                {
+                    /* Populate the page */
+                    rc = xenpaging_populate_page(paging, &req.gfn, fd, i);
+                    if ( rc != 0 )
+                    {
+                        ERROR("Error populating page");
+                        goto out;
+                    }
                 }
 
                 /* Prepare the response */
--- xen-4.0.1-testing.orig/xen/arch/x86/mm/p2m.c
+++ xen-4.0.1-testing/xen/arch/x86/mm/p2m.c
@@ -2000,12 +2000,15 @@ p2m_remove_page(struct domain *d, unsign
 
     P2M_DEBUG("removing gfn=%#lx mfn=%#lx\n", gfn, mfn);
 
-    for ( i = 0; i < (1UL << page_order); i++ )
+    if ( mfn_valid(_mfn(mfn)) )
     {
-        mfn_return = d->arch.p2m->get_entry(d, gfn + i, &t, p2m_query);
-        if ( !p2m_is_grant(t) )
-            set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY);
-        ASSERT( !p2m_is_valid(t) || mfn + i == mfn_x(mfn_return) );
+        for ( i = 0; i < (1UL << page_order); i++ )
+        {
+            mfn_return = d->arch.p2m->get_entry(d, gfn + i, &t, p2m_query);
+            if ( !p2m_is_grant(t) )
+                set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY);
+            ASSERT( !p2m_is_valid(t) || mfn + i == mfn_x(mfn_return) );
+        }
     }
     set_p2m_entry(d, gfn, _mfn(INVALID_MFN), page_order, p2m_invalid);
 }
@@ -2533,6 +2536,35 @@ int p2m_mem_paging_evict(struct domain *
     return 0;
 }
 
+void p2m_mem_paging_drop_page(struct domain *d, unsigned long gfn)
+{
+    struct vcpu *v = current;
+    mem_event_request_t req;
+    p2m_type_t p2mt;
+
+    memset(&req, 0, sizeof(req));
+
+    /* Check that there's space on the ring for this request */
+    if ( mem_event_check_ring(d) )
+        return;
+
+    gfn_to_mfn(d, gfn, &p2mt);
+    /* Pause domain */
+    if ( v->domain->domain_id == d->domain_id )
+    {
+        vcpu_pause_nosync(v);
+        req.flags |= MEM_EVENT_FLAG_VCPU_PAUSED;
+    }
+
+    /* Send request to pager */
+    req.flags |= MEM_EVENT_FLAG_DROP_PAGE;
+    req.gfn = gfn;
+    req.p2mt = p2mt;
+    req.vcpu_id = v->vcpu_id;
+
+    mem_event_put_request(d, &req);
+}
+
 void p2m_mem_paging_populate(struct domain *d, unsigned long gfn)
 {
     struct vcpu *v = current;
@@ -2597,17 +2629,20 @@ void p2m_mem_paging_resume(struct domain
     /* Pull the response off the ring */
     mem_event_get_response(d, &rsp);
 
-    /* Fix p2m entry */
-    mfn = gfn_to_mfn(d, rsp.gfn, &p2mt);
-    if (mfn_valid(mfn))
+    if ( !( rsp.flags & MEM_EVENT_FLAG_DROP_PAGE ) )
     {
-        p2m_lock(d->arch.p2m);
-        set_p2m_entry(d, rsp.gfn, mfn, 0, p2m_ram_rw);
-        set_gpfn_from_mfn(mfn_x(mfn), rsp.gfn);
-        p2m_unlock(d->arch.p2m);
-    } else {
-        gdprintk(XENLOG_ERR, "invalid mfn %lx for gfn %lx p2mt %x\n",
-           mfn_x(mfn), rsp.gfn, p2mt);
+        /* Fix p2m entry */
+        mfn = gfn_to_mfn(d, rsp.gfn, &p2mt);
+        if (mfn_valid(mfn))
+        {
+            p2m_lock(d->arch.p2m);
+            set_p2m_entry(d, rsp.gfn, mfn, 0, p2m_ram_rw);
+            set_gpfn_from_mfn(mfn_x(mfn), rsp.gfn);
+            p2m_unlock(d->arch.p2m);
+        } else {
+            gdprintk(XENLOG_ERR, "invalid mfn %lx for gfn %lx p2mt %x\n",
+               mfn_x(mfn), rsp.gfn, p2mt);
+        }
     }
 
     /* Unpause domain */
--- xen-4.0.1-testing.orig/xen/common/memory.c
+++ xen-4.0.1-testing/xen/common/memory.c
@@ -162,6 +162,12 @@ int guest_remove_page(struct domain *d,
 
 #ifdef CONFIG_X86
     mfn = mfn_x(gfn_to_mfn(d, gmfn, &p2mt)); 
+    if ( unlikely(p2m_is_paging(p2mt)) )
+    {
+        guest_physmap_remove_page(d, gmfn, mfn, 0);
+        p2m_mem_paging_drop_page(d, gmfn);
+        return 1;
+    }
 #else
     mfn = gmfn_to_mfn(d, gmfn);
 #endif
--- xen-4.0.1-testing.orig/xen/include/asm-x86/p2m.h
+++ xen-4.0.1-testing/xen/include/asm-x86/p2m.h
@@ -441,6 +441,8 @@ int set_shared_p2m_entry(struct domain *
 int p2m_mem_paging_nominate(struct domain *d, unsigned long gfn);
 /* Evict a frame */
 int p2m_mem_paging_evict(struct domain *d, unsigned long gfn);
+/* Tell xenpaging to drop a paged out frame */
+void p2m_mem_paging_drop_page(struct domain *d, unsigned long gfn);
 /* Start populating a paged out frame */
 void p2m_mem_paging_populate(struct domain *d, unsigned long gfn);
 /* Prepare the p2m for paging a frame in */
@@ -448,6 +450,8 @@ int p2m_mem_paging_prep(struct domain *d
 /* Resume normal operation (in case a domain was paused) */
 void p2m_mem_paging_resume(struct domain *d);
 #else
+static inline void p2m_mem_paging_drop_page(struct domain *d, unsigned long gfn)
+{ }
 static inline void p2m_mem_paging_populate(struct domain *d, unsigned long gfn)
 { }
 #endif
--- xen-4.0.1-testing.orig/xen/include/public/mem_event.h
+++ xen-4.0.1-testing/xen/include/public/mem_event.h
@@ -37,6 +37,7 @@
 #define MEM_EVENT_FLAG_VCPU_PAUSED  (1 << 0)
 #define MEM_EVENT_FLAG_DOM_PAUSED   (1 << 1)
 #define MEM_EVENT_FLAG_OUT_OF_MEM   (1 << 2)
+#define MEM_EVENT_FLAG_DROP_PAGE    (1 << 3)
 
 
 typedef struct mem_event_shared_page {