direct-io.hg

changeset 14405:8e76e1b95b12

[HVM][QEMU] Save/restore: enable HVM live migration
by getting page-dirtying bitmaps from qemu-dm as well as from xen.
Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
author Tim Deegan <Tim.Deegan@xensource.com>
date Fri Mar 16 11:39:50 2007 +0000 (2007-03-16)
parents 422a61ebac54
children a20e3ad50ae8
files tools/ioemu/target-i386-dm/exec-dm.c tools/ioemu/xenstore.c tools/libxc/Makefile tools/libxc/xc_hvm_save.c tools/libxc/xenguest.h tools/libxc/xg_private.c tools/xcutils/Makefile tools/xcutils/xc_save.c
line diff
     1.1 --- a/tools/ioemu/target-i386-dm/exec-dm.c	Fri Mar 16 10:42:25 2007 +0000
     1.2 +++ b/tools/ioemu/target-i386-dm/exec-dm.c	Fri Mar 16 11:39:50 2007 +0000
     1.3 @@ -450,6 +450,9 @@ static inline int paddr_is_ram(target_ph
     1.4  #define phys_ram_addr(x) (phys_ram_base + (x))
     1.5  #endif
     1.6  
     1.7 +extern unsigned long *logdirty_bitmap;
     1.8 +extern unsigned long logdirty_bitmap_size;
     1.9 +
    1.10  void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
    1.11                              int len, int is_write)
    1.12  {
    1.13 @@ -485,9 +488,20 @@ void cpu_physical_memory_rw(target_phys_
    1.14                      l = 1;
    1.15                  }
    1.16              } else if (paddr_is_ram(addr)) {
    1.17 -                /* Reading from RAM */
    1.18 +                /* Writing to RAM */
    1.19                  ptr = phys_ram_addr(addr);
    1.20                  memcpy(ptr, buf, l);
    1.21 +                if (logdirty_bitmap != NULL) {
    1.22 +                    /* Record that we have dirtied this frame */
    1.23 +                    unsigned long pfn = addr >> TARGET_PAGE_BITS;
    1.24 +                    if (pfn / 8 >= logdirty_bitmap_size) {
    1.25 +                        fprintf(logfile, "dirtying pfn %x >= bitmap size %x\n",
    1.26 +                                pfn, logdirty_bitmap_size * 8);
    1.27 +                    } else {
    1.28 +                        logdirty_bitmap[pfn / HOST_LONG_BITS]
    1.29 +                            |= 1UL << pfn % HOST_LONG_BITS;
    1.30 +                    }
    1.31 +                }
    1.32  #ifdef __ia64__
    1.33                  sync_icache(ptr, l);
    1.34  #endif 
     2.1 --- a/tools/ioemu/xenstore.c	Fri Mar 16 10:42:25 2007 +0000
     2.2 +++ b/tools/ioemu/xenstore.c	Fri Mar 16 11:39:50 2007 +0000
     2.3 @@ -11,6 +11,11 @@
     2.4  #include "vl.h"
     2.5  #include "block_int.h"
     2.6  #include <unistd.h>
     2.7 +#include <sys/ipc.h>
     2.8 +#include <sys/shm.h>
     2.9 +#include <sys/types.h>
    2.10 +#include <sys/stat.h>
    2.11 +#include <fcntl.h>
    2.12  
    2.13  static struct xs_handle *xsh = NULL;
    2.14  static char *hd_filename[MAX_DISKS];
    2.15 @@ -183,6 +188,13 @@ void xenstore_parse_domain_config(int do
    2.16  	}
    2.17      }
    2.18  
    2.19 +    /* Set a watch for log-dirty requests from the migration tools */
    2.20 +    if (pasprintf(&buf, "%s/logdirty/next-active", path) != -1) {
    2.21 +        xs_watch(xsh, buf, "logdirty");
    2.22 +        fprintf(logfile, "Watching %s\n", buf);
    2.23 +    }
    2.24 +
    2.25 +
    2.26   out:
    2.27      free(type);
    2.28      free(params);
    2.29 @@ -201,6 +213,116 @@ int xenstore_fd(void)
    2.30      return -1;
    2.31  }
    2.32  
    2.33 +unsigned long *logdirty_bitmap = NULL;
    2.34 +unsigned long logdirty_bitmap_size;
    2.35 +extern int vga_ram_size, bios_size;
    2.36 +
    2.37 +void xenstore_process_logdirty_event(void)
    2.38 +{
    2.39 +    char *act;
    2.40 +    static char *active_path = NULL;
    2.41 +    static char *next_active_path = NULL;
    2.42 +    static char *seg = NULL;
    2.43 +    unsigned int len;
    2.44 +    int i;
    2.45 +
    2.46 +    fprintf(logfile, "Triggered log-dirty buffer switch\n");
    2.47 +
    2.48 +    if (!seg) {
    2.49 +        char *path, *p, *key_ascii, *key_terminated[17] = {0,};
    2.50 +        key_t key;
    2.51 +        int shmid;
    2.52 +
    2.53 +        /* Find and map the shared memory segment for log-dirty bitmaps */
    2.54 +        if (!(path = xs_get_domain_path(xsh, domid))) {            
    2.55 +            fprintf(logfile, "Log-dirty: can't get domain path in store\n");
    2.56 +            exit(1);
    2.57 +        }
    2.58 +        if (!(path = realloc(path, strlen(path) 
    2.59 +                             + strlen("/logdirty/next-active") + 1))) {
    2.60 +            fprintf(logfile, "Log-dirty: out of memory\n");
    2.61 +            exit(1);
    2.62 +        }
    2.63 +        strcat(path, "/logdirty/");
    2.64 +        p = path + strlen(path);
    2.65 +        strcpy(p, "key");
    2.66 +        
    2.67 +        key_ascii = xs_read(xsh, XBT_NULL, path, &len);
    2.68 +        if (!key_ascii) {
    2.69 +            /* No key yet: wait for the next watch */
    2.70 +            free(path);
    2.71 +            return;
    2.72 +        }
    2.73 +        strncpy(key_terminated, key_ascii, 16);
    2.74 +        free(key_ascii);
    2.75 +        key = (key_t) strtoull(key_terminated, NULL, 16);
    2.76 +
    2.77 +        /* Figure out how bit the log-dirty bitmaps are */
    2.78 +        logdirty_bitmap_size = ((phys_ram_size + 0x20 
    2.79 +                                 - (vga_ram_size + bios_size)) 
    2.80 +                                >> (TARGET_PAGE_BITS)); /* nr of bits in map*/
    2.81 +        if (logdirty_bitmap_size > HVM_BELOW_4G_MMIO_START >> TARGET_PAGE_BITS)
    2.82 +            logdirty_bitmap_size += 
    2.83 +                HVM_BELOW_4G_MMIO_LENGTH >> TARGET_PAGE_BITS; /* still bits */
    2.84 +        logdirty_bitmap_size = ((logdirty_bitmap_size + HOST_LONG_BITS - 1)
    2.85 +                                / HOST_LONG_BITS); /* longs */
    2.86 +        logdirty_bitmap_size *= sizeof (unsigned long); /* bytes */
    2.87 +
    2.88 +        /* Map the shared-memory segment */
    2.89 +        if ((shmid = shmget(key, 
    2.90 +                            2 * logdirty_bitmap_size, 
    2.91 +                            S_IRUSR|S_IWUSR)) == -1 
    2.92 +            || (seg = shmat(shmid, NULL, 0)) == (void *)-1) {
    2.93 +            fprintf(logfile, "Log-dirty: can't map segment %16.16llx (%s)\n",
    2.94 +                    (unsigned long long) key, strerror(errno));
    2.95 +            exit(1);
    2.96 +        }
    2.97 +
    2.98 +        fprintf(logfile, "Log-dirty: mapped segment at %p\n", seg);
    2.99 +
   2.100 +        /* Double-check that the bitmaps are the size we expect */
   2.101 +        if (logdirty_bitmap_size != *(uint32_t *)seg) {
   2.102 +            fprintf(logfile, "Log-dirty: got %lu, calc %lu\n", 
   2.103 +                    *(uint32_t *)seg, logdirty_bitmap_size);
   2.104 +            return;
   2.105 +        }
   2.106 +
   2.107 +        /* Remember the paths for the next-active and active entries */
   2.108 +        strcpy(p, "active");
   2.109 +        if (!(active_path = strdup(path))) {
   2.110 +            fprintf(logfile, "Log-dirty: out of memory\n");
   2.111 +            exit(1);
   2.112 +        }
   2.113 +        strcpy(p, "next-active");
   2.114 +        if (!(next_active_path = strdup(path))) {
   2.115 +            fprintf(logfile, "Log-dirty: out of memory\n");
   2.116 +            exit(1);
   2.117 +        }
   2.118 +        free(path);
   2.119 +    }
   2.120 +    
   2.121 +    /* Read the required active buffer from the store */
   2.122 +    act = xs_read(xsh, XBT_NULL, next_active_path, &len);
   2.123 +    if (!act) {
   2.124 +        fprintf(logfile, "Log-dirty: can't read next-active\n");
   2.125 +        exit(1);
   2.126 +    }
   2.127 +
   2.128 +    /* Switch buffers */
   2.129 +    i = act[0] - '0';
   2.130 +    if (i != 0 && i != 1) {
   2.131 +        fprintf(logfile, "Log-dirty: bad next-active entry: %s\n", act);
   2.132 +        exit(1);
   2.133 +    }
   2.134 +    logdirty_bitmap = seg + i * logdirty_bitmap_size;
   2.135 +
   2.136 +    /* Ack that we've switched */
   2.137 +    xs_write(xsh, XBT_NULL, active_path, act, len);
   2.138 +    free(act);
   2.139 +}
   2.140 +
   2.141 +
   2.142 +
   2.143  void xenstore_process_event(void *opaque)
   2.144  {
   2.145      char **vec, *image = NULL;
   2.146 @@ -210,6 +332,11 @@ void xenstore_process_event(void *opaque
   2.147      if (!vec)
   2.148  	return;
   2.149  
   2.150 +    if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
   2.151 +        xenstore_process_logdirty_event();
   2.152 +        goto out;
   2.153 +    }
   2.154 +
   2.155      if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
   2.156  	strlen(vec[XS_WATCH_TOKEN]) != 3)
   2.157  	goto out;
     3.1 --- a/tools/libxc/Makefile	Fri Mar 16 10:42:25 2007 +0000
     3.2 +++ b/tools/libxc/Makefile	Fri Mar 16 11:39:50 2007 +0000
     3.3 @@ -57,7 +57,7 @@ GUEST_SRCS-$(CONFIG_IA64)    += xc_dom_c
     3.4  
     3.5  CFLAGS   += -Werror -Wmissing-prototypes
     3.6  CFLAGS   += -fno-strict-aliasing
     3.7 -CFLAGS   += $(INCLUDES) -I.
     3.8 +CFLAGS   += $(INCLUDES) -I. -I../xenstore
     3.9  
    3.10  # Needed for posix_fadvise64() in xc_linux.c
    3.11  CFLAGS-$(CONFIG_Linux) += -D_GNU_SOURCE
     4.1 --- a/tools/libxc/xc_hvm_save.c	Fri Mar 16 10:42:25 2007 +0000
     4.2 +++ b/tools/libxc/xc_hvm_save.c	Fri Mar 16 11:39:50 2007 +0000
     4.3 @@ -54,6 +54,11 @@ static unsigned long hvirt_start;
     4.4  /* #levels of page tables used by the current guest */
     4.5  static unsigned int pt_levels;
     4.6  
     4.7 +/* Shared-memory bitmaps for getting log-dirty bits from qemu */
     4.8 +static unsigned long *qemu_bitmaps[2];
     4.9 +static int qemu_active;
    4.10 +static int qemu_non_active;
    4.11 +
    4.12  int xc_hvm_drain_io(int handle, domid_t dom)
    4.13  {
    4.14      DECLARE_HYPERCALL;
    4.15 @@ -77,7 +82,8 @@ int xc_hvm_drain_io(int handle, domid_t 
    4.16  */
    4.17  
    4.18  #define BITS_PER_LONG (sizeof(unsigned long) * 8)
    4.19 -#define BITMAP_SIZE   ((pfn_array_size + BITS_PER_LONG - 1) / 8)
    4.20 +#define BITS_TO_LONGS(bits) (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
    4.21 +#define BITMAP_SIZE   (BITS_TO_LONGS(pfn_array_size) * sizeof(unsigned long))
    4.22  
    4.23  #define BITMAP_ENTRY(_nr,_bmap) \
    4.24     ((unsigned long *)(_bmap))[(_nr)/BITS_PER_LONG]
    4.25 @@ -124,6 +130,7 @@ static inline int permute( int i, int nr
    4.26      return i;
    4.27  }
    4.28  
    4.29 +
    4.30  static uint64_t tv_to_us(struct timeval *new)
    4.31  {
    4.32      return (new->tv_sec * 1000000) + new->tv_usec;
    4.33 @@ -277,7 +284,9 @@ static int suspend_and_state(int (*suspe
    4.34  }
    4.35  
    4.36  int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
    4.37 -                  uint32_t max_factor, uint32_t flags, int (*suspend)(int))
    4.38 +                uint32_t max_factor, uint32_t flags, int (*suspend)(int),
    4.39 +                void *(*init_qemu_maps)(int, unsigned), 
    4.40 +                void (*qemu_flip_buffer)(int, int))
    4.41  {
    4.42      xc_dominfo_t info;
    4.43  
    4.44 @@ -392,8 +401,6 @@ int xc_hvm_save(int xc_handle, int io_fd
    4.45              "nr_pages=0x%lx\n", info.max_memkb, max_mfn, info.nr_pages); 
    4.46  
    4.47      if (live) {
    4.48 -        ERROR("hvm domain doesn't support live migration now.\n");
    4.49 -        goto out;
    4.50          
    4.51          if (xc_shadow_control(xc_handle, dom,
    4.52                                XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY,
    4.53 @@ -453,6 +460,15 @@ int xc_hvm_save(int xc_handle, int io_fd
    4.54      to_skip = malloc(BITMAP_SIZE);
    4.55  
    4.56  
    4.57 +    if (live) {
    4.58 +        /* Get qemu-dm logging dirty pages too */
    4.59 +        void *seg = init_qemu_maps(dom, BITMAP_SIZE);
    4.60 +        qemu_bitmaps[0] = seg;
    4.61 +        qemu_bitmaps[1] = seg + BITMAP_SIZE;
    4.62 +        qemu_active = 0;
    4.63 +        qemu_non_active = 1;
    4.64 +    }
    4.65 +
    4.66      hvm_buf_size = xc_domain_hvm_getcontext(xc_handle, dom, 0, 0);
    4.67      if ( hvm_buf_size == -1 )
    4.68      {
    4.69 @@ -677,10 +693,23 @@ int xc_hvm_save(int xc_handle, int io_fd
    4.70                  goto out;
    4.71              }
    4.72  
    4.73 +            /* Pull in the dirty bits from qemu too */
    4.74 +            if (!last_iter) {
    4.75 +                qemu_active = qemu_non_active;
    4.76 +                qemu_non_active = qemu_active ? 0 : 1;
    4.77 +                qemu_flip_buffer(dom, qemu_active);
    4.78 +                for (j = 0; j < BITMAP_SIZE / sizeof(unsigned long); j++) {
    4.79 +                    to_send[j] |= qemu_bitmaps[qemu_non_active][j];
    4.80 +                    qemu_bitmaps[qemu_non_active][j] = 0;
    4.81 +                }
    4.82 +            } else {
    4.83 +                for (j = 0; j < BITMAP_SIZE / sizeof(unsigned long); j++) 
    4.84 +                    to_send[j] |= qemu_bitmaps[qemu_active][j];
    4.85 +            }
    4.86 +
    4.87              sent_last_iter = sent_this_iter;
    4.88  
    4.89              print_stats(xc_handle, dom, sent_this_iter, &stats, 1);
    4.90 -
    4.91          }
    4.92  
    4.93  
     5.1 --- a/tools/libxc/xenguest.h	Fri Mar 16 10:42:25 2007 +0000
     5.2 +++ b/tools/libxc/xenguest.h	Fri Mar 16 11:39:50 2007 +0000
     5.3 @@ -32,8 +32,10 @@ int xc_linux_save(int xc_handle, int io_
     5.4   * @return 0 on success, -1 on failure
     5.5   */
     5.6  int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
     5.7 -                  uint32_t max_factor, uint32_t flags /* XCFLAGS_xxx */,
     5.8 -                  int (*suspend)(int domid));
     5.9 +                uint32_t max_factor, uint32_t flags /* XCFLAGS_xxx */,
    5.10 +                int (*suspend)(int domid),  
    5.11 +                void *(*init_qemu_maps)(int, unsigned), 
    5.12 +                void (*qemu_flip_buffer)(int, int));
    5.13  
    5.14  /**
    5.15   * This function will restore a saved domain running Linux.
     6.1 --- a/tools/libxc/xg_private.c	Fri Mar 16 10:42:25 2007 +0000
     6.2 +++ b/tools/libxc/xg_private.c	Fri Mar 16 11:39:50 2007 +0000
     6.3 @@ -201,7 +201,9 @@ unsigned long csum_page(void *page)
     6.4  __attribute__((weak)) 
     6.5      int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
     6.6                      uint32_t max_factor, uint32_t flags,
     6.7 -                    int (*suspend)(int domid))
     6.8 +                    int (*suspend)(int domid), 
     6.9 +                    void *(*init_qemu_maps)(int, unsigned), 
    6.10 +                    void (*qemu_flip_buffer)(int, int))
    6.11  {
    6.12      errno = ENOSYS;
    6.13      return -1;
     7.1 --- a/tools/xcutils/Makefile	Fri Mar 16 10:42:25 2007 +0000
     7.2 +++ b/tools/xcutils/Makefile	Fri Mar 16 11:39:50 2007 +0000
     7.3 @@ -13,7 +13,7 @@ include $(XEN_ROOT)/tools/Rules.mk
     7.4  
     7.5  PROGRAMS_INSTALL_DIR = /usr/$(LIBDIR)/xen/bin
     7.6  
     7.7 -INCLUDES += -I $(XEN_LIBXC)
     7.8 +INCLUDES += -I $(XEN_LIBXC) -I $(XEN_XENSTORE)
     7.9  
    7.10  CFLAGS += -Werror -fno-strict-aliasing
    7.11  CFLAGS += $(INCLUDES)
    7.12 @@ -22,9 +22,9 @@ CFLAGS += $(INCLUDES)
    7.13  CFLAGS += -Wp,-MD,.$(@F).d
    7.14  PROG_DEP = .*.d
    7.15  
    7.16 -PROGRAMS		= xc_restore xc_save readnotes
    7.17 +PROGRAMS = xc_restore xc_save readnotes
    7.18  
    7.19 -LDLIBS			= -L$(XEN_LIBXC) -lxenguest -lxenctrl
    7.20 +LDLIBS   = -L$(XEN_LIBXC) -L$(XEN_XENSTORE) -lxenguest -lxenctrl -lxenstore
    7.21  
    7.22  .PHONY: all
    7.23  all: build
     8.1 --- a/tools/xcutils/xc_save.c	Fri Mar 16 10:42:25 2007 +0000
     8.2 +++ b/tools/xcutils/xc_save.c	Fri Mar 16 11:39:50 2007 +0000
     8.3 @@ -12,7 +12,13 @@
     8.4  #include <stdint.h>
     8.5  #include <string.h>
     8.6  #include <stdio.h>
     8.7 +#include <sys/ipc.h>
     8.8 +#include <sys/shm.h>
     8.9 +#include <sys/types.h>
    8.10 +#include <sys/stat.h>
    8.11 +#include <fcntl.h>
    8.12  
    8.13 +#include <xs.h>
    8.14  #include <xenctrl.h>
    8.15  #include <xenguest.h>
    8.16  
    8.17 @@ -31,6 +37,123 @@ static int suspend(int domid)
    8.18              !strncmp(ans, "done\n", 5));
    8.19  }
    8.20  
    8.21 +/* For HVM guests, there are two sources of dirty pages: the Xen shadow
    8.22 + * log-dirty bitmap, which we get with a hypercall, and qemu's version.
    8.23 + * The protocol for getting page-dirtying data from qemu uses a
    8.24 + * double-buffered shared memory interface directly between xc_save and
    8.25 + * qemu-dm. 
    8.26 + *
    8.27 + * xc_save calculates the size of the bitmaps and notifies qemu-dm 
    8.28 + * through the store that it wants to share the bitmaps.  qemu-dm then 
    8.29 + * starts filling in the 'active' buffer. 
    8.30 + *
    8.31 + * To change the buffers over, xc_save writes the other buffer number to
    8.32 + * the store and waits for qemu to acknowledge that it is now writing to
    8.33 + * the new active buffer.  xc_save can then process and clear the old
    8.34 + * active buffer. */
    8.35 +
    8.36 +static char *qemu_active_path;
    8.37 +static char *qemu_next_active_path;
    8.38 +static struct xs_handle *xs;
    8.39 +
    8.40 +/* Get qemu to change buffers. */
    8.41 +static void qemu_flip_buffer(int domid, int next_active)
    8.42 +{
    8.43 +    char digit = '0' + next_active;
    8.44 +    unsigned int len;
    8.45 +    char *active_str, **watch;
    8.46 +    struct timeval tv;
    8.47 +    fd_set fdset;
    8.48 +
    8.49 +    /* Tell qemu that we want it to start writing log-dirty bits to the
    8.50 +     * other buffer */
    8.51 +    if (!xs_write(xs, XBT_NULL, qemu_next_active_path, &digit, 1)) {
    8.52 +        errx(1, "can't write next-active to store path (%s)\n", 
    8.53 +              qemu_next_active_path);
    8.54 +        exit(1);
    8.55 +    }
    8.56 +
    8.57 +    /* Wait a while for qemu to signal that it has switched to the new 
    8.58 +     * active buffer */
    8.59 + read_again: 
    8.60 +    tv.tv_sec = 5;
    8.61 +    tv.tv_usec = 0;
    8.62 +    FD_ZERO(&fdset);
    8.63 +    FD_SET(xs_fileno(xs), &fdset);
    8.64 +    if ((select(xs_fileno(xs) + 1, &fdset, NULL, NULL, &tv)) != 1) {
    8.65 +        errx(1, "timed out waiting for qemu to switch buffers\n");
    8.66 +        exit(1);
    8.67 +    }
    8.68 +    watch = xs_read_watch(xs, &len);
    8.69 +    free(watch);
    8.70 +    
    8.71 +    active_str = xs_read(xs, XBT_NULL, qemu_active_path, &len);
    8.72 +    if (active_str == NULL || active_str[0] - '0' != next_active) 
    8.73 +        /* Watch fired but value is not yet right */
    8.74 +        goto read_again;
    8.75 +}
    8.76 +
    8.77 +static void * init_qemu_maps(int domid, unsigned int bitmap_size)
    8.78 +{
    8.79 +    key_t key;
    8.80 +    char key_ascii[17] = {0,};
    8.81 +    int shmid = -1;
    8.82 +    void *seg; 
    8.83 +    char *path, *p;
    8.84 +
    8.85 +    /* Make a shared-memory segment */
    8.86 +    while (shmid == -1)
    8.87 +    {
    8.88 +        key = rand(); /* No security, just a sequence of numbers */
    8.89 +        shmid = shmget(key, 2 * bitmap_size, 
    8.90 +                       IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
    8.91 +        if (shmid == -1 && errno != EEXIST)
    8.92 +            errx(1, "can't get shmem to talk to qemu-dm");
    8.93 +    }
    8.94 +
    8.95 +    /* Map it into our address space */
    8.96 +    seg = shmat(shmid, NULL, 0);
    8.97 +    if (seg == (void *) -1) 
    8.98 +        errx(1, "can't map shmem to talk to qemu-dm");
    8.99 +    memset(seg, 0, 2 * bitmap_size);
   8.100 +
   8.101 +    /* Write the size of it into the first 32 bits */
   8.102 +    *(uint32_t *)seg = bitmap_size;
   8.103 +
   8.104 +    /* Tell qemu about it */
   8.105 +    if ((xs = xs_daemon_open()) == NULL)
   8.106 +        errx(1, "Couldn't contact xenstore");
   8.107 +    if (!(path = xs_get_domain_path(xs, domid)))
   8.108 +        errx(1, "can't get domain path in store");
   8.109 +    if (!(path = realloc(path, strlen(path) 
   8.110 +                         + strlen("/logdirty/next-active") + 1))) 
   8.111 +        errx(1, "no memory for constructing xenstore path");
   8.112 +    strcat(path, "/logdirty/");
   8.113 +    p = path + strlen(path);
   8.114 +
   8.115 +    strcpy(p, "key");
   8.116 +    snprintf(key_ascii, 17, "%16.16llx", (unsigned long long) key);
   8.117 +    if (!xs_write(xs, XBT_NULL, path, key_ascii, 16))
   8.118 +        errx(1, "can't write key (%s) to store path (%s)\n", key_ascii, path);
   8.119 +
   8.120 +    /* Watch for qemu's indication of the active buffer, and request it 
   8.121 +     * to start writing to buffer 0 */
   8.122 +    strcpy(p, "active");
   8.123 +    if (!xs_watch(xs, path, "qemu-active-buffer"))
   8.124 +        errx(1, "can't set watch in store (%s)\n", path);
   8.125 +    if (!(qemu_active_path = strdup(path)))
   8.126 +        errx(1, "no memory for copying xenstore path");
   8.127 +
   8.128 +    strcpy(p, "next-active");
   8.129 +    if (!(qemu_next_active_path = strdup(path)))
   8.130 +        errx(1, "no memory for copying xenstore path");
   8.131 +
   8.132 +    qemu_flip_buffer(domid, 0);
   8.133 +
   8.134 +    free(path);
   8.135 +    return seg;
   8.136 +}
   8.137 +
   8.138  
   8.139  int
   8.140  main(int argc, char **argv)
   8.141 @@ -52,9 +175,11 @@ main(int argc, char **argv)
   8.142      flags = atoi(argv[5]);
   8.143  
   8.144      if (flags & XCFLAGS_HVM)
   8.145 -        ret = xc_hvm_save(xc_fd, io_fd, domid, maxit, max_f, flags, &suspend);
   8.146 +        ret = xc_hvm_save(xc_fd, io_fd, domid, maxit, max_f, flags, 
   8.147 +                          &suspend, &init_qemu_maps, &qemu_flip_buffer);
   8.148      else 
   8.149 -        ret = xc_linux_save(xc_fd, io_fd, domid, maxit, max_f, flags, &suspend);
   8.150 +        ret = xc_linux_save(xc_fd, io_fd, domid, maxit, max_f, flags, 
   8.151 +                            &suspend);
   8.152  
   8.153      xc_interface_close(xc_fd);
   8.154