[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH v3 07/22] Add basic live update stream creation
From: David Woodhouse <dwmw@xxxxxxxxxxxx> Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx> --- 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 <xen/types.h> +#include <xen/vmap.h> +#include <xen/lu.h> + +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 <xen/types.h> +#include <xen/mm.h> + +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: + */ -- 2.21.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |