From patchwork Mon Jul 18 21:14:40 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamas Lengyel X-Patchwork-Id: 9235293 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 C06FE600BC for ; Mon, 18 Jul 2016 21:18:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A3BFD1FE95 for ; Mon, 18 Jul 2016 21:18:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 97E4C205AF; Mon, 18 Jul 2016 21:18:30 +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 EF6DF1FE95 for ; Mon, 18 Jul 2016 21:18:28 +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 1bPFsP-0007N5-1H; Mon, 18 Jul 2016 21:14:57 +0000 Received: from mail6.bemta14.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1bPFsN-0007My-5P for xen-devel@lists.xenproject.org; Mon, 18 Jul 2016 21:14:55 +0000 Received: from [193.109.254.147] by server-7.bemta-14.messagelabs.com id 84/5D-09881-EC64D875; Mon, 18 Jul 2016 21:14:54 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupjkeJIrShJLcpLzFFi42K5GHrLSfesW2+ 4wbNlqhbft0xmcmD0OPzhCksAYxRrZl5SfkUCa8a353fZCv5GVly/ktjAuM2mi5GLQ0hgJqPE 2yX/2EAcFoE3LBLda2ezgDgSAu9YJB7MnQ+U4QRyYiTuLJnHCGHXSPQeeAEWFxLQlDi44Qwzx KgJTBInmxeCJdgEjCSuXu0Bs0UElCTurZrMBGIzC1xjlPjxpAzEFhZwkth49AnYUBYBVYm5Vx cwg9i8Al4S3a3LmCGWyUlcnv6AbQIj3wJGhlWMGsWpRWWpRbpGFnpJRZnpGSW5iZk5uoaGJnq 5qcXFiempOYlJxXrJ+bmbGIGhUs/AwLiDcd1xv0OMkhxMSqK8qqK94UJ8SfkplRmJxRnxRaU5 qcWHGGU4OJQkePNdgXKCRanpqRVpmTnAoIVJS3DwKInw7ncBSvMWFyTmFmemQ6ROMRpzbPl9b S0Tx7ap99YyCbHk5eelSonz2oJMEgApzSjNgxsEi6ZLjLJSwryMDAwMQjwFqUW5mSWo8q8YxT kYlYR5m0Gm8GTmlcDtewV0ChPQKQaq3SCnlCQipKQaGCfX5GY9uibKp25Sclf/QM727s7QnOJ vT9t6dHwXm0zennBg4eZNu3UeVj92vnGcZ8qab6tP7Lhdud1wZ5R5s7j+KUcus6s7jcpfcrye /Fug5Nrex/L5TpOOzS8MZORslTpYmPt87s6NwvUNsraM2vdPn1AVEdwoPcn87PWs6U9l07/Un 5+Z2KLEUpyRaKjFXFScCAAX/8vZoQIAAA== X-Env-Sender: tamas.lengyel@zentific.com X-Msg-Ref: server-9.tower-27.messagelabs.com!1468876492!54566124!1 X-Originating-IP: [209.85.218.66] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 8.77; banners=-,-,- X-VirusChecked: Checked Received: (qmail 18536 invoked from network); 18 Jul 2016 21:14:53 -0000 Received: from mail-oi0-f66.google.com (HELO mail-oi0-f66.google.com) (209.85.218.66) by server-9.tower-27.messagelabs.com with AES128-GCM-SHA256 encrypted SMTP; 18 Jul 2016 21:14:53 -0000 Received: by mail-oi0-f66.google.com with SMTP id w143so17239587oiw.2 for ; Mon, 18 Jul 2016 14:14:53 -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=ySxzRsveBwUS/G1Sj8WzIVeTXJE17GwvsxbEzgPLpG0=; b=hFltwbGz5AezE03ca4IVATLs3Ps9gzzE4IqS3076oquY+6tULRu6nqkdANot65YbfW jCCOaMReE/VXkSvOORMpFj/suLLvuPbmGFc8EQe6P4i5KRgU44gC/kyCrnNe2nQx0s3y 5cvsIj6mpZ8HA8O7zbswpftAbeNRsvxYtEJExCmmQT6t0IBMFXWsigapqUmykNJ45Yys cWjKVM3E18gRFVDIbw6GSyqBtlebvN5P58c77r8UU5+AvJn5XX7WfMPbiOofOcbJz3nP CPviXWwXNnDClL7yiGXj2mSTqn76/8DqmzTxBS//eovXXNmUxvgHNclMZpQwfZTRIvVe l1Lw== 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=ySxzRsveBwUS/G1Sj8WzIVeTXJE17GwvsxbEzgPLpG0=; b=jrTaNkZVXQ8eMRWyAwzEcDujfunkl2351qlGIJwgL57YHRNdqs2LBOH25rB9iV6ST1 fD195T+YdxGn83GpJeyB53OKPdsiMzg7fRfKo8Hn8ez2awRgUgr+ho0pCk4PAf0K871l sQie7ORQSmagN5DtfTwUo2By/Q0oaaUWzPLqFCQGrcrMNXnJ0ePnr1Z9zVeURo5s7clW 32PQCF531QkIq/Hgmvkzu08ffBxG34ZW9ghbAdt7HdmwRV+ueuqLkINlAKzEHewBa7Fk dI81yfrK0M3ZeQ01qJ1sH9URi/OtMdoTCO/JGf6lvI+mQiOHFhOLRMDH/UWtUzIYBGd8 Y19g== X-Gm-Message-State: ALyK8tLSXHbnGb4hnuvG8wlV4w1xQ/quAGbBO+fSN68YbPBxKHfdehhJec8Gwlqfya775A== X-Received: by 10.202.199.149 with SMTP id x143mr17624956oif.50.1468876491738; Mon, 18 Jul 2016 14:14:51 -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 96sm6796543otj.37.2016.07.18.14.14.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 18 Jul 2016 14:14:51 -0700 (PDT) From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Date: Mon, 18 Jul 2016 15:14:40 -0600 Message-Id: <1468876480-27373-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 v7] 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 --- Cc: Ian Jackson Cc: George Dunlap Cc: Jan Beulich Cc: Andrew Cooper v7: style fixes --- 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 | 140 +++++++++++++++++++++++++++++++++++ xen/include/public/memory.h | 10 ++- 5 files changed, 205 insertions(+), 1 deletion(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index e904bd5..0ca94cd 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, + unsigned long start, + unsigned long end); + /* 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..9eb08b7 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, + unsigned long start, + unsigned long end) +{ + 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.start = start; + mso.u.range.end = end; + + 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..ae1cff3 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 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; + unsigned long start, end; + + if ( argc != 6 ) + return usage(argv[0]); + sdomid = strtol(argv[2], NULL, 0); + cdomid = strtol(argv[3], NULL, 0); + start = strtoul(argv[4], NULL, 0); + end = strtoul(argv[5], NULL, 0); + + rc = xc_memshr_range_share(xch, sdomid, cdomid, start, end); + 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 a522423..6d00228 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -1294,6 +1294,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->_scratchspace ? range->_scratchspace : range->start; + + while( range->end >= 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->end >= ++start && hypercall_preempt_check() ) + { + rc = 1; + break; + } + } + + range->_scratchspace = start; + + /* + * We only propagate -ENOMEM as individual pages may fail with -EINVAL, + * and for range 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 +1520,94 @@ 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 _scratchscape 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._scratchspace && + (mso.u.range._scratchspace < mso.u.range.start || + mso.u.range._scratchspace > mso.u.range.end) ) + 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.start || max_sgfn < mso.u.range.end || + max_cgfn < mso.u.range.start || max_cgfn < mso.u.range.end ) + { + 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._scratchspace = 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..e0bc018 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 start; /* IN: start gfn. */ + uint64_aligned_t end; /* IN: end gfn (inclusive) */ + uint64_aligned_t _scratchspace; /* 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 */