From patchwork Tue Mar 21 13:59:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jennifer Herbert X-Patchwork-Id: 9636651 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 E935C602D6 for ; Tue, 21 Mar 2017 14:02:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DBF3C27D29 for ; Tue, 21 Mar 2017 14:02:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CD32D28338; Tue, 21 Mar 2017 14:02:40 +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.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED 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 04A8727D29 for ; Tue, 21 Mar 2017 14:02:40 +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 1cqKKc-0001Bs-In; Tue, 21 Mar 2017 14:00:14 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cqKKb-0001Bf-11 for xen-devel@lists.xen.org; Tue, 21 Mar 2017 14:00:13 +0000 Received: from [85.158.137.68] by server-3.bemta-3.messagelabs.com id BB/ED-14551-CE131D85; Tue, 21 Mar 2017 14:00:12 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrDLMWRWlGSWpSXmKPExsXitHSDve5rw4s RBqf+qVos+biYxYHR4+ju30wBjFGsmXlJ+RUJrBnfppxnK7gTULF552TWBsYt1l2MnBwSAv4S XzZ+Zeli5OBgEzCR+LqqBCQsIqAucbrjImsXIxcHs8BHRom7m1Yyg9QICzhLzJuhClLDIqAqs W/ZXkYQm1fAW2LT2S4WiJGKEt3PJrCB2EICGhL9B++zQtQISpyc+QSshllAQuLgixfMExi5Zy FJzUKSWsDItIpRozi1qCy1SNfQQi+pKDM9oyQ3MTNH19DAWC83tbg4MT01JzGpWC85P3cTIzA U6hkYGHcw/j7teYhRkoNJSZR3zaULEUJ8SfkplRmJxRnxRaU5qcWHGGU4OJQkeMsMLkYICRal pqdWpGXmAIMSJi3BwaMkwrtQHyjNW1yQmFucmQ6ROsWoKCXO+xSkTwAkkVGaB9cGi4RLjLJSw ryMDAwMQjwFqUW5mSWo8q8YxTkYlYR5s0Cm8GTmlcBNfwW0mAlocdmeCyCLSxIRUlINjOoh82 /f8J2l7r9mz7GJTxn6u2amCZesFfWbeHt16+cp/FveXL/74s3tOabPZ83vrjzAfPzG9LMVqiE 2/7N3OC6b1f3t1ZPYQxu/mt+b/fOOh5jAtUknw24sDNG5+OquyxKTclMVDjubpI3vWV94+ArN k9L4umYK1+5Fv/JfTDaUnKnBmMV6gvGdEktxRqKhFnNRcSIAVBvuJX8CAAA= X-Env-Sender: prvs=246752839=jennifer.herbert@citrix.com X-Msg-Ref: server-11.tower-31.messagelabs.com!1490104809!60429657!1 X-Originating-IP: [66.165.176.63] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni42MyA9PiAzMDYwNDg=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 9.2.3; banners=-,-,- X-VirusChecked: Checked Received: (qmail 33888 invoked from network); 21 Mar 2017 14:00:11 -0000 Received: from smtp02.citrix.com (HELO SMTP02.CITRIX.COM) (66.165.176.63) by server-11.tower-31.messagelabs.com with RC4-SHA encrypted SMTP; 21 Mar 2017 14:00:11 -0000 X-IronPort-AV: E=Sophos;i="5.36,198,1486425600"; d="scan'208";a="423991330" From: Jennifer Herbert To: Xen-devel Date: Tue, 21 Mar 2017 13:59:51 +0000 Message-ID: <1490104791-32638-1-git-send-email-jennifer.herbert@citrix.com> X-Mailer: git-send-email 1.7.10.4 MIME-Version: 1.0 Cc: Wei Liu , Jennifer Herbert , Ian Jackson , Paul Durrant , Jan Beulich , Andrew Cooper Subject: [Xen-devel] [PATCH v2] dm_op: Add xendevicemodel_modified_memory_bulk. 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: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Jennifer Herbert This new lib devicemodel call allows multiple extents of pages to be marked as modified in a single call. This is something needed for a usecase I'm working on. The xen side of the modified_memory call has been modified to accept an array of extents. The devicemodle library either provides an array of length 1, to support the original library function, or a second function allows an array to be provided. Signed-off-by: Jennifer Herbert --- Cc: Jan Beulich Cc: Ian Jackson Cc: Wei Liu Cc: Andrew Cooper Cc: Paul Durrant --- This version of this patch removes the need for the 'offset' parameter, by instead reducing nr_extents, and working backwards from the end of the array. This patch also removes the need to ever write back the passed array of extents to the guest, but instead putting its partial progress in a 'pfns_processed' parameter, which replaces the old 'offset' parameter. As with the 'offest' parameter, 'pfns_processed' should be set to 0 on calling. tools/libs/devicemodel/core.c | 30 +++++-- tools/libs/devicemodel/include/xendevicemodel.h | 19 +++- xen/arch/x86/hvm/dm.c | 110 ++++++++++++++--------- xen/include/public/hvm/dm_op.h | 17 +++- 4 files changed, 122 insertions(+), 54 deletions(-) diff --git a/tools/libs/devicemodel/core.c b/tools/libs/devicemodel/core.c index a85cb49..f9e37a5 100644 --- a/tools/libs/devicemodel/core.c +++ b/tools/libs/devicemodel/core.c @@ -434,22 +434,36 @@ int xendevicemodel_track_dirty_vram( dirty_bitmap, (size_t)(nr + 7) / 8); } -int xendevicemodel_modified_memory( - xendevicemodel_handle *dmod, domid_t domid, uint64_t first_pfn, - uint32_t nr) +int xendevicemodel_modified_memory_bulk( + xendevicemodel_handle *dmod, domid_t domid, + struct xen_dm_op_modified_memory_extent *extents, uint32_t nr) { struct xen_dm_op op; - struct xen_dm_op_modified_memory *data; + struct xen_dm_op_modified_memory *header; + size_t extents_size = nr * sizeof(struct xen_dm_op_modified_memory_extent); memset(&op, 0, sizeof(op)); op.op = XEN_DMOP_modified_memory; - data = &op.u.modified_memory; + header = &op.u.modified_memory; - data->first_pfn = first_pfn; - data->nr = nr; + header->nr_extents = nr; + header->pfns_processed = 0; - return xendevicemodel_op(dmod, domid, 1, &op, sizeof(op)); + return xendevicemodel_op(dmod, domid, 2, &op, sizeof(op), + extents, extents_size); +} + +int xendevicemodel_modified_memory( + xendevicemodel_handle *dmod, domid_t domid, uint64_t first_pfn, + uint32_t nr) +{ + struct xen_dm_op_modified_memory_extent extent; + + extent.first_pfn = first_pfn; + extent.nr = nr; + + return xendevicemodel_modified_memory_bulk(dmod, domid, &extent, 1); } int xendevicemodel_set_mem_type( diff --git a/tools/libs/devicemodel/include/xendevicemodel.h b/tools/libs/devicemodel/include/xendevicemodel.h index b3f600e..9c62bf9 100644 --- a/tools/libs/devicemodel/include/xendevicemodel.h +++ b/tools/libs/devicemodel/include/xendevicemodel.h @@ -236,8 +236,8 @@ int xendevicemodel_track_dirty_vram( uint32_t nr, unsigned long *dirty_bitmap); /** - * This function notifies the hypervisor that a set of domain pages - * have been modified. + * This function notifies the hypervisor that a set of contiguous + * domain pages have been modified. * * @parm dmod a handle to an open devicemodel interface. * @parm domid the domain id to be serviced @@ -250,6 +250,21 @@ int xendevicemodel_modified_memory( uint32_t nr); /** + * This function notifies the hypervisor that a set of discontiguous + * domain pages have been modified. + * + * @parm dmod a handle to an open devicemodel interface. + * @parm domid the domain id to be serviced + * @parm extents an array of extent structs, which each hold + a start_pfn and nr (number of pfns). + * @parm nr the number of extents in the array + * @return 0 on success, -1 on failure. + */ +int xendevicemodel_modified_memory_bulk( + xendevicemodel_handle *dmod, domid_t domid, + struct xen_dm_op_modified_memory_extent extents[], uint32_t nr); + +/** * This function notifies the hypervisor that a set of domain pages * are to be treated in a specific way. (See the definition of * hvmmem_type_t). diff --git a/xen/arch/x86/hvm/dm.c b/xen/arch/x86/hvm/dm.c index 2122c45..c90af64 100644 --- a/xen/arch/x86/hvm/dm.c +++ b/xen/arch/x86/hvm/dm.c @@ -119,56 +119,89 @@ static int set_isa_irq_level(struct domain *d, uint8_t isa_irq, } static int modified_memory(struct domain *d, - struct xen_dm_op_modified_memory *data) + struct xen_dm_op_modified_memory *header, + xen_dm_op_buf_t* buf) { - xen_pfn_t last_pfn = data->first_pfn + data->nr - 1; - unsigned int iter = 0; + /* Process maximum of 256 pfns before checking for continuation */ + const unsigned int cont_check_interval = 0xff; int rc = 0; - - if ( (data->first_pfn > last_pfn) || - (last_pfn > domain_get_maximum_gpfn(d)) ) - return -EINVAL; + unsigned int rem_extents = header->nr_extents; + unsigned int batch_rem_pfns = cont_check_interval; if ( !paging_mode_log_dirty(d) ) return 0; - while ( iter < data->nr ) + if ( (buf->size / sizeof(struct xen_dm_op_modified_memory_extent)) < + header->nr_extents ) + return -EINVAL; + + while ( rem_extents > 0) { - unsigned long pfn = data->first_pfn + iter; - struct page_info *page; + struct xen_dm_op_modified_memory_extent extent; + unsigned int batch_nr; + xen_pfn_t pfn; + xen_pfn_t end_pfn; - page = get_page_from_gfn(d, pfn, NULL, P2M_UNSHARE); - if ( page ) + if ( copy_from_guest_offset(&extent, buf->h, rem_extents - 1, 1) ) + return -EFAULT; + + pfn = extent.first_pfn + header->pfns_processed; + batch_nr = extent.nr - header->pfns_processed; + + if ( batch_nr > batch_rem_pfns ) + { + batch_nr = batch_rem_pfns; + header->pfns_processed += batch_nr; + } + else { - mfn_t gmfn = _mfn(page_to_mfn(page)); - - paging_mark_dirty(d, gmfn); - /* - * These are most probably not page tables any more - * don't take a long time and don't die either. - */ - sh_remove_shadows(d, gmfn, 1, 0); - put_page(page); + rem_extents--; + header->pfns_processed = 0; } - iter++; + batch_rem_pfns -= batch_nr; + end_pfn = pfn + batch_nr; + + if ( (pfn >= end_pfn) || + (end_pfn > domain_get_maximum_gpfn(d)) ) + return -EINVAL; + + while ( pfn < end_pfn ) + { + struct page_info *page; + page = get_page_from_gfn(d, pfn, NULL, P2M_UNSHARE); + + if ( page ) + { + mfn_t gmfn = _mfn(page_to_mfn(page)); + + paging_mark_dirty(d, gmfn); + /* + * These are most probably not page tables any more + * don't take a long time and don't die either. + */ + sh_remove_shadows(d, gmfn, 1, 0); + put_page(page); + } + pfn++; + } /* - * Check for continuation every 256th iteration and if the - * iteration is not the last. + * Check for continuation every 256th pfn and if the + * pfn is not the last. */ - if ( (iter < data->nr) && ((iter & 0xff) == 0) && - hypercall_preempt_check() ) + if ( (batch_rem_pfns == 0) && (rem_extents > 0) ) { - data->first_pfn += iter; - data->nr -= iter; - - rc = -ERESTART; - break; + if ( hypercall_preempt_check() ) + { + header->nr_extents = rem_extents; + rc = -ERESTART; + break; + } + batch_rem_pfns = cont_check_interval; } - } - - return rc; + } + return rc; } static bool allow_p2m_type_change(p2m_type_t old, p2m_type_t new) @@ -441,13 +474,8 @@ static int dm_op(domid_t domid, struct xen_dm_op_modified_memory *data = &op.u.modified_memory; - const_op = false; - - rc = -EINVAL; - if ( data->pad ) - break; - - rc = modified_memory(d, data); + rc = modified_memory(d, data, &bufs[1]); + const_op = (rc != -ERESTART); break; } diff --git a/xen/include/public/hvm/dm_op.h b/xen/include/public/hvm/dm_op.h index f54cece..57adbf5 100644 --- a/xen/include/public/hvm/dm_op.h +++ b/xen/include/public/hvm/dm_op.h @@ -237,13 +237,24 @@ struct xen_dm_op_set_pci_link_route { * XEN_DMOP_modified_memory: Notify that a set of pages were modified by * an emulator. * - * NOTE: In the event of a continuation, the @first_pfn is set to the - * value of the pfn of the remaining set of pages and @nr reduced - * to the size of the remaining set. + * DMOP buf 1 contains an array of xen_dm_op_modified_memory_extent with + * @nr_extent entries. The value of @nr_extent will be reduced on + * continuation. + * + * @pfns_processed is used for continuation, and not intended to be usefull + * to the caller. It gives the number of pfns already processed (and can + * be skipped) in the last extent. This should always be set to zero. */ #define XEN_DMOP_modified_memory 11 struct xen_dm_op_modified_memory { + /* IN - number of extents. */ + uint32_t nr_extents; + /* IN - should be set to 0, and is updated on continuation. */ + uint32_t pfns_processed; +}; + +struct xen_dm_op_modified_memory_extent { /* IN - number of contiguous pages modified */ uint32_t nr; uint32_t pad;