|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v5 4/9] xen: introduce XEN_DOMCTL_devour
New operation sets the 'recipient' domain which will receive 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..bbb0505 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;
+ /* Newly created guest which receives freed memory pages (soft reset) */
+ 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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |