From patchwork Wed Jan 22 08:53:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Woodhouse X-Patchwork-Id: 11345367 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 0F190139A for ; Wed, 22 Jan 2020 08:56:05 +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 DFAAC2253D for ; Wed, 22 Jan 2020 08:56:04 +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="NB9NZBVZ" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DFAAC2253D 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 1iuBn0-0001T1-Fh; Wed, 22 Jan 2020 08:55:06 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1iuBmy-0001Rz-Un for xen-devel@lists.xenproject.org; Wed, 22 Jan 2020 08:55:04 +0000 X-Inumbo-ID: be42c6ac-3cf4-11ea-8e9a-bc764e2007e4 Received: from merlin.infradead.org (unknown [2001:8b0:10b:1231::1]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id be42c6ac-3cf4-11ea-8e9a-bc764e2007e4; Wed, 22 Jan 2020 08:54:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=merlin.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=FHPcS0DtLZaNzZQhavkVgyBADnomo0xIa8I6Bc0tqgM=; b=NB9NZBVZUY79m7tHXxgG0Sw4+b /FTkzCLDttmfU7na20FdCMM+MCb9SLUXxlXp+B4YMt4/R4EQSRHHVpK3XH0E4cX6kflOkn8YbqvnL IqDjcmfxU5KH1uFei4ZFB3V4dkP28/NNnGcPMAW1Mp2MXsmQaJxXpxMAvPwo3gFAhzfckAcHt/xvo 1J8Wok025Tj8vHE0CZeiw5q/+wWKlTMF4wcbQz2Toj+7K27KirxeFt8y3kvVz6ArRkVUoKTbHa8JV L1dAWztQ3FnSWxtCaad7JWVY5dyLiYdMjGewRg0uCUgqusLaHbV/qm4TEAkdYbRc8zD/I0LRNvItK UeDE1A0g==; Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by merlin.infradead.org with esmtpsa (Exim 4.92.3 #3 (Red Hat Linux)) id 1iuBlu-0002cq-4Q; Wed, 22 Jan 2020 08:53:58 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.92 #3 (Red Hat Linux)) id 1iuBlt-008mRi-Ap; Wed, 22 Jan 2020 08:53:57 +0000 From: David Woodhouse To: Xen-devel Date: Wed, 22 Jan 2020 08:53:51 +0000 Message-Id: <20200122085357.2092778-8-dwmw2@infradead.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200122085357.2092778-1-dwmw2@infradead.org> References: <6cbe16ae42ab806df513d359220212d4f01ce43d.camel@infradead.org> <20200122085357.2092778-1-dwmw2@infradead.org> MIME-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by merlin.infradead.org. See http://www.infradead.org/rpr.html Subject: [Xen-devel] [RFC PATCH v2 08/14] 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 | 108 +++++++++++++++++++++++++++++++++++++++++ xen/include/xen/lu.h | 12 +++++ 4 files changed, 122 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 62b34e69e9..36c824a99a 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -78,3 +78,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..52030e8b2e --- /dev/null +++ b/xen/common/lu/stream.c @@ -0,0 +1,108 @@ +/* + * 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] = 0; + } + + 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, 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) +{ + int order = get_order_from_bytes((stream->nr_pages + 1) * sizeof(mfn_t)); + + if (stream->pagelist) + free_xenheap_pages(stream->pagelist, order); + if (stream->data) + vunmap(stream->data); +} diff --git a/xen/include/xen/lu.h b/xen/include/xen/lu.h new file mode 100644 index 0000000000..cb2f1dbe06 --- /dev/null +++ b/xen/include/xen/lu.h @@ -0,0 +1,12 @@ + +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, void *data, size_t size); +void lu_stream_free(struct lu_stream *stream);