diff mbox

[v4,25/47] postcopy: OS support test

Message ID 1412358473-31398-26-git-send-email-dgilbert@redhat.com
State New
Headers show

Commit Message

Dr. David Alan Gilbert Oct. 3, 2014, 5:47 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                   | 160 +++++++++++++++++++++++++++++++++++++++
 savevm.c                         |   6 ++
 4 files changed, 186 insertions(+), 1 deletion(-)
 create mode 100644 include/migration/postcopy-ram.h
 create mode 100644 postcopy-ram.c

Comments

David Gibson Nov. 4, 2014, 1:40 a.m. UTC | #1
On Fri, Oct 03, 2014 at 06:47:31PM +0100, 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                   | 160 +++++++++++++++++++++++++++++++++++++++
>  savevm.c                         |   6 ++
>  4 files changed, 186 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 97db978..fa0a3a0 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -54,7 +54,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);

Maybe postcopy_supported_by_host() would be a bit clearer?

[snip]
> +#ifdef HOST_X86_64
> + /* NOTE: These are Andrea's 3.15.0 world */

I thought the usual approach in qemu was to import the updated headers
first in a separate patch, rather than embeddeding new defines.


> +#ifndef MADV_USERFAULT
> +#define MADV_USERFAULT   18
> +#define MADV_NOUSERFAULT 19
> +#endif
> +
> +#ifndef __NR_remap_anon_pages
> +#define __NR_remap_anon_pages 321
> +#endif
> +
> +#ifndef __NR_userfaultfd
> +#define __NR_userfaultfd 322
> +#endif
> +
> +#endif
> +
> +#ifndef USERFAULTFD_PROTOCOL
> +#define USERFAULTFD_PROTOCOL (uint64_t)0xaa
> +#endif
> +
> +#endif
Dr. David Alan Gilbert Nov. 25, 2014, 5:34 p.m. UTC | #2
* David Gibson (david@gibson.dropbear.id.au) wrote:
> On Fri, Oct 03, 2014 at 06:47:31PM +0100, 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                   | 160 +++++++++++++++++++++++++++++++++++++++
> >  savevm.c                         |   6 ++
> >  4 files changed, 186 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 97db978..fa0a3a0 100644
> > --- a/Makefile.objs
> > +++ b/Makefile.objs
> > @@ -54,7 +54,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);
> 
> Maybe postcopy_supported_by_host() would be a bit clearer?

I went with postcopy_ram_supported_by_host
(and flipped the sense so it returns true if it's supported)

> [snip]
> > +#ifdef HOST_X86_64
> > + /* NOTE: These are Andrea's 3.15.0 world */
> 
> I thought the usual approach in qemu was to import the updated headers
> first in a separate patch, rather than embeddeding new defines.

Yes, those will sort themselves out when the syscalls land in the kernel and
then we can import the headers.

Dave

--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
diff mbox

Patch

diff --git a/Makefile.objs b/Makefile.objs
index 97db978..fa0a3a0 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -54,7 +54,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..bba5c71
--- /dev/null
+++ b/postcopy-ram.c
@@ -0,0 +1,160 @@ 
+/*
+ * 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 */
+
+#ifdef HOST_X86_64
+ /* NOTE: These are 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 321
+#endif
+
+#ifndef __NR_userfaultfd
+#define __NR_userfaultfd 322
+#endif
+
+#endif
+
+#ifndef USERFAULTFD_PROTOCOL
+#define USERFAULTFD_PROTOCOL (uint64_t)0xaa
+#endif
+
+#endif
+
+#if defined(__linux__) && defined(MADV_USERFAULT) && \
+                          defined(__NR_remap_anon_pages)
+
+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 = NULL, *testarea2 = NULL;
+    long pagesize = getpagesize();
+    int ufd = -1;
+    int ret = -1; /* Error unless we change it */
+
+    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");
+        goto out;
+    }
+    g_assert(((size_t)testarea & (pagesize-1)) == 0);
+
+    ufd = syscall(__NR_userfaultfd, O_CLOEXEC);
+    if (ufd == -1) {
+        perror("postcopy_ram_hosttest: userfaultfd not available");
+        goto out;
+    }
+
+    if (madvise(testarea, pagesize, MADV_USERFAULT)) {
+        perror("postcopy_ram_hosttest: MADV_USERFAULT not available");
+        goto out;
+    }
+
+    if (madvise(testarea, pagesize, MADV_NOUSERFAULT)) {
+        perror("postcopy_ram_hosttest: MADV_NOUSERFAULT not available");
+        goto out;
+    }
+
+    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");
+        goto out;
+    }
+    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");
+        goto out;
+    }
+
+    /* Success! */
+    ret = 0;
+out:
+    if (testarea) {
+        munmap(testarea, pagesize);
+    }
+    if (testarea2) {
+        munmap(testarea2, pagesize);
+    }
+    if (ufd != -1) {
+        close(ufd);
+    }
+    return ret;
+}
+
+#else
+/* No target OS support, stubs just fail */
+
+int postcopy_ram_hosttest(void)
+{
+    error_report("postcopy_ram_hosttest: No OS support");
+    return -1;
+}
+
+#endif
+
diff --git a/savevm.c b/savevm.c
index 1642a59..a0cb88b 100644
--- a/savevm.c
+++ b/savevm.c
@@ -33,6 +33,7 @@ 
 #include "qemu/timer.h"
 #include "audio/audio.h"
 #include "migration/migration.h"
+#include "migration/postcopy-ram.h"
 #include "qemu/sockets.h"
 #include "qemu/queue.h"
 #include "sysemu/cpus.h"
@@ -1087,6 +1088,11 @@  static int loadvm_postcopy_ram_handle_advise(MigrationIncomingState *mis,
         return -1;
     }
 
+    /* Check this host can do it  */
+    if (postcopy_ram_hosttest()) {
+        return -1;
+    }
+
     if (remote_hps != sysconf(_SC_PAGESIZE))  {
         /*
          * Some combinations of mismatch are probably possible but it gets