From patchwork Tue Mar 29 14:03:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamas K Lengyel X-Patchwork-Id: 12794895 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B9A1AC4332F for ; Tue, 29 Mar 2022 14:04:37 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.295841.503587 (Exim 4.92) (envelope-from ) id 1nZCSG-0008Pw-IS; Tue, 29 Mar 2022 14:04:16 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 295841.503587; Tue, 29 Mar 2022 14:04:16 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1nZCSG-0008Pp-EB; Tue, 29 Mar 2022 14:04:16 +0000 Received: by outflank-mailman (input) for mailman id 295841; Tue, 29 Mar 2022 14:04:15 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1nZCSE-0008Pe-Pb for xen-devel@lists.xenproject.org; Tue, 29 Mar 2022 14:04:15 +0000 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 1929a52e-af69-11ec-8fbc-03012f2f19d4; Tue, 29 Mar 2022 16:04:09 +0200 (CEST) Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Mar 2022 07:04:08 -0700 Received: from tlengyel-mobl3.amr.corp.intel.com (HELO localhost.localdomain) ([10.212.29.163]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Mar 2022 07:04:06 -0700 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 1929a52e-af69-11ec-8fbc-03012f2f19d4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1648562651; x=1680098651; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=r2hq6EJ3nE5Ns7N1HiuCsO/GX8EEWS3F/6vdp4nzR2w=; b=AAHm23MmhpIiDz6JOVt1KeWjt6VMMWL6vveOXJy5Rya2y/TWSJvnIQj1 rMj0bvEr9MRth12hCLV1Y6g263mth2MvKYzzFnZD32rIJZs8k1NzpkQiO ftt4zownwLHodcSBpfsr1L+4T6Mw1vCa9+XlYFCRHg5uiayYdrCtzHSX0 7eCb+YJKdoPXrawfqbX4LZjgC4biiK6qvytFJUB4lLdeutwHfngLin9Rg D1TGyIUliwCrErX4tNJjLVGLHpTK8BPvgeOeTWREqsvudy7Pw4OvnueBe Jh0hD0O7HjJDRcZ878p1QYToj9RLsaIbOwzH6V06ZMm32YNK0qk3Lba3M A==; X-IronPort-AV: E=McAfee;i="6200,9189,10301"; a="239853158" X-IronPort-AV: E=Sophos;i="5.90,220,1643702400"; d="scan'208";a="239853158" X-IronPort-AV: E=Sophos;i="5.90,220,1643702400"; d="scan'208";a="652987555" From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Cc: Tamas K Lengyel , Wei Liu , Anthony PERARD , Juergen Gross , Andrew Cooper , George Dunlap , Jan Beulich , Julien Grall , Stefano Stabellini , Jun Nakajima , Kevin Tian , =?utf-8?q?Roger_Pau_Monn=C3=A9?= , Tamas K Lengyel Subject: [PATCH v2 1/3] x86/mem_sharing: option to enforce fork starting with empty p2m Date: Tue, 29 Mar 2022 10:03:20 -0400 Message-Id: X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 Add option to the fork memop to enforce a start with an empty p2m. Pre-populating special pages to the fork tend to be necessary only when setting up forks to be fully functional with a toolstack or if the fork makes use of them in some way. For short-lived forks these pages are optional and starting with an empty p2m has advantages both in terms of reset performance as well as easier reasoning about the state of the fork after creation. Signed-off-by: Tamas K Lengyel --- v2: rename flag to empty_p2m, add assert at the end and move vAPIC page mapping skipping logic into where its mapped --- tools/include/xenctrl.h | 3 ++- tools/libs/ctrl/xc_memshr.c | 5 +++- xen/arch/x86/hvm/vmx/vmx.c | 5 ++++ xen/arch/x86/include/asm/hvm/domain.h | 4 +++- xen/arch/x86/mm/mem_sharing.c | 33 +++++++++++++++++---------- xen/include/public/memory.h | 4 ++-- 6 files changed, 37 insertions(+), 17 deletions(-) diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h index 95bd5eca67..26766ec19f 100644 --- a/tools/include/xenctrl.h +++ b/tools/include/xenctrl.h @@ -2281,7 +2281,8 @@ int xc_memshr_fork(xc_interface *xch, uint32_t source_domain, uint32_t client_domain, bool allow_with_iommu, - bool block_interrupts); + bool block_interrupts, + bool empty_p2m); /* * Note: this function is only intended to be used on short-lived forks that diff --git a/tools/libs/ctrl/xc_memshr.c b/tools/libs/ctrl/xc_memshr.c index a6cfd7dccf..0143f9ddea 100644 --- a/tools/libs/ctrl/xc_memshr.c +++ b/tools/libs/ctrl/xc_memshr.c @@ -240,7 +240,8 @@ int xc_memshr_debug_gref(xc_interface *xch, } int xc_memshr_fork(xc_interface *xch, uint32_t pdomid, uint32_t domid, - bool allow_with_iommu, bool block_interrupts) + bool allow_with_iommu, bool block_interrupts, + bool empty_p2m) { xen_mem_sharing_op_t mso; @@ -253,6 +254,8 @@ int xc_memshr_fork(xc_interface *xch, uint32_t pdomid, uint32_t domid, mso.u.fork.flags |= XENMEM_FORK_WITH_IOMMU_ALLOWED; if ( block_interrupts ) mso.u.fork.flags |= XENMEM_FORK_BLOCK_INTERRUPTS; + if ( empty_p2m ) + mso.u.fork.flags |= XENMEM_FORK_EMPTY_P2M; return xc_memshr_memop(xch, domid, &mso); } diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index c075370f64..5e60c92d5c 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -424,6 +424,11 @@ static void cf_check domain_creation_finished(struct domain *d) if ( !has_vlapic(d) || mfn_eq(apic_access_mfn, INVALID_MFN) ) return; +#ifdef CONFIG_MEM_SHARING + if ( d->arch.hvm.mem_sharing.empty_p2m ) + return; +#endif + ASSERT(epte_get_entry_emt(d, gfn, apic_access_mfn, 0, &ipat, p2m_mmio_direct) == MTRR_TYPE_WRBACK); ASSERT(ipat); diff --git a/xen/arch/x86/include/asm/hvm/domain.h b/xen/arch/x86/include/asm/hvm/domain.h index 698455444e..22a17c36c5 100644 --- a/xen/arch/x86/include/asm/hvm/domain.h +++ b/xen/arch/x86/include/asm/hvm/domain.h @@ -31,7 +31,9 @@ #ifdef CONFIG_MEM_SHARING struct mem_sharing_domain { - bool enabled, block_interrupts; + bool enabled; + bool block_interrupts; + bool empty_p2m; /* * When releasing shared gfn's in a preemptible manner, recall where diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index 15e6a7ed81..ef67285a98 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -1643,7 +1643,8 @@ static int bring_up_vcpus(struct domain *cd, struct domain *d) return 0; } -static int copy_vcpu_settings(struct domain *cd, const struct domain *d) +static int copy_vcpu_settings(struct domain *cd, const struct domain *d, + bool empty_p2m) { unsigned int i; struct p2m_domain *p2m = p2m_get_hostp2m(cd); @@ -1660,7 +1661,7 @@ static int copy_vcpu_settings(struct domain *cd, const struct domain *d) /* Copy & map in the vcpu_info page if the guest uses one */ vcpu_info_mfn = d_vcpu->vcpu_info_mfn; - if ( !mfn_eq(vcpu_info_mfn, INVALID_MFN) ) + if ( !empty_p2m && !mfn_eq(vcpu_info_mfn, INVALID_MFN) ) { mfn_t new_vcpu_info_mfn = cd_vcpu->vcpu_info_mfn; @@ -1807,17 +1808,18 @@ static int copy_special_pages(struct domain *cd, struct domain *d) return 0; } -static int copy_settings(struct domain *cd, struct domain *d) +static int copy_settings(struct domain *cd, struct domain *d, + bool empty_p2m) { int rc; - if ( (rc = copy_vcpu_settings(cd, d)) ) + if ( (rc = copy_vcpu_settings(cd, d, empty_p2m)) ) return rc; if ( (rc = hvm_copy_context_and_params(cd, d)) ) return rc; - if ( (rc = copy_special_pages(cd, d)) ) + if ( !empty_p2m && (rc = copy_special_pages(cd, d)) ) return rc; copy_tsc(cd, d); @@ -1826,9 +1828,11 @@ static int copy_settings(struct domain *cd, struct domain *d) return rc; } -static int fork(struct domain *cd, struct domain *d) +static int fork(struct domain *cd, struct domain *d, uint16_t flags) { int rc = -EBUSY; + bool block_interrupts = flags & XENMEM_FORK_BLOCK_INTERRUPTS; + bool empty_p2m = flags & XENMEM_FORK_EMPTY_P2M; if ( !cd->controller_pause_count ) return rc; @@ -1856,7 +1860,13 @@ static int fork(struct domain *cd, struct domain *d) if ( (rc = bring_up_vcpus(cd, d)) ) goto done; - rc = copy_settings(cd, d); + if ( !(rc = copy_settings(cd, d, empty_p2m)) ) + { + cd->arch.hvm.mem_sharing.block_interrupts = block_interrupts; + + if ( (cd->arch.hvm.mem_sharing.empty_p2m = empty_p2m) ) + ASSERT(page_list_empty(&cd->page_list)); + } done: if ( rc && rc != -ERESTART ) @@ -1920,7 +1930,7 @@ static int mem_sharing_fork_reset(struct domain *d) } spin_unlock_recursive(&d->page_alloc_lock); - rc = copy_settings(d, pd); + rc = copy_settings(d, pd, d->arch.hvm.mem_sharing.empty_p2m); domain_unpause(d); @@ -2190,7 +2200,8 @@ int mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg) if ( mso.u.fork.pad ) goto out; if ( mso.u.fork.flags & - ~(XENMEM_FORK_WITH_IOMMU_ALLOWED | XENMEM_FORK_BLOCK_INTERRUPTS) ) + ~(XENMEM_FORK_WITH_IOMMU_ALLOWED | XENMEM_FORK_BLOCK_INTERRUPTS | + XENMEM_FORK_EMPTY_P2M) ) goto out; rc = rcu_lock_live_remote_domain_by_id(mso.u.fork.parent_domain, @@ -2212,14 +2223,12 @@ int mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg) goto out; } - rc = fork(d, pd); + rc = fork(d, pd, mso.u.fork.flags); if ( rc == -ERESTART ) rc = hypercall_create_continuation(__HYPERVISOR_memory_op, "lh", XENMEM_sharing_op, arg); - else if ( !rc && (mso.u.fork.flags & XENMEM_FORK_BLOCK_INTERRUPTS) ) - d->arch.hvm.mem_sharing.block_interrupts = true; rcu_unlock_domain(pd); break; diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h index a1a0f0233a..d44c256b3c 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -543,10 +543,10 @@ struct xen_mem_sharing_op { } debug; struct mem_sharing_op_fork { /* OP_FORK */ domid_t parent_domain; /* IN: parent's domain id */ -/* Only makes sense for short-lived forks */ +/* These flags only makes sense for short-lived forks */ #define XENMEM_FORK_WITH_IOMMU_ALLOWED (1u << 0) -/* Only makes sense for short-lived forks */ #define XENMEM_FORK_BLOCK_INTERRUPTS (1u << 1) +#define XENMEM_FORK_EMPTY_P2M (1u << 2) uint16_t flags; /* IN: optional settings */ uint32_t pad; /* Must be set to 0 */ } fork; From patchwork Tue Mar 29 14:03:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamas K Lengyel X-Patchwork-Id: 12794894 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B507BC433EF for ; Tue, 29 Mar 2022 14:04:37 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.295842.503592 (Exim 4.92) (envelope-from ) id 1nZCSG-0008TU-Qw; Tue, 29 Mar 2022 14:04:16 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 295842.503592; Tue, 29 Mar 2022 14:04:16 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1nZCSG-0008Sd-MG; Tue, 29 Mar 2022 14:04:16 +0000 Received: by outflank-mailman (input) for mailman id 295842; Tue, 29 Mar 2022 14:04:15 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1nZCSF-0008Pe-LR for xen-devel@lists.xenproject.org; Tue, 29 Mar 2022 14:04:15 +0000 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 1c0f1eef-af69-11ec-8fbc-03012f2f19d4; Tue, 29 Mar 2022 16:04:12 +0200 (CEST) Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Mar 2022 07:04:09 -0700 Received: from tlengyel-mobl3.amr.corp.intel.com (HELO localhost.localdomain) ([10.212.29.163]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Mar 2022 07:04:08 -0700 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 1c0f1eef-af69-11ec-8fbc-03012f2f19d4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1648562654; x=1680098654; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=43ECNuCX2PPxh+aosXm++u7sNS4fbK0+kwt3CNxi5Z0=; b=ACEM4YQIV9ZvFsyIy1swlJxwuA/H46YxXT0sP2DWp9+tGYDcTJaHuSft RDDll+FKjoP4XCEMdZDDH6ijzL+U7tkoia8a0iU+WWDyrPEQqJyIUFOVG RMeSvjfSZpCyrPuXeOz0bfZhk7MO5dX6WkQjWPcQHVSnVc8Ae7jZJnawC B7Sce3VrPpf7lYWl27QqJtSXa3d7CNAVOwljrOaE3mINoD6UFF8vboYOi 08hZSudjj2U5n0LWrDdq6UUuD3ZT4gQ4p/vE76vgAAdcp5D8sOVUtyeqT rU47mT/N4yzu4LwihltTO7RqFn8C5c1jen70syWbIC2FHRKtXRGRlCETW A==; X-IronPort-AV: E=McAfee;i="6200,9189,10301"; a="239853164" X-IronPort-AV: E=Sophos;i="5.90,220,1643702400"; d="scan'208";a="239853164" X-IronPort-AV: E=Sophos;i="5.90,220,1643702400"; d="scan'208";a="652987568" From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Cc: Tamas K Lengyel , Jan Beulich , Andrew Cooper , =?utf-8?q?Roger_Pau_Monn=C3=A9?= , Wei Liu , Tamas K Lengyel , George Dunlap Subject: [PATCH v2 2/3] x86/mem_sharing: add fork_complete field to mem_sharing_domain Date: Tue, 29 Mar 2022 10:03:21 -0400 Message-Id: <10b1b71d918b7d7315b49b5932497d094f767a1e.1648561546.git.tamas.lengyel@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 The fork's physmap should only be populated with select special pages during the setup of the fork. The rest of the fork's physmap should only be populated as needed after the fork is complete. Add a field to specify when the fork is complete so fork_page() can determine whether it's time to start adding entries to the physmap. Signed-off-by: Tamas K Lengyel Acked-by: Jan Beulich --- v2: replace previous patch that set parent to dom_cow as a placeholder --- xen/arch/x86/include/asm/hvm/domain.h | 1 + xen/arch/x86/mm/mem_sharing.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/include/asm/hvm/domain.h b/xen/arch/x86/include/asm/hvm/domain.h index 22a17c36c5..7078d041bd 100644 --- a/xen/arch/x86/include/asm/hvm/domain.h +++ b/xen/arch/x86/include/asm/hvm/domain.h @@ -32,6 +32,7 @@ struct mem_sharing_domain { bool enabled; + bool fork_complete; bool block_interrupts; bool empty_p2m; diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index ef67285a98..bfde342a38 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -1555,7 +1555,7 @@ int mem_sharing_fork_page(struct domain *d, gfn_t gfn, bool unsharing) p2m_type_t p2mt; struct page_info *page; - if ( !mem_sharing_is_fork(d) ) + if ( !d->arch.hvm.mem_sharing.fork_complete ) return -ENOENT; if ( !unsharing ) @@ -1862,6 +1862,7 @@ static int fork(struct domain *cd, struct domain *d, uint16_t flags) if ( !(rc = copy_settings(cd, d, empty_p2m)) ) { + cd->arch.hvm.mem_sharing.fork_complete = true; cd->arch.hvm.mem_sharing.block_interrupts = block_interrupts; if ( (cd->arch.hvm.mem_sharing.empty_p2m = empty_p2m) ) From patchwork Tue Mar 29 14:03:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamas K Lengyel X-Patchwork-Id: 12794896 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id B50B2C433FE for ; Tue, 29 Mar 2022 14:04:37 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.295843.503609 (Exim 4.92) (envelope-from ) id 1nZCSK-0000Un-28; Tue, 29 Mar 2022 14:04:20 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 295843.503609; Tue, 29 Mar 2022 14:04:20 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1nZCSJ-0000Ug-V1; Tue, 29 Mar 2022 14:04:19 +0000 Received: by outflank-mailman (input) for mailman id 295843; Tue, 29 Mar 2022 14:04:18 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1nZCSI-0000Ow-19 for xen-devel@lists.xenproject.org; Tue, 29 Mar 2022 14:04:18 +0000 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 1c5ff81f-af69-11ec-a405-831a346695d4; Tue, 29 Mar 2022 16:04:14 +0200 (CEST) Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Mar 2022 07:04:12 -0700 Received: from tlengyel-mobl3.amr.corp.intel.com (HELO localhost.localdomain) ([10.212.29.163]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Mar 2022 07:04:09 -0700 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 1c5ff81f-af69-11ec-a405-831a346695d4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1648562654; x=1680098654; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=+8+ET7KVGpLminOLzDYelfXHOUx6SBUWvMMkONAQxJk=; b=m8tWoN0jddMXHG751REfwW2VHvBqQtT883Z9tD06KMMRyVqeOOtZNlwy E2Z1uK2iRxT40KHB+pScz+tLFrARQr2sRAGtKQBTKP2fpqCLLNuJF8qVc jFEIJPtWatVoWH10XI5x0y0rccjSH9xDy9wWdvcLjiuoYColC4NBbW7c9 1ngemLoEtA3Pij2/GEMfIvQU0kvSn2ghmGMrm+JcpHjkskMCl0QKViVFL t77wPBpegVhheehhtLSUC5VkCzyH+dZjIk9HID0W24SbZUDuhodiYaAW8 wCRc83WLOB9SKYS3PYamsx45x62eRM6LeuX1INVUg8sKL+hXy85j79F2a Q==; X-IronPort-AV: E=McAfee;i="6200,9189,10301"; a="239853176" X-IronPort-AV: E=Sophos;i="5.90,220,1643702400"; d="scan'208";a="239853176" X-IronPort-AV: E=Sophos;i="5.90,220,1643702400"; d="scan'208";a="652987598" From: Tamas K Lengyel To: xen-devel@lists.xenproject.org Cc: Tamas K Lengyel , Wei Liu , Anthony PERARD , Juergen Gross , Andrew Cooper , George Dunlap , Jan Beulich , Julien Grall , Stefano Stabellini , =?utf-8?q?Roger_Pau_Monn=C3=A9?= , Tamas K Lengyel , Alexandru Isaila , Petre Pircalabu Subject: [PATCH v2 3/3] x86/mem_sharing: make fork_reset more configurable Date: Tue, 29 Mar 2022 10:03:22 -0400 Message-Id: <3ebadf898bf9e165d657a31c0aa98bbd300ffcb2.1648561546.git.tamas.lengyel@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Allow specify distinct parts of the fork VM to be reset. This is useful when a fuzzing operation involves mapping in only a handful of pages that are known ahead of time. Throwing these pages away just to be re-copied immediately is expensive, thus allowing to specify partial resets can speed things up. Also allow resetting to be initiated from vm_event responses as an optiomization. Signed-off-by: Tamas K Lengyel --- v2: address review comments and add more sanity checking --- tools/include/xenctrl.h | 3 ++- tools/libs/ctrl/xc_memshr.c | 7 ++++++- xen/arch/x86/include/asm/mem_sharing.h | 9 +++++++++ xen/arch/x86/mm/mem_sharing.c | 27 +++++++++++++++++++++----- xen/common/vm_event.c | 15 ++++++++++++++ xen/include/public/memory.h | 4 +++- xen/include/public/vm_event.h | 8 ++++++++ 7 files changed, 65 insertions(+), 8 deletions(-) diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h index 26766ec19f..8a5b125aae 100644 --- a/tools/include/xenctrl.h +++ b/tools/include/xenctrl.h @@ -2291,7 +2291,8 @@ int xc_memshr_fork(xc_interface *xch, * * With VMs that have a lot of memory this call may block for a long time. */ -int xc_memshr_fork_reset(xc_interface *xch, uint32_t forked_domain); +int xc_memshr_fork_reset(xc_interface *xch, uint32_t forked_domain, + bool reset_state, bool reset_memory); /* Debug calls: return the number of pages referencing the shared frame backing * the input argument. Should be one or greater. diff --git a/tools/libs/ctrl/xc_memshr.c b/tools/libs/ctrl/xc_memshr.c index 0143f9ddea..5044d5b83e 100644 --- a/tools/libs/ctrl/xc_memshr.c +++ b/tools/libs/ctrl/xc_memshr.c @@ -260,12 +260,17 @@ int xc_memshr_fork(xc_interface *xch, uint32_t pdomid, uint32_t domid, return xc_memshr_memop(xch, domid, &mso); } -int xc_memshr_fork_reset(xc_interface *xch, uint32_t domid) +int xc_memshr_fork_reset(xc_interface *xch, uint32_t domid, bool reset_state, + bool reset_memory) { xen_mem_sharing_op_t mso; memset(&mso, 0, sizeof(mso)); mso.op = XENMEM_sharing_op_fork_reset; + if ( reset_state ) + mso.u.fork.flags |= XENMEM_FORK_RESET_STATE; + if ( reset_memory ) + mso.u.fork.flags |= XENMEM_FORK_RESET_MEMORY; return xc_memshr_memop(xch, domid, &mso); } diff --git a/xen/arch/x86/include/asm/mem_sharing.h b/xen/arch/x86/include/asm/mem_sharing.h index cf7a12f4d2..2c00069bc9 100644 --- a/xen/arch/x86/include/asm/mem_sharing.h +++ b/xen/arch/x86/include/asm/mem_sharing.h @@ -85,6 +85,9 @@ static inline bool mem_sharing_is_fork(const struct domain *d) int mem_sharing_fork_page(struct domain *d, gfn_t gfn, bool unsharing); +int mem_sharing_fork_reset(struct domain *d, bool reset_state, + bool reset_memory); + /* * If called by a foreign domain, possible errors are * -EBUSY -> ring full @@ -148,6 +151,12 @@ static inline int mem_sharing_fork_page(struct domain *d, gfn_t gfn, bool lock) return -EOPNOTSUPP; } +static inline int mem_sharing_fork_reset(struct domain *d, bool reset_state, + bool reset_memory) +{ + return -EOPNOTSUPP; +} + #endif #endif /* __MEM_SHARING_H__ */ diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c index bfde342a38..11c74e3905 100644 --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -1890,15 +1890,24 @@ static int fork(struct domain *cd, struct domain *d, uint16_t flags) * footprints the hypercall continuation should be implemented (or if this * feature needs to be become "stable"). */ -static int mem_sharing_fork_reset(struct domain *d) +int mem_sharing_fork_reset(struct domain *d, bool reset_state, + bool reset_memory) { - int rc; + int rc = 0; struct domain *pd = d->parent; struct p2m_domain *p2m = p2m_get_hostp2m(d); struct page_info *page, *tmp; + ASSERT(reset_state || reset_memory); + + if ( !d->arch.hvm.mem_sharing.fork_complete ) + return -ENOSYS; + domain_pause(d); + if ( !reset_memory ) + goto state; + /* need recursive lock because we will free pages */ spin_lock_recursive(&d->page_alloc_lock); page_list_for_each_safe(page, tmp, &d->page_list) @@ -1931,7 +1940,9 @@ static int mem_sharing_fork_reset(struct domain *d) } spin_unlock_recursive(&d->page_alloc_lock); - rc = copy_settings(d, pd, d->arch.hvm.mem_sharing.empty_p2m); + state: + if ( reset_state ) + rc = copy_settings(d, pd, d->arch.hvm.mem_sharing.empty_p2m); domain_unpause(d); @@ -2237,15 +2248,21 @@ int mem_sharing_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_sharing_op_t) arg) case XENMEM_sharing_op_fork_reset: { + bool reset_state = mso.u.fork.flags & XENMEM_FORK_RESET_STATE; + bool reset_memory = mso.u.fork.flags & XENMEM_FORK_RESET_MEMORY; + rc = -EINVAL; - if ( mso.u.fork.pad || mso.u.fork.flags ) + if ( mso.u.fork.pad || (!reset_state && !reset_memory) ) + goto out; + if ( mso.u.fork.flags & + ~(XENMEM_FORK_RESET_STATE | XENMEM_FORK_RESET_MEMORY) ) goto out; rc = -ENOSYS; if ( !d->parent ) goto out; - rc = mem_sharing_fork_reset(d); + rc = mem_sharing_fork_reset(d, reset_state, reset_memory); break; } diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c index 84cf52636b..d26a6699fc 100644 --- a/xen/common/vm_event.c +++ b/xen/common/vm_event.c @@ -28,6 +28,11 @@ #include #include #include + +#ifdef CONFIG_MEM_SHARING +#include +#endif + #include #include @@ -394,6 +399,16 @@ static int vm_event_resume(struct domain *d, struct vm_event_domain *ved) if ( rsp.reason == VM_EVENT_REASON_MEM_PAGING ) p2m_mem_paging_resume(d, &rsp); #endif +#ifdef CONFIG_MEM_SHARING + if ( mem_sharing_is_fork(d) ) + { + bool reset_state = rsp.flags & VM_EVENT_FLAG_RESET_FORK_STATE; + bool reset_mem = rsp.flags & VM_EVENT_FLAG_RESET_FORK_MEMORY; + + if ( reset_state || reset_mem ) + ASSERT(!mem_sharing_fork_reset(d, reset_state, reset_mem)); + } +#endif /* * Check emulation flags in the arch-specific handler only, as it diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h index d44c256b3c..2a4edfc84b 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -541,12 +541,14 @@ struct xen_mem_sharing_op { uint32_t gref; /* IN: gref to debug */ } u; } debug; - struct mem_sharing_op_fork { /* OP_FORK */ + struct mem_sharing_op_fork { /* OP_FORK/_RESET */ domid_t parent_domain; /* IN: parent's domain id */ /* These flags only makes sense for short-lived forks */ #define XENMEM_FORK_WITH_IOMMU_ALLOWED (1u << 0) #define XENMEM_FORK_BLOCK_INTERRUPTS (1u << 1) #define XENMEM_FORK_EMPTY_P2M (1u << 2) +#define XENMEM_FORK_RESET_STATE (1u << 3) +#define XENMEM_FORK_RESET_MEMORY (1u << 4) uint16_t flags; /* IN: optional settings */ uint32_t pad; /* Must be set to 0 */ } fork; diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h index bb003d21d0..81c2ee28cc 100644 --- a/xen/include/public/vm_event.h +++ b/xen/include/public/vm_event.h @@ -127,6 +127,14 @@ * Reset the vmtrace buffer (if vmtrace is enabled) */ #define VM_EVENT_FLAG_RESET_VMTRACE (1 << 13) +/* + * Reset the VM state (if VM is fork) + */ +#define VM_EVENT_FLAG_RESET_FORK_STATE (1 << 14) +/* + * Remove unshared entried from physmap (if VM is fork) + */ +#define VM_EVENT_FLAG_RESET_FORK_MEMORY (1 << 15) /* * Reasons for the vm event request