From patchwork Fri Apr 21 13:15:45 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jennifer Herbert X-Patchwork-Id: 9692819 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 2CD9B60328 for ; Fri, 21 Apr 2017 13:18:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1DBC5277D9 for ; Fri, 21 Apr 2017 13:18:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1251928627; Fri, 21 Apr 2017 13:18:28 +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 42005277D9 for ; Fri, 21 Apr 2017 13:18:27 +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 1d1YPr-0002we-3o; Fri, 21 Apr 2017 13:16:03 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1d1YPq-0002vj-D7 for xen-devel@lists.xen.org; Fri, 21 Apr 2017 13:16:02 +0000 Received: from [85.158.139.211] by server-12.bemta-5.messagelabs.com id 03/69-01735-1160AF85; Fri, 21 Apr 2017 13:16:01 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmplkeJIrShJLcpLzFFi42JxWrohUleQ7Ve EwYM1TBZLPi5mcWD0OLr7N1MAYxRrZl5SfkUCa8b17y1MBfcDKpZM38bawLjIuouRk0NCwF/i 3NX9bCA2m4CyRO/E18wgtoiAusTpjousXYxcHMwC05gkTnz5xtLFyMEhDNTwe3sQSA2LgKrEx 455LCA2r4C3xKWVC1ghZspJnD/+E2wOp4CPxPmNLxlBbCGgmjO9J9khbA2J/oP3WSF6BSVOzn wCNodZQELi4IsXzBMYeWchSc1CklrAyLSKUaM4tagstUjX0EwvqSgzPaMkNzEzR9fQwFQvN7W 4ODE9NScxqVgvOT93EyMweBiAYAfj+dOehxglOZiURHlDfv+MEOJLyk+pzEgszogvKs1JLT7E KMPBoSTBu5XlV4SQYFFqempFWmYOMIxh0hIcPEoivDysQGne4oLE3OLMdIjUKUZFKXHeBpA+A ZBERmkeXBssdi4xykoJ8zICHSLEU5BalJtZgir/ilGcg1FJmLcAZApPZl4J3PRXQIuZgBaf9f sBsrgkESEl1cDI+DbrWr/VZ5tqt+XFS6aa1K48vTt0yuPjF1dfvOLjEOPwzNHUj2HO4ZKXWk0 s8St393FZaaoKehY1KOk/Pzj5iPu+xfKRnC9uFh58qvfM9JreO/+rwTsWay3miNxyUC6Gq71/ x5dpPfdt9W76XIvLeP+W6Who0u7mQFO7pV7CxkEPHZoePDmqxFKckWioxVxUnAgAZnYb5pgCA AA= X-Env-Sender: prvs=277b21c2f=jennifer.herbert@citrix.com X-Msg-Ref: server-12.tower-206.messagelabs.com!1492780558!58173413!2 X-Originating-IP: [66.165.176.89] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni44OSA9PiAyMDMwMDc=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 9.4.12; banners=-,-,- X-VirusChecked: Checked Received: (qmail 40933 invoked from network); 21 Apr 2017 13:16:00 -0000 Received: from smtp.citrix.com (HELO SMTP.CITRIX.COM) (66.165.176.89) by server-12.tower-206.messagelabs.com with RC4-SHA encrypted SMTP; 21 Apr 2017 13:16:00 -0000 X-IronPort-AV: E=Sophos;i="5.37,230,1488844800"; d="scan'208";a="420277599" From: To: Xen-devel Date: Fri, 21 Apr 2017 13:15:45 +0000 Message-ID: <1492780545-22401-5-git-send-email-jennifer.herbert@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1492780545-22401-1-git-send-email-jennifer.herbert@citrix.com> References: <1492780545-22401-1-git-send-email-jennifer.herbert@citrix.com> MIME-Version: 1.0 Cc: Wei Liu , Andrew Cooper , Jennifer Herbert , Julien Grall , Paul Durrant , Jan Beulich , Ian Jackson Subject: [Xen-devel] [PATCH v7 for-4.9 5/5] dmop: 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 devicemodel 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 Reviewed-by: Jan Beulich Reviewed-by: Paul Durrant Acked-by: Wei Liu --- CC: Paul Durrant CC: Andrew Cooper CC: Jan Beulich CC: Ian Jackson CC: Wei Liu CC: Julien Grall --- No change. --- tools/libs/devicemodel/core.c | 30 ++++-- tools/libs/devicemodel/include/xendevicemodel.h | 19 +++- xen/arch/x86/hvm/dm.c | 117 ++++++++++++++++-------- xen/include/public/hvm/dm_op.h | 19 +++- 4 files changed, 134 insertions(+), 51 deletions(-) diff --git a/tools/libs/devicemodel/core.c b/tools/libs/devicemodel/core.c index ff09819..d7c6476 100644 --- a/tools/libs/devicemodel/core.c +++ b/tools/libs/devicemodel/core.c @@ -459,22 +459,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->opaque = 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 1da216f..580fad2 100644 --- a/tools/libs/devicemodel/include/xendevicemodel.h +++ b/tools/libs/devicemodel/include/xendevicemodel.h @@ -254,8 +254,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 @@ -268,6 +268,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 196729a..ab181d8 100644 --- a/xen/arch/x86/hvm/dm.c +++ b/xen/arch/x86/hvm/dm.c @@ -153,56 +153,102 @@ 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) + const struct dmop_args *bufs, + struct xen_dm_op_modified_memory *header) { - xen_pfn_t last_pfn = data->first_pfn + data->nr - 1; - unsigned int iter = 0; - int rc = 0; +#define EXTENTS_BUFFER 1 - if ( (data->first_pfn > last_pfn) || - (last_pfn > domain_get_maximum_gpfn(d)) ) - return -EINVAL; + /* Process maximum of 256 pfns before checking for continuation. */ + const unsigned int cont_check_interval = 0x100; + unsigned int *rem_extents = &header->nr_extents; + unsigned int batch_rem_pfns = cont_check_interval; + /* Used for continuation. */ + unsigned int *pfns_done = &header->opaque; if ( !paging_mode_log_dirty(d) ) return 0; - while ( iter < data->nr ) + if ( (bufs->buf[EXTENTS_BUFFER].size / + sizeof(struct xen_dm_op_modified_memory_extent)) < + *rem_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, end_pfn; + int rc; + + rc = copy_from_guest_buf_offset(&extent, + bufs, EXTENTS_BUFFER, (*rem_extents - 1) * sizeof(extent)); + if ( rc ) + return -EFAULT; + + if ( extent.pad ) + return -EINVAL; + + end_pfn = extent.first_pfn + extent.nr; + + if ( end_pfn <= extent.first_pfn || + end_pfn > domain_get_maximum_gpfn(d) ) + return -EINVAL; - page = get_page_from_gfn(d, pfn, NULL, P2M_UNSHARE); - if ( page ) + if ( *pfns_done >= extent.nr ) + return -EINVAL; + + pfn = extent.first_pfn + *pfns_done; + batch_nr = extent.nr - *pfns_done; + + if ( batch_nr > batch_rem_pfns ) + { + batch_nr = batch_rem_pfns; + *pfns_done += batch_nr; + end_pfn = pfn + 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)--; + *pfns_done = 0; } - iter++; + batch_rem_pfns -= batch_nr; + + for ( ; pfn < end_pfn; 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); + } + } /* - * Check for continuation every 256th iteration and if the - * iteration is not the last. + * After a full batch of cont_check_interval pfns + * have been processed, and there are still extents + * remaining to process, check for continuation. */ - 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; + if ( hypercall_preempt_check() ) + return -ERESTART; - rc = -ERESTART; - break; + batch_rem_pfns = cont_check_interval; } } + return 0; - return rc; +#undef EXTENTS_BUFFER } static bool allow_p2m_type_change(p2m_type_t old, p2m_type_t new) @@ -539,13 +585,8 @@ static int dm_op(const struct dmop_args *op_args) 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, op_args, data); + const_op = !rc; break; } diff --git a/xen/include/public/hvm/dm_op.h b/xen/include/public/hvm/dm_op.h index 5ea79ef..20c21b6 100644 --- a/xen/include/public/hvm/dm_op.h +++ b/xen/include/public/hvm/dm_op.h @@ -237,13 +237,26 @@ 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_extents entries. + * + * On error, @nr_extents will contain the index+1 of the extent that + * had the error. It is not defined if or which pages may have been + * marked as dirty, in this event. */ #define XEN_DMOP_modified_memory 11 struct xen_dm_op_modified_memory { + /* + * IN - Number of extents to be processed + * OUT -returns n+1 for failing extent + */ + uint32_t nr_extents; + /* IN/OUT - Must be set to 0 */ + uint32_t opaque; +}; + +struct xen_dm_op_modified_memory_extent { /* IN - number of contiguous pages modified */ uint32_t nr; uint32_t pad;