[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.