From patchwork Thu Jan 30 16:13:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Woodhouse X-Patchwork-Id: 11358309 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5ABE7139A for ; Thu, 30 Jan 2020 16:16:17 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 36B5620707 for ; Thu, 30 Jan 2020 16:16:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="uQsXGNFK" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 36B5620707 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=infradead.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1ixCSP-0004Pt-AI; Thu, 30 Jan 2020 16:14:17 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1ixCSN-0004Ob-NX for xen-devel@lists.xenproject.org; Thu, 30 Jan 2020 16:14:15 +0000 X-Inumbo-ID: 758ad0ca-437b-11ea-a933-bc764e2007e4 Received: from bombadil.infradead.org (unknown [2607:7c80:54:e::133]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id 758ad0ca-437b-11ea-a933-bc764e2007e4; Thu, 30 Jan 2020 16:13:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=P1JBbhQ8GJUIqzOoGTJM/rEnqMJxaYbZHtfoRu2ij9A=; b=uQsXGNFKRAQjhQu4gczJ6ykM9a qPjTFzzOeB9kNOSVOEqiXHoz7Nxim1uXoriSwyAaUfQaB13zbt1GbJh0/3LRJCvp+DGTkGPmSLdj5 0PcOOTeXeYXqCv5nW5pter/mQUrNiYpDEQw7XMrWnln7TRl6b3GV/wOG31Lr8brNcWVpbwqYtnb7R caK2BmEujfXz3uqMyDQhmqvqDwREvwUDo0oZ9aLW/kg/CneCXLhINiot5mBIgxML4kTXLeSiJtppW 5XPBvWwTS3vV5bu+51jPjcwYm5YvFKplnWrZShX0nPRoaYy3iVYuX4XkXx51UseIZAVJYZCr0Axzs U31SFj3w==; Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by bombadil.infradead.org with esmtpsa (Exim 4.92.3 #3 (Red Hat Linux)) id 1ixCRf-00059z-IS; Thu, 30 Jan 2020 16:13:31 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.92 #3 (Red Hat Linux)) id 1ixCRe-009kdJ-Ba; Thu, 30 Jan 2020 16:13:30 +0000 From: David Woodhouse To: Xen-devel Date: Thu, 30 Jan 2020 16:13:15 +0000 Message-Id: <20200130161330.2324143-7-dwmw2@infradead.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200130161330.2324143-1-dwmw2@infradead.org> References: <20200130161330.2324143-1-dwmw2@infradead.org> MIME-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by bombadil.infradead.org. See http://www.infradead.org/rpr.html Subject: [Xen-devel] [RFC PATCH v3 07/22] Add basic live update stream creation X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Julien Grall , Wei Liu , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Varad Gautam , paul@xen.org, Ian Jackson , Hongyan Xia , Amit Shah , =?utf-8?q?Ro?= =?utf-8?q?ger_Pau_Monn=C3=A9?= Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" From: David Woodhouse Signed-off-by: David Woodhouse --- xen/common/Makefile | 1 + xen/common/lu/Makefile | 1 + xen/common/lu/stream.c | 135 +++++++++++++++++++++++++++++++++++++++++ xen/include/xen/lu.h | 29 +++++++++ 4 files changed, 166 insertions(+) create mode 100644 xen/common/lu/Makefile create mode 100644 xen/common/lu/stream.c create mode 100644 xen/include/xen/lu.h diff --git a/xen/common/Makefile b/xen/common/Makefile index 2abb8250b0..60502bb909 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -72,3 +72,4 @@ subdir-$(CONFIG_UBSAN) += ubsan subdir-$(CONFIG_NEEDS_LIBELF) += libelf subdir-$(CONFIG_HAS_DEVICE_TREE) += libfdt +subdir-y += lu diff --git a/xen/common/lu/Makefile b/xen/common/lu/Makefile new file mode 100644 index 0000000000..68991b3ca4 --- /dev/null +++ b/xen/common/lu/Makefile @@ -0,0 +1 @@ +obj-y += stream.o diff --git a/xen/common/lu/stream.c b/xen/common/lu/stream.c new file mode 100644 index 0000000000..10e123a466 --- /dev/null +++ b/xen/common/lu/stream.c @@ -0,0 +1,135 @@ +/* + * Live update data stream handling. + * + * During live update, one version of Xen (Xen#1) performs a kexec into + * a new version of Xen (Xen#2), performing guest-transparent live + * migration of all existing domains. + * + * Xen#2 must avoid scribbling on any pages which may belong to existing + * domains. In order to achieve this, we reserve a contiguous area of + * physical memory to be used by the boot allocator in Xen#2. Xen must + * not allocate pages from that region which are later shared with + * guests or need to persist across live update. + * + * The live update bootmem region is reserved by the first Xen to boot, + * and userspace can obtain its address using KEXEC_CMD_kexec_get_range + * with the new KEXEC_RANGE_MA_LIVEUPDATE type. Userspace kexec(8) + * appends the appropriate 'liveupdate=' parameter to the command line + * of Xen#2 when setting up the kexec image. + * + * At the time of kexec, Xen#1 serialises the domain state into buffers + * allocated from its own heap., then creates a single physically + * contiguous scatter-gather list containing the MFNs of those data + * pages (which Xen#2 can then trivially vmap()). In a system with + * 4KiB pages, the MFN list for the live update data stream will fit + * into a single page until the total size of the live update data + * exceeds 2MiB. + * + * The physical address of the MFN list is passed to Xen#2 by placing + * it at the start of the reserved live update bootmem region, with a + * magic number to avoid false positives. + */ + +#include +#include +#include + +static int lu_stream_extend(struct lu_stream *stream, int nr_pages) +{ + int order = get_order_from_bytes((nr_pages + 1) * sizeof(mfn_t)); + int old_order = get_order_from_bytes((stream->nr_pages + 1) * sizeof(mfn_t)); + + if ( !stream->nr_pages || order > old_order ) + { + mfn_t *new_pglist = alloc_xenheap_pages(order, 0); + + if ( !new_pglist ) + return -ENOMEM; + + if ( stream->nr_pages ) + { + memcpy(new_pglist, stream->pagelist, + stream->nr_pages * sizeof(mfn_t)); + free_xenheap_pages(stream->pagelist, old_order); + } + stream->pagelist = new_pglist; + } + while ( stream->nr_pages < nr_pages ) + { + struct page_info *pg = alloc_domheap_page(NULL, MEMF_no_owner); + + if ( !pg ) + { + /* Ensure the cleanup frees the correct order of pagelist */ + stream->nr_pages++; + + return -ENOMEM; + } + stream->pagelist[stream->nr_pages++] = page_to_mfn(pg); + stream->pagelist[stream->nr_pages] = INVALID_MFN; + } + + if ( stream->data ) + vunmap(stream->data); + stream->data = vmap(stream->pagelist, stream->nr_pages); + if ( !stream->data ) + return -ENOMEM; + + return 0; +} + +void *lu_stream_reserve(struct lu_stream *stream, size_t size) +{ + int nr_pages = (stream->len + size + PAGE_SIZE - 1) >> PAGE_SHIFT; + + if ( stream->nr_pages < nr_pages && lu_stream_extend(stream, nr_pages) ) + return NULL; + + return stream->data + stream->len; +} + +void lu_stream_end_reservation(struct lu_stream *stream, size_t size) +{ + stream->len += size; +} + +int lu_stream_append(struct lu_stream *stream, const void *data, size_t size) +{ + void *p = lu_stream_reserve(stream, size); + + if ( !p ) + return -ENOMEM; + memcpy(p, data, size); + lu_stream_end_reservation(stream, size); + + return 0; +} + +void lu_stream_free(struct lu_stream *stream) +{ + unsigned int order = get_order_from_bytes((stream->nr_pages + 1) * sizeof(mfn_t)); + unsigned int i; + + if ( stream->data ) + vunmap(stream->data); + + if ( stream->pagelist ) + { + for ( i = 0; i < stream->nr_pages; i++ ) + { + if (mfn_valid(stream->pagelist[i])) + free_domheap_page(mfn_to_page(stream->pagelist[i])); + } + free_xenheap_pages(stream->pagelist, order); + } +} + +/* + * local variables: + * mode: c + * c-file-style: "bsd" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * end: + */ diff --git a/xen/include/xen/lu.h b/xen/include/xen/lu.h new file mode 100644 index 0000000000..abb30545fe --- /dev/null +++ b/xen/include/xen/lu.h @@ -0,0 +1,29 @@ +#ifndef __XEN_LU_H__ +#define __XEN_LU_H__ + +#include +#include + +struct lu_stream { + mfn_t *pagelist; + size_t len; + int nr_pages; + char *data; +}; + +void *lu_stream_reserve(struct lu_stream *stream, size_t size); +void lu_stream_end_reservation(struct lu_stream *stream, size_t size); +int lu_stream_append(struct lu_stream *stream, const void *data, size_t size); +void lu_stream_free(struct lu_stream *stream); + +#endif /* __XEN_LU_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */