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