From patchwork Mon Aug 1 17:14:27 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamas Lengyel X-Patchwork-Id: 9254643 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 35FD46048B for ; Mon, 1 Aug 2016 17:15:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 219672843C for ; Mon, 1 Aug 2016 17:15:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 165A6284AE; Mon, 1 Aug 2016 17:15:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham version=3.3.1 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.wl.linuxfoundation.org (Postfix) with ESMTPS id 6999E2843C for ; Mon, 1 Aug 2016 17:15:56 +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 1bUGnU-0001DQ-Va; Mon, 01 Aug 2016 17:14:36 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bUGnT-0001Bv-0L for xen-devel@lists.xenproject.org; Mon, 01 Aug 2016 17:14:35 +0000 Received: from [85.158.137.68] by server-8.bemta-3.messagelabs.com id AE/EE-10540-A738F975; Mon, 01 Aug 2016 17:14:34 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFuphkeJIrShJLcpLzFFi42K5GHr/oG5l8/x wg/XP5C2+b5nM5MDocfjDFZYAxijWzLyk/IoE1ownbWuYC/ZGVTxo/MTYwPjEpouRi0NIYCaj xIKrn9hBHBaBNywSH6etZexi5OSQEHjHInH3QmoXIweQHSNx9oYFRLhGYt6fhcwgtpCApsTBD WeYIQZNYpLo2H4RrJdNwEji6tUeNhBbREBJ4t6qyUwgNrPANUaJH0/KQGxhASeJ20/es4LYLA KqEpP6/4PV8wp4SbSs/sIOsUxO4vL0B2wTGPkWMDKsYlQvTi0qSy3SNdJLKspMzyjJTczM0TU 0MNbLTS0uTkxPzUlMKtZLzs/dxAgMk3oGBsYdjKeanQ8xSnIwKYnyejbNDxfiS8pPqcxILM6I LyrNSS0+xCjDwaEkwdsMkhMsSk1PrUjLzAEGLExagoNHSYS3AiTNW1yQmFucmQ6ROsVozLHl9 7W1TBzbpt5byyTEkpeflyolzmsKUioAUppRmgc3CBZJlxhlpYR5GRkYGIR4ClKLcjNLUOVfMY pzMCoJ80aDTOHJzCuB2/cK6BQmoFMS7eeAnFKSiJCSamBsYpx60bRKv9ngn0ma5c3gopbLzw6 cbFl5iIlT/vfjH7NsT8/5PO/PDLGCp5fnF62pLq+417Ig40bQrwtn2mYdlVes3ZvVLJDict88 iXVqUJyBZODOmoeVF7OOcM656m1XUjbJOLBk34PD2u5GYWLZmpsEtty8807xmRTP4YK0GV/aH f8f3M+jxFKckWioxVxUnAgAk5Rrep8CAAA= X-Env-Sender: tamas.lengyel@zentific.com X-Msg-Ref: server-12.tower-31.messagelabs.com!1470071672!36761480!1 X-Originating-IP: [209.85.223.193] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 8.77; banners=-,-,- X-VirusChecked: Checked Received: (qmail 15537 invoked from network); 1 Aug 2016 17:14:33 -0000 Received: from mail-io0-f193.google.com (HELO mail-io0-f193.google.com) (209.85.223.193) by server-12.tower-31.messagelabs.com with AES128-GCM-SHA256 encrypted SMTP; 1 Aug 2016 17:14:33 -0000 Received: by mail-io0-f193.google.com with SMTP id q83so14382905iod.2 for ; Mon, 01 Aug 2016 10:14:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zentific-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=3TkJG+aFU9NifQBhAQxu/SyqXd4BtBoiIxfzzQQXpFA=; b=PFOrcEu9TDrKyId2eVfdCsGatnmfVX5Zr+ZRrEE6qI5zeXkAif1iT/wwAfT3h2TTVw vjJgLcvRnOc0C/Ry0B8dnwxG+rmSs1LVCPD995EDKdzmqwa94JRlVQul+f1Mc3Xolidb p3Whwsqlxel7274vYTylRPxklUjQy9XiHQalZ5AlRSuZI4zH3G2zivIyrepvH8DWxewE adwP/7/zsESdcQ/aXOvg4OzgK2P4yu2gElAXmbxzi0G3WLOBiX7TwbLVRYJ+MRe2RTCZ N/JwbwPB2LrBkYuniyx4dPsqJiNcmjg6rtVlj7N8P44JpE15rVcgkaRFcVXrbWt8YOZq siCQ== 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=3TkJG+aFU9NifQBhAQxu/SyqXd4BtBoiIxfzzQQXpFA=; b=Dtzp/T1CXEMV3WAyEjjv69bfyAy9OKl+QLGfM1aeyAthoVH0HywpmKYm/fDY1hFfXF eJbbbXaJsm6samFgeMgMJSW1XpkKT/2XE+CB6U12lTfe/6y6kmYFnB22hyVLE6D54q7o KxtimofWPkERtJ2HG6gotbgigK2afYQ8xn+7IHNHzynI2eycYQl8YMT9TZv0LB7pJWTL skOKVLJDPDUt1JQKybKZXHsg0Fx2P1UfnAaG5EtpOfNMoT9mGzX/NTznqPCn4wXiihv2 1kJtm1d0qU8fmoBMYhiYQBRFWbTUJ5y3drNrStR+M8VAHWCmyGqe3elKceyMcdUX4Siv mUtQ== X-Gm-Message-State: AEkoouthOhMsukyW7EaKYHVaYCtDKX786ukpJPdX9q5y2nNDfuGf23DBocLGoun+vD1F8g== X-Received: by 10.107.135.142 with SMTP id r14mr63743586ioi.133.1470071671735; Mon, 01 Aug 2016 10:14:31 -0700 (PDT) Received: from l1.lan (c-73-14-35-59.hsd1.co.comcast.net. [73.14.35.59]) by smtp.gmail.com with ESMTPSA id l63sm14095540ioi.14.2016.08.01.10.14.29 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 01 Aug 2016 10:14:30 -0700 (PDT) From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Date: Mon, 1 Aug 2016 11:14:27 -0600 Message-Id: <1470071667-32314-1-git-send-email-tamas.lengyel@zentific.com> X-Mailer: git-send-email 2.8.1 Cc: George Dunlap , Tamas K Lengyel , Ian Jackson , Jan Beulich , Andrew Cooper Subject: [Xen-devel] [PATCH v9] x86/mem-sharing: mem-sharing a range of memory 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-Virus-Scanned: ClamAV using ClamSMTP Currently mem-sharing can be performed on a page-by-page basis from the control domain. However, this process is quite wasteful when a range of pages have to be deduplicated. This patch introduces a new mem_sharing memop for range sharing 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 sharing a range of memory. Signed-off-by: Tamas K Lengyel Acked-by: Wei Liu Reviewed-by: Andrew Cooper --- Cc: Ian Jackson Cc: George Dunlap Cc: Jan Beulich Cc: Andrew Cooper v9: style fixes and minor adjustments --- tools/libxc/include/xenctrl.h | 15 ++++ tools/libxc/xc_memshr.c | 19 +++++ tools/tests/mem-sharing/memshrtool.c | 22 ++++++ xen/arch/x86/mm/mem_sharing.c | 142 +++++++++++++++++++++++++++++++++++ xen/include/public/memory.h | 10 ++- 5 files changed, 207 insertions(+), 1 deletion(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index fdc148a..560ce7b 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -2334,6 +2334,21 @@ int xc_memshr_add_to_physmap(xc_interface *xch, domid_t client_domain, unsigned long client_gfn); +/* Allows to deduplicate a range of memory of a client domain. Using + * this function is equivalent of calling xc_memshr_nominate_gfn for each gfn + * in the two domains followed by xc_memshr_share_gfns. + * + * 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_range_share(xc_interface *xch, + domid_t source_domain, + domid_t client_domain, + uint64_t first_gfn, + uint64_t last_gfn); + /* 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..f53a59a 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_range_share(xc_interface *xch, + domid_t source_domain, + domid_t client_domain, + uint64_t first_gfn, + uint64_t last_gfn) +{ + xen_mem_sharing_op_t mso; + + memset(&mso, 0, sizeof(mso)); + + mso.op = XENMEM_sharing_op_range_share; + + mso.u.range.client_domain = client_domain; + mso.u.range.first_gfn = first_gfn; + mso.u.range.last_gfn = last_gfn; + + return xc_memshr_memop(xch, source_domain, &mso); +} + int xc_memshr_domain_resume(xc_interface *xch, domid_t domid) { diff --git a/tools/tests/mem-sharing/memshrtool.c b/tools/tests/mem-sharing/memshrtool.c index 437c7c9..8e5e22b 100644 --- a/tools/tests/mem-sharing/memshrtool.c +++ b/tools/tests/mem-sharing/memshrtool.c @@ -24,6 +24,8 @@ static int usage(const char* prog) printf(" nominate - Nominate a page for sharing.\n"); printf(" share \n"); printf(" - Share two pages.\n"); + printf(" range \n"); + printf(" - Share pages between domains in a range.\n"); printf(" unshare - Unshare a page by grabbing a writable map.\n"); printf(" add-to-physmap \n"); printf(" - Populate a page in a domain with a shared page.\n"); @@ -180,6 +182,26 @@ int main(int argc, const char** argv) } printf("Audit returned %d errors.\n", rc); } + else if( !strcasecmp(cmd, "range") ) + { + domid_t sdomid, cdomid; + int rc; + uint64_t first_gfn, last_gfn; + + if ( argc != 6 ) + return usage(argv[0]); + sdomid = strtol(argv[2], NULL, 0); + cdomid = strtol(argv[3], NULL, 0); + first_gfn = strtoul(argv[4], NULL, 0); + last_gfn = strtoul(argv[5], NULL, 0); + + rc = xc_memshr_range_share(xch, sdomid, cdomid, first_gfn, last_gfn); + if ( rc < 0 ) + { + printf("error executing xc_memshr_range_share: %s\n", strerror(errno)); + return rc; + } + } return 0; } diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index 47e0820..eb7674f 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -1324,6 +1324,58 @@ int relinquish_shared_pages(struct domain *d) return rc; } +static int range_share(struct domain *d, struct domain *cd, + struct mem_sharing_op_range *range) +{ + int rc = 0; + shr_handle_t sh, ch; + unsigned long start = range->opaque ?: range->first_gfn; + + while ( range->last_gfn >= 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, start, 0, &sh); + if ( rc == -ENOMEM ) + break; + + if ( !rc ) + { + rc = mem_sharing_nominate_page(cd, 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, start, sh, + cd, start, ch); + ASSERT(!rc); + } + } + + /* Check for continuation if it's not the last iteration. */ + if ( range->last_gfn >= ++start && hypercall_preempt_check() ) + { + rc = 1; + break; + } + } + + range->opaque = start; + + /* + * The last page may fail with -EINVAL, and for range sharing we don't + * care about that. + */ + if ( range->last_gfn < start && rc == -EINVAL ) + rc = 0; + + return rc; +} + int mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg) { int rc; @@ -1498,6 +1550,96 @@ int mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg) } break; + case XENMEM_sharing_op_range_share: + { + unsigned long max_sgfn, max_cgfn; + struct domain *cd; + + rc = -EINVAL; + if ( mso.u.range._pad[0] || mso.u.range._pad[1] || + mso.u.range._pad[2] ) + goto out; + + /* + * We use opaque for the hypercall continuation value. + * Ideally the user sets this to 0 in the beginning but + * there is no good way of enforcing that here, so we just check + * that it's at least in range. + */ + if ( mso.u.range.opaque && + (mso.u.range.opaque < mso.u.range.first_gfn || + mso.u.range.opaque > mso.u.range.last_gfn) ) + goto out; + + if ( !mem_sharing_enabled(d) ) + goto out; + + rc = rcu_lock_live_remote_domain_by_id(mso.u.range.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; + } + + /* + * Sanity check only, the client should keep the domains paused for + * the duration of this op. + */ + 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 < mso.u.range.first_gfn || + max_sgfn < mso.u.range.last_gfn || + max_cgfn < mso.u.range.first_gfn || + max_cgfn < mso.u.range.last_gfn ) + { + rcu_unlock_domain(cd); + rc = -EINVAL; + goto out; + } + + rc = range_share(d, cd, &mso.u.range); + rcu_unlock_domain(cd); + + 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.range.opaque = 0; + } + 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..3badfb9 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_range_share 8 #define XENMEM_SHARING_OP_S_HANDLE_INVALID (-10) #define XENMEM_SHARING_OP_C_HANDLE_INVALID (-9) @@ -500,7 +501,14 @@ 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_range { /* OP_RANGE_SHARE */ + uint64_aligned_t first_gfn; /* IN: the first gfn */ + uint64_aligned_t last_gfn; /* IN: the last gfn */ + uint64_aligned_t opaque; /* Must be set to 0 */ + domid_t client_domain; /* IN: the client domain id */ + uint16_t _pad[3]; /* Must be set to 0 */ + } range; struct mem_sharing_op_debug { /* OP_DEBUG_xxx */ union { uint64_aligned_t gfn; /* IN: gfn to debug */