[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v5 1/2] x86/mem-sharing: Bulk mem-sharing entire domains
On Sat, Jun 11, 2016 at 5:24 PM, Tamas K Lengyel <tamas@xxxxxxxxxxxxx> wrote: > Currently mem-sharing can be performed on a page-by-page base from the control > domain. However, when completely deduplicating (cloning) a VM, this requires > at least 3 hypercalls per page. As the user has to loop through all pages up > to max_gpfn, this process is very slow and wasteful. > > This patch introduces a new mem_sharing memop for bulk deduplication where > the user doesn't have to separately nominate each page in both the source and > destination domain, and the looping over all pages happen in the hypervisor. > This significantly reduces the overhead of completely deduplicating entire > domains. > > Signed-off-by: Tamas K Lengyel <tamas@xxxxxxxxxxxxx> > Acked-by: Wei Liu <wei.liu2@xxxxxxxxxx> > --- > Ian Jackson <ian.jackson@xxxxxxxxxxxxx> > George Dunlap <george.dunlap@xxxxxxxxxxxxx> > Jan Beulich <jbeulich@xxxxxxxx> > Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Missed Cc: here. > > v4: Add padding to bulk op and enforce it being 0 > Use correct XSM permission check > --- > tools/libxc/include/xenctrl.h | 15 ++++++ > tools/libxc/xc_memshr.c | 19 +++++++ > xen/arch/x86/mm/mem_sharing.c | 121 > ++++++++++++++++++++++++++++++++++++++++++ > xen/include/public/memory.h | 15 +++++- > 4 files changed, 169 insertions(+), 1 deletion(-) > > diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h > index 6ae1a2b..34dcc72 100644 > --- a/tools/libxc/include/xenctrl.h > +++ b/tools/libxc/include/xenctrl.h > @@ -2327,6 +2327,21 @@ int xc_memshr_add_to_physmap(xc_interface *xch, > domid_t client_domain, > unsigned long client_gfn); > > +/* Allows to deduplicate the entire memory of a client domain in bulk. Using > + * this function is equivalent of calling xc_memshr_nominate_gfn for each gfn > + * in the two domains followed by xc_memshr_share_gfns. If successfull, > + * returns the number of shared pages in 'shared'. Both domains must be > paused. > + * > + * May fail with -EINVAL if the source and client domain have different > + * memory size or if memory sharing is not enabled on either of the domains. > + * May also fail with -ENOMEM if there isn't enough memory available to store > + * the sharing metadata before deduplication can happen. > + */ > +int xc_memshr_bulk_share(xc_interface *xch, > + domid_t source_domain, > + domid_t client_domain, > + uint64_t *shared); > + > /* Debug calls: return the number of pages referencing the shared frame > backing > * the input argument. Should be one or greater. > * > diff --git a/tools/libxc/xc_memshr.c b/tools/libxc/xc_memshr.c > index deb0aa4..71350d2 100644 > --- a/tools/libxc/xc_memshr.c > +++ b/tools/libxc/xc_memshr.c > @@ -181,6 +181,25 @@ int xc_memshr_add_to_physmap(xc_interface *xch, > return xc_memshr_memop(xch, source_domain, &mso); > } > > +int xc_memshr_bulk_share(xc_interface *xch, > + domid_t source_domain, > + domid_t client_domain, > + uint64_t *shared) > +{ > + int rc; > + xen_mem_sharing_op_t mso; > + > + memset(&mso, 0, sizeof(mso)); > + > + mso.op = XENMEM_sharing_op_bulk_share; > + mso.u.bulk.client_domain = client_domain; > + > + rc = xc_memshr_memop(xch, source_domain, &mso); > + if ( !rc && shared ) *shared = mso.u.bulk.shared; > + > + return rc; > +} > + > int xc_memshr_domain_resume(xc_interface *xch, > domid_t domid) > { > diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c > index a522423..ba06fb0 100644 > --- a/xen/arch/x86/mm/mem_sharing.c > +++ b/xen/arch/x86/mm/mem_sharing.c > @@ -1294,6 +1294,54 @@ int relinquish_shared_pages(struct domain *d) > return rc; > } > > +static int bulk_share(struct domain *d, struct domain *cd, unsigned long > limit, > + struct mem_sharing_op_bulk *bulk) > +{ > + int rc = 0; > + shr_handle_t sh, ch; > + > + while( limit > bulk->start ) > + { > + /* > + * We only break out if we run out of memory as individual pages may > + * legitimately be unsharable and we just want to skip over those. > + */ > + rc = mem_sharing_nominate_page(d, bulk->start, 0, &sh); > + if ( rc == -ENOMEM ) > + break; > + if ( !rc ) > + { > + rc = mem_sharing_nominate_page(cd, bulk->start, 0, &ch); > + if ( rc == -ENOMEM ) > + break; > + if ( !rc ) > + { > + /* If we get here this should be guaranteed to succeed. */ > + rc = mem_sharing_share_pages(d, bulk->start, sh, > + cd, bulk->start, ch); > + ASSERT(!rc); > + } > + } > + > + /* Check for continuation if it's not the last iteration. */ > + if ( limit > ++bulk->start && hypercall_preempt_check() ) > + { > + rc = 1; > + break; > + } > + } > + > + /* > + * We only propagate -ENOMEM as individual pages may fail with -EINVAL, > + * and for bulk sharing we only care if -ENOMEM was encountered so we > reset > + * rc here. > + */ > + if ( rc < 0 && rc != -ENOMEM ) > + rc = 0; > + > + return rc; > +} > + > int mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg) > { > int rc; > @@ -1468,6 +1516,79 @@ int > mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg) > } > break; > > + case XENMEM_sharing_op_bulk_share: > + { > + unsigned long max_sgfn, max_cgfn; > + struct domain *cd; > + > + rc = -EINVAL; > + if( mso.u.bulk._pad[0] || mso.u.bulk._pad[1] || > mso.u.bulk._pad[2] ) > + goto out; > + > + if ( !mem_sharing_enabled(d) ) > + goto out; > + > + rc = rcu_lock_live_remote_domain_by_id(mso.u.bulk.client_domain, > + &cd); > + if ( rc ) > + goto out; > + > + /* > + * We reuse XENMEM_sharing_op_share XSM check here as this is > essentially > + * the same concept repeated over multiple pages. > + */ > + rc = xsm_mem_sharing_op(XSM_DM_PRIV, d, cd, > XENMEM_sharing_op_share); > + if ( rc ) > + { > + rcu_unlock_domain(cd); > + goto out; > + } > + > + if ( !mem_sharing_enabled(cd) ) > + { > + rcu_unlock_domain(cd); > + rc = -EINVAL; > + goto out; > + } > + > + if ( !atomic_read(&d->pause_count) || > + !atomic_read(&cd->pause_count) ) > + { > + rcu_unlock_domain(cd); > + rc = -EINVAL; > + goto out; > + } > + > + max_sgfn = domain_get_maximum_gpfn(d); > + max_cgfn = domain_get_maximum_gpfn(cd); > + > + if ( max_sgfn != max_cgfn || max_sgfn < mso.u.bulk.start ) > + { > + rcu_unlock_domain(cd); > + rc = -EINVAL; > + goto out; > + } > + > + rc = bulk_share(d, cd, max_sgfn + 1, &mso.u.bulk); > + if ( rc > 0 ) > + { > + if ( __copy_to_guest(arg, &mso, 1) ) > + rc = -EFAULT; > + else > + rc = > hypercall_create_continuation(__HYPERVISOR_memory_op, > + "lh", > XENMEM_sharing_op, > + arg); > + } > + else > + { > + mso.u.bulk.start = 0; > + mso.u.bulk.shared = atomic_read(&cd->shr_pages); > + } > + > + rcu_unlock_domain(cd); > + } > + break; > + > case XENMEM_sharing_op_debug_gfn: > { > unsigned long gfn = mso.u.debug.u.gfn; > diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h > index 29ec571..084f06e 100644 > --- a/xen/include/public/memory.h > +++ b/xen/include/public/memory.h > @@ -465,6 +465,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_mem_access_op_t); > #define XENMEM_sharing_op_debug_gref 5 > #define XENMEM_sharing_op_add_physmap 6 > #define XENMEM_sharing_op_audit 7 > +#define XENMEM_sharing_op_bulk_share 8 > > #define XENMEM_SHARING_OP_S_HANDLE_INVALID (-10) > #define XENMEM_SHARING_OP_C_HANDLE_INVALID (-9) > @@ -500,7 +501,19 @@ struct xen_mem_sharing_op { > uint64_aligned_t client_gfn; /* IN: the client gfn */ > uint64_aligned_t client_handle; /* IN: handle to the client page > */ > domid_t client_domain; /* IN: the client domain id */ > - } share; > + } share; > + struct mem_sharing_op_bulk { /* OP_BULK_SHARE */ > + uint64_aligned_t start; /* IN: start gfn. Set to 0 for > + full deduplication. Field is > + reset to 0 when hypercall > + completes */ > + uint64_aligned_t shared; /* OUT: the number of gfns > + that are shared after this > + operation, including pages > + that were already shared */ > + domid_t client_domain; /* IN: the client domain id */ > + uint16_t _pad[3]; > + } bulk; > struct mem_sharing_op_debug { /* OP_DEBUG_xxx */ > union { > uint64_aligned_t gfn; /* IN: gfn to debug */ > -- > 2.8.1 > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |