On 2014/8/11 22:29, Dr. David Alan Gilbert (git) wrote:
From: "Dr. David Alan Gilbert"<dgilb...@redhat.com>
Provide a check to see if the OS we're running on has all the bits
needed for postcopy.
Creates postcopy-ram.c which will get most of the other helpers we need.
Signed-off-by: Dr. David Alan Gilbert<dgilb...@redhat.com>
---
Makefile.objs | 2 +-
include/migration/postcopy-ram.h | 19 ++++++
postcopy-ram.c | 129 +++++++++++++++++++++++++++++++++++++++
3 files changed, 149 insertions(+), 1 deletion(-)
create mode 100644 include/migration/postcopy-ram.h
create mode 100644 postcopy-ram.c
diff --git a/Makefile.objs b/Makefile.objs
index 1f76cea..a7ad235 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -55,7 +55,7 @@ common-obj-y += qemu-file.o
common-obj-$(CONFIG_RDMA) += migration-rdma.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o
-common-obj-y += page_cache.o xbzrle.o
+common-obj-y += page_cache.o xbzrle.o postcopy-ram.o
common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
diff --git a/include/migration/postcopy-ram.h b/include/migration/postcopy-ram.h
new file mode 100644
index 0000000..dcd1afa
--- /dev/null
+++ b/include/migration/postcopy-ram.h
@@ -0,0 +1,19 @@
+/*
+ * Postcopy migration for RAM
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ * Dave Gilbert<dgilb...@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#ifndef QEMU_POSTCOPY_RAM_H
+#define QEMU_POSTCOPY_RAM_H
+
+/* Return 0 if the host supports everything we need to do postcopy-ram */
+int postcopy_ram_hosttest(void);
+
+#endif
diff --git a/postcopy-ram.c b/postcopy-ram.c
new file mode 100644
index 0000000..1f3e6ea
--- /dev/null
+++ b/postcopy-ram.c
@@ -0,0 +1,129 @@
+/*
+ * Postcopy migration for RAM
+ *
+ * Copyright 2013-2014 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ * Dave Gilbert<dgilb...@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+/*
+ * Postcopy is a migration technique where the execution flips from the
+ * source to the destination before all the data has been copied.
+ */
+
+#include<glib.h>
+#include<stdio.h>
+#include<unistd.h>
+
+#include "qemu-common.h"
+#include "migration/migration.h"
+#include "migration/postcopy-ram.h"
+
+//#define DEBUG_POSTCOPY
+
+#ifdef DEBUG_POSTCOPY
+#define DPRINTF(fmt, ...) \
+ do { fprintf(stderr, "postcopy@%" PRId64 " " fmt "\n", \
+ qemu_clock_get_ms(QEMU_CLOCK_REALTIME), \
+ ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+ do { } while (0)
+#endif
+
+/* Postcopy needs to detect accesses to pages that haven't yet been copied
+ * across, and efficiently map new pages in, the techniques for doing this
+ * are target OS specific.
+ */
+#if defined(__linux__)
+
+/* On Linux we use:
+ * madvise MADV_USERFAULT - to mark an area of anonymous memory such
+ * that userspace is notifed of accesses to
+ * unallocated areas.
+ * userfaultfd - opens a socket to receive USERFAULT messages
+ * remap_anon_pages - to shuffle mapped pages into previously unallocated
+ * areas without creating loads of VMAs.
+ */
+
+#include<sys/mman.h>
+#include<sys/types.h>
+
+/* TODO remove once we have libc defs
+ * NOTE: These are x86-64 numbers for Andrea's 3.15.0 world */
+#ifndef MADV_USERFAULT
+#define MADV_USERFAULT 18
+#define MADV_NOUSERFAULT 19
+#endif
+
+#ifndef __NR_remap_anon_pages
+#define __NR_remap_anon_pages 317
+#endif
+
+int postcopy_ram_hosttest(void)
+{
+ /* TODO: Needs guarding with CONFIG_ once we have libc's that have the defs
+ *
+ * Try each syscall we need, but this isn't a testbench,
+ * just enough to see that we have the calls
+ */
+ void *testarea, *testarea2;
+ long pagesize = getpagesize();
+
+ testarea = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE |
+ MAP_ANONYMOUS, -1, 0);
+ if (!testarea) {
+ perror("postcopy_ram_hosttest: Failed to map test area");
+ return -1;
+ }
+ g_assert(((size_t)testarea& (pagesize-1)) == 0);
+
+ if (madvise(testarea, pagesize, MADV_USERFAULT)) {
+ perror("postcopy_ram_hosttest: MADV_USERFAULT not available");
+ munmap(testarea, pagesize);
+ return -1;
+ }
+
+ if (madvise(testarea, pagesize, MADV_NOUSERFAULT)) {
+ perror("postcopy_ram_hosttest: MADV_NOUSERFAULT not available");
+ munmap(testarea, pagesize);
+ return -1;
+ }
+
+ testarea2 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE |
+ MAP_ANONYMOUS, -1, 0);
+ if (!testarea2) {
+ perror("postcopy_ram_hosttest: Failed to map second test area");
Before return, should we munmap testarea?
BTW, i think it is better to use goto statement,
which we can handle the error cases together!
Best regards,
zhanghailiang
+ return -1;
+ }
+ g_assert(((size_t)testarea2& (pagesize-1)) == 0);
+ *(char *)testarea = 0; /* Force the map of the new page */
+ if (syscall(__NR_remap_anon_pages, testarea2, testarea, pagesize, 0) !=
+ pagesize) {
+ perror("postcopy_ram_hosttest: remap_anon_pages not available");
+ munmap(testarea, pagesize);
+ munmap(testarea2, pagesize);
+ return -1;
+ }
+
+ munmap(testarea, pagesize);
+ munmap(testarea2, pagesize);
+ return 0;
+}
+
+#else
+/* No target OS support, stubs just fail */
+
+int postcopy_ram_hosttest(void)
+{
+ error_report("postcopy_ram_hosttest: No OS support");
+ return -1;
+}
+
+#endif
+