[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v4 4/9] xen: introduce XEN_DOMCTL_devour



New operation sets the 'recipient' domain which will recieve all
memory pages from a particular domain and kills the original domain.

Signed-off-by: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx>
---
 xen/common/domain.c         |  3 +++
 xen/common/domctl.c         | 33 +++++++++++++++++++++++++++++++++
 xen/common/page_alloc.c     | 28 ++++++++++++++++++++++++----
 xen/include/public/domctl.h | 15 +++++++++++++++
 xen/include/xen/sched.h     |  2 ++
 5 files changed, 77 insertions(+), 4 deletions(-)

diff --git a/xen/common/domain.c b/xen/common/domain.c
index c13a7cf..f26267a 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -825,6 +825,9 @@ static void complete_domain_destroy(struct rcu_head *head)
     if ( d->target != NULL )
         put_domain(d->target);
 
+    if ( d->recipient != NULL )
+        put_domain(d->recipient);
+
     evtchn_destroy_final(d);
 
     radix_tree_destroy(&d->pirq_tree, free_pirq_struct);
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index f15dcfe..7e7fb47 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -1177,6 +1177,39 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
     }
     break;
 
+    case XEN_DOMCTL_devour:
+    {
+        struct domain *recipient_dom;
+
+        if ( !d->recipient )
+        {
+            recipient_dom = get_domain_by_id(op->u.devour.recipient);
+            if ( recipient_dom == NULL )
+            {
+                ret = -ESRCH;
+                break;
+            }
+
+            if ( recipient_dom->tot_pages != 0 )
+            {
+                put_domain(recipient_dom);
+                ret = -EINVAL;
+                break;
+            }
+            /*
+             * Make sure no allocation/remapping is ongoing and set is_dying
+             * flag to prevent such actions in future.
+             */
+            spin_lock(&d->page_alloc_lock);
+            d->is_dying = DOMDYING_locked;
+            d->recipient = recipient_dom;
+            smp_wmb(); /* make sure recipient was set before domain_kill() */
+            spin_unlock(&d->page_alloc_lock);
+        }
+        ret = domain_kill(d);
+    }
+    break;
+
     default:
         ret = arch_do_domctl(op, d, u_domctl);
         break;
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 7b4092d..7eb4404 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -1707,6 +1707,7 @@ void free_domheap_pages(struct page_info *pg, unsigned 
int order)
 {
     struct domain *d = page_get_owner(pg);
     unsigned int i;
+    unsigned long mfn, gmfn;
     bool_t drop_dom_ref;
 
     ASSERT(!in_irq());
@@ -1764,13 +1765,32 @@ void free_domheap_pages(struct page_info *pg, unsigned 
int order)
             scrub = 1;
         }
 
-        if ( unlikely(scrub) )
-            for ( i = 0; i < (1 << order); i++ )
-                scrub_one_page(&pg[i]);
+        if ( !d || !d->recipient || d->recipient->is_dying )
+        {
+            if ( unlikely(scrub) )
+                for ( i = 0; i < (1 << order); i++ )
+                    scrub_one_page(&pg[i]);
 
-        free_heap_pages(pg, order);
+            free_heap_pages(pg, order);
+        }
+        else
+        {
+            mfn = page_to_mfn(pg);
+            gmfn = mfn_to_gmfn(d, mfn);
+
+            page_set_owner(pg, NULL);
+            if ( assign_pages(d->recipient, pg, order, 0) )
+                /* assign_pages reports the error by itself */
+                goto out;
+
+            if ( guest_physmap_add_page(d->recipient, gmfn, mfn, order) )
+                printk(XENLOG_G_INFO
+                       "Failed to add MFN %lx (GFN %lx) to Dom%d's physmap\n",
+                       mfn, gmfn, d->recipient->domain_id);
+        }
     }
 
+out:
     if ( drop_dom_ref )
         put_domain(d);
 }
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 57e2ed7..871fa5e 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -995,6 +995,19 @@ struct xen_domctl_psr_cmt_op {
 typedef struct xen_domctl_psr_cmt_op xen_domctl_psr_cmt_op_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cmt_op_t);
 
+/*
+ * XEN_DOMCTL_devour - kills the domain reassigning all of its domheap pages
+ * to the 'recipient' domain. Pages from xen heap belonging to the domain
+ * are not copied. Reassigned pages are mapped to the same GMFNs in the
+ * recipient domain as they were mapped in the original. The recipient domain
+ * is supposed to not have any domheap pages to avoid MFN-GMFN collisions.
+ */
+struct xen_domctl_devour {
+    domid_t recipient;
+};
+typedef struct xen_domctl_devour xen_domctl_devour_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_devour_t);
+
 struct xen_domctl {
     uint32_t cmd;
 #define XEN_DOMCTL_createdomain                   1
@@ -1070,6 +1083,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_setvnumainfo                  74
 #define XEN_DOMCTL_psr_cmt_op                    75
 #define XEN_DOMCTL_arm_configure_domain          76
+#define XEN_DOMCTL_devour                        77
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -1135,6 +1149,7 @@ struct xen_domctl {
         struct xen_domctl_gdbsx_domstatus   gdbsx_domstatus;
         struct xen_domctl_vnuma             vnuma;
         struct xen_domctl_psr_cmt_op        psr_cmt_op;
+        struct xen_domctl_devour            devour;
         uint8_t                             pad[128];
     } u;
 };
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index a42d0b8..552e4a3 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -366,6 +366,8 @@ struct domain
     bool_t           is_privileged;
     /* Which guest this guest has privileges on */
     struct domain   *target;
+    /* Which guest receives freed memory pages */
+    struct domain   *recipient;
     /* Is this guest being debugged by dom0? */
     bool_t           debugger_attached;
     /* Is this guest dying (i.e., a zombie)? */
-- 
1.9.3


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.