From patchwork Thu May 12 15:25:51 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamas K Lengyel X-Patchwork-Id: 9083091 Return-Path: X-Original-To: patchwork-xen-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id BDFF8BF440 for ; Thu, 12 May 2016 15:28:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A8C122024D for ; Thu, 12 May 2016 15:28:23 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7DC3B201E4 for ; Thu, 12 May 2016 15:28:22 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1b0sUz-0004IU-Hp; Thu, 12 May 2016 15:26:01 +0000 Received: from mail6.bemta6.messagelabs.com ([85.158.143.247]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1b0sUy-0004IL-OS for xen-devel@lists.xenproject.org; Thu, 12 May 2016 15:26:00 +0000 Received: from [85.158.143.35] by server-1.bemta-6.messagelabs.com id C5/2A-18833-880A4375; Thu, 12 May 2016 15:26:00 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpkkeJIrShJLcpLzFFi42K5GHr1oG77ApN wg8aF6hbft0xmcmD0OPzhCksAYxRrZl5SfkUCa8avvxPYCta6Vkw7epalgfGLXhcjF4eQwDRG ibXvd7GAOBIC71gknq14z9jFyAnkxEj0XH3NCmFXSVx5c4kJxBYS0JC4fbORHaL7G6PEmxN72 UASbALaEm2vd4E1iAgoSdxbNRmsgVlAU6LtPcQgYQEPiScdS5lBbBYBVYnpDx+zg9i8As4S66 9/hFomJ3F5+gO2CYy8CxgZVjGqF6cWlaUW6RrpJRVlpmeU5CZm5ugaGpjp5aYWFyemp+YkJhX rJefnbmIEBgQDEOxgXPbX6RCjJAeTkigvX7VJuBBfUn5KZUZicUZ8UWlOavEhRhkODiUJ3uz5 QDnBotT01Iq0zBxgaMKkJTh4lER480HSvMUFibnFmekQqVOMxhxbfl9by8Sxbeq9tUxCLHn5e alS4ryrQUoFQEozSvPgBsFi5hKjrJQwLyPQaUI8BalFuZklqPKvGMU5GJWEeaeCTOHJzCuB2/ cK6BQmoFOqrxuBnFKSiJCSamCMi5m/XVQ2uUV9zqJGDmdbnfbLXze8afm5uGLBr6jfEsJrZ17 6OPP1myViWj6nJhhfC917g/M144LwBx8fK84+/eXoz1f7ZiSqLdgqvvLaVIuklOv33wg1u8xX 8Fdtmlr2w0raqaduRZFlNGOkwaX3byNEfCxLc1knt8/rTDtrOO8xk3FWeeEpJZbijERDLeai4 kQADyPvVZQCAAA= X-Env-Sender: tamas.k.lengyel@gmail.com X-Msg-Ref: server-16.tower-21.messagelabs.com!1463066758!9509762!1 X-Originating-IP: [209.85.213.193] X-SpamReason: No, hits=0.5 required=7.0 tests=BODY_RANDOM_LONG X-StarScan-Received: X-StarScan-Version: 8.34; banners=-,-,- X-VirusChecked: Checked Received: (qmail 13883 invoked from network); 12 May 2016 15:25:59 -0000 Received: from mail-ig0-f193.google.com (HELO mail-ig0-f193.google.com) (209.85.213.193) by server-16.tower-21.messagelabs.com with AES128-GCM-SHA256 encrypted SMTP; 12 May 2016 15:25:59 -0000 Received: by mail-ig0-f193.google.com with SMTP id rc4so32454igc.0 for ; Thu, 12 May 2016 08:25:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=CWgvZH9ac9grdNRkD8V60QctTxWas/AI+Zh2cDfc5Ms=; b=kgw4efBKSoNlSwA239QjOiesW6qKNjxlceC7cYsMxev72Sua4PU8dFl1u9ogtSz6ln xuX1xx40Y3hCcJRRgpDOsj30L43YaC1S1aLnmut7I3tGl67BBXC7gqLVzWUk+yIn/F3a TOsS3wGYtE/no403zdpDvM3reiAUpI62h763Yp8Dn25MXTOMGaaMyYJmXCb9yr5wyX7r jYdp4JBu9qkJWrl+yDi+DYk/awI1B7OgI76BGJzL4sXtk/aqQJ/Qqdak8mNmPlcaoBSv 6+77hTv4vtChajeoTKxorltKmYPLlsbPPbFWbsDeq6dtAfkN9fT0WYFcRI+gwNF9tFdd HciA== X-Gm-Message-State: AOPr4FXb49wgsQUraMvapy5mOxhLtaLZeTKp8zklSvCbCYIgyXuW5L8RgNEDZBUZ8pAZ9g== X-Received: by 10.202.54.212 with SMTP id d203mr5900446oia.23.1463066758099; Thu, 12 May 2016 08:25:58 -0700 (PDT) Received: from l1.UTSARR.NET ([129.115.2.246]) by smtp.gmail.com with ESMTPSA id 90sm3365374otj.15.2016.05.12.08.25.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 12 May 2016 08:25:56 -0700 (PDT) From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Date: Thu, 12 May 2016 09:25:51 -0600 Message-Id: <1463066752-23969-1-git-send-email-tamas@tklengyel.com> X-Mailer: git-send-email 2.8.1 Cc: Tamas K Lengyel Subject: [Xen-devel] [PATCH v3 1/2] x86/mem-sharing: Bulk mem-sharing entire domains X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Spam-Status: No, score=-3.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RCVD_IN_SORBS_WEB, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 Acked-by: Wei Liu --- Ian Jackson George Dunlap Jan Beulich Andrew Cooper v3: Bail if domains are not paused Rename bulk_share struct to just bulk Return -ENOMEM error if nomination fails Return total number of shared pages (not keeping separate count) v2: Stash hypercall continuation start point in xen_mem_sharing_op_t Return number of successfully shared pages in xen_mem_sharing_op_t --- tools/libxc/include/xenctrl.h | 15 +++++++ tools/libxc/xc_memshr.c | 19 ++++++++ xen/arch/x86/mm/mem_sharing.c | 100 ++++++++++++++++++++++++++++++++++++++++++ xen/include/public/memory.h | 14 +++++- 4 files changed, 147 insertions(+), 1 deletion(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index dc54612..29ff13e 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..06176aa 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -1294,6 +1294,43 @@ int relinquish_shared_pages(struct domain *d) return rc; } +static int bulk_share(struct domain *d, struct domain *cd, unsigned long max, + struct mem_sharing_op_bulk *bulk) +{ + int rc; + shr_handle_t sh, ch; + + while( bulk->start <= max ) + { + 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 ) + mem_sharing_share_pages(d, bulk->start, sh, cd, bulk->start, ch); + } + + ++(bulk->start); + + /* Check for continuation if it's not the last iteration. */ + if ( bulk->start < max && hypercall_preempt_check() ) + { + rc = 1; + break; + } + } + + /* We only propagate -ENOMEM so 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 +1505,69 @@ 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 ( !mem_sharing_enabled(d) ) + goto out; + + rc = rcu_lock_live_remote_domain_by_id(mso.u.bulk.client_domain, + &cd); + if ( rc ) + goto out; + + rc = xsm_mem_sharing_op(XSM_DM_PRIV, d, cd, mso.op); + 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, &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.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 fe52ee1..202250a 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -453,6 +453,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) @@ -488,7 +489,18 @@ 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 + used internally and may change + when the hypercall returns. */ + uint64_aligned_t shared; /* OUT: the number of gfns + that are shared after this + operation including pages + already shared before */ + domid_t client_domain; /* IN: the client domain id */ + } bulk; struct mem_sharing_op_debug { /* OP_DEBUG_xxx */ union { uint64_aligned_t gfn; /* IN: gfn to debug */