Message ID | 1407767399-3030-20-git-send-email-dgilbert@redhat.com |
---|---|
State | New |
Headers | show |
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 > +
* 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 --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 +