diff mbox

[v2,19/43] postcopy: OS support test

Message ID 1407767399-3030-20-git-send-email-dgilbert@redhat.com
State New
Headers show

Commit Message

Dr. David Alan Gilbert Aug. 11, 2014, 2:29 p.m. UTC
From: "Dr. David Alan Gilbert" <dgilbert@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 <dgilbert@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

Comments

Zhanghailiang Aug. 12, 2014, 5:32 a.m. UTC | #1
On 2014/8/11 22:29, Dr. David Alan Gilbert (git) wrote:
> From: "Dr. David Alan Gilbert"<dgilbert@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<dgilbert@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<dgilbert@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<dgilbert@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
> +
Dr. David Alan Gilbert Aug. 12, 2014, 8:18 a.m. UTC | #2
* zhanghailiang (zhang.zhanghailiang@huawei.com) wrote:
> On 2014/8/11 22:29, Dr. David Alan Gilbert (git) wrote:
> >From: "Dr. David Alan Gilbert"<dgilbert@redhat.com>
> >

<snip>

> >+    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!

Yes, thank you for spotting this; I'll fix it in my next version.

Dave

> 
> 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
> >+
> 
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
diff mbox

Patch

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  <dgilbert@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  <dgilbert@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");
+        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
+