Create log-dirty shared memory between stubdom-dm and xc_save.
Allocate the log-dirty shared memory segment in the stubdom-dm and map the
memory region into the xc_save process by using grant table interface.

Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>

diff -r 6595393a3d28 extras/mini-os/logdirty.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extras/mini-os/logdirty.c	Tue Dec 16 14:39:49 2008 +0900
@@ -0,0 +1,135 @@
+/******************************************************************************
+ * logdirty.c
+ * 
+ * Log-dirty bitmap allocator for Mini-OS.
+ * 
+ * Copyright (c) 2008, NEC Corporation.
+ *      Yosuke Iwamatsu <y-iwamatsu at ab jp nec com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <os.h>
+#include <xenbus.h>
+#include <gnttab.h>
+#include <lib.h>
+#include <xen/io/logdirty.h>
+
+#define GRANT_INVALID_REF 0
+
+static grant_ref_t ring_ref = GRANT_INVALID_REF;
+static struct logdirty_shared_info *sh_info = NULL;
+static void *seg = NULL;
+
+static void free_logdirty_bitmap(void)
+{
+    int i;
+
+    if (ring_ref == GRANT_INVALID_REF)
+        return;
+
+    if (!sh_info)
+        goto end_ring_access;
+
+    if (!seg)
+        goto free_sh_info;
+
+    for (i = 0; i < sh_info->count; i++)
+        gnttab_end_access(sh_info->gref[i]);
+    free_pages(seg, sh_info->count);
+    seg = NULL;
+
+  free_sh_info:
+    free_page(sh_info);
+    sh_info = NULL;
+
+  end_ring_access:
+    gnttab_end_access(ring_ref);
+    ring_ref = GRANT_INVALID_REF;
+}
+
+void *init_logdirty_bitmap(char *_nodename, unsigned long size, domid_t backend)
+{
+    unsigned int page_count;
+    int i;
+    xenbus_transaction_t xbt;
+    char *err;
+    char *message = NULL;
+    int retry = 0;
+
+    printk("Initialising logdirty bitmap\n");
+
+    page_count = ((2 * size - 1) >> PAGE_SHIFT) + 1;
+    if (page_count > LOGDIRTY_MAX_PAGE_COUNT) {
+        printk("Log dirty bitmap size too large: %u", size);
+        goto error;
+    }
+    
+    sh_info = (struct logdirty_shared_info *)alloc_page();
+    memset(sh_info, 0, PAGE_SIZE);
+    sh_info->count = page_count;
+
+    seg = (void *)alloc_pages(get_order(2 * size));
+    memset(seg, 0, sh_info->count * PAGE_SIZE);
+    for (i = 0; i < sh_info->count; i++)
+        sh_info->gref[i] =
+            gnttab_grant_access(backend,
+                                virt_to_mfn((char *)seg + i * PAGE_SIZE),
+                                0);
+
+    ring_ref = gnttab_grant_access(backend, virt_to_mfn(sh_info), 0);
+ 
+ again:
+    err = xenbus_transaction_start(&xbt);
+    if (err) {
+        printk("starting transaction\n");
+    }
+
+    err = xenbus_printf(xbt, _nodename, "ring-ref", "%u", ring_ref);
+    if (err) {
+        message = "writing ring-ref";
+        goto abort_transaction;
+    }
+
+    err = xenbus_printf(xbt, _nodename, "domid", "%u", xenbus_get_self_id());
+    if (err) {
+        message = "writing domid";
+        goto abort_transaction;
+    }
+
+    err = xenbus_transaction_end(xbt, 0, &retry);
+    if (retry) {
+            goto again;
+        printk("completing transaction\n");
+    }
+
+    goto done;
+
+ abort_transaction:
+    xenbus_transaction_end(xbt, 1, &retry);
+    goto error;
+
+ done:
+    return seg;
+
+ error:
+    free_logdirty_bitmap();
+    return NULL;
+}
+
diff -r 6595393a3d28 tools/libxc/xenguest.h
--- a/tools/libxc/xenguest.h	Tue Dec 09 16:28:02 2008 +0000
+++ b/tools/libxc/xenguest.h	Tue Dec 16 14:39:49 2008 +0900
@@ -13,6 +13,7 @@
 #define XCFLAGS_DEBUG     2
 #define XCFLAGS_HVM       4
 #define XCFLAGS_STDVGA    8
+#define XCFLAGS_STUBDOM  16
 
 
 /**
diff -r 6595393a3d28 tools/xcutils/xc_save.c
--- a/tools/xcutils/xc_save.c	Tue Dec 09 16:28:02 2008 +0000
+++ b/tools/xcutils/xc_save.c	Tue Dec 16 14:39:49 2008 +0900
@@ -16,12 +16,14 @@
 #include <sys/shm.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
 #include <fcntl.h>
 #include <err.h>
 
 #include <xs.h>
 #include <xenctrl.h>
 #include <xenguest.h>
+#include <xen/io/logdirty.h>
 
 static struct suspendinfo {
     int xc_fd; /* libxc handle */
@@ -197,6 +199,9 @@ static int qemu_shmid = -1;
 static int qemu_shmid = -1;
 static struct xs_handle *xs;
 
+static int gnt_handle = -1;
+static struct logdirty_shared_info *logdirty_sh_info = NULL;
+static void *logdirty_seg = NULL;
 
 /* Mark the shared-memory segment for destruction */
 static void qemu_destroy_buffer(void)
@@ -204,6 +209,41 @@ static void qemu_destroy_buffer(void)
     if (qemu_shmid != -1)
         shmctl(qemu_shmid, IPC_RMID, NULL);
     qemu_shmid = -1;
+}
+
+/* Unmap the shared-memory segment using libxc gnttab interface */
+static void stubdom_destroy_buffer(void)
+{
+    int ret;
+
+    if (gnt_handle == -1)
+        return;
+
+    if (!logdirty_sh_info)
+        goto close_gnt_handle;
+
+    if (!logdirty_seg)
+        goto unmap_sh_info;
+
+    /* Unmap the shared-memory segment */
+    ret = xc_gnttab_munmap(gnt_handle,
+                           logdirty_seg,
+                           logdirty_sh_info->count);
+    if (ret == -1)
+        warnx("can't unmap logdirty segment");
+    logdirty_seg = NULL;
+
+ unmap_sh_info:
+    ret = xc_gnttab_munmap(gnt_handle, logdirty_sh_info, 1);
+    if (ret == -1)
+        warnx("can't unmap logdirty shared info");
+    logdirty_sh_info = NULL;
+
+ close_gnt_handle:
+    ret = xc_gnttab_close(gnt_handle);
+    if (ret == -1)
+        warnx("can't close gnttab handle");
+    gnt_handle = -1;
 }
 
 /* Get qemu to change buffers. */
@@ -303,12 +343,111 @@ static void *init_qemu_maps(int domid, u
     return seg;
 }
 
+static void *init_stubdom_maps(int domid, unsigned int bitmap_size)
+{
+    key_t key;
+    char key_ascii[17] = {0,};
+    char *path, *p;
+
+    char *ring_str, *stub_str;
+    unsigned int ring_ref, stub_domid;
+    unsigned int len;
+    uint32_t domids[LOGDIRTY_MAX_PAGE_COUNT];
+    int i;
+
+    /* Write a key to xenstore */
+    key = rand();
+
+    if ((xs = xs_daemon_open()) == NULL)
+        errx(1, "Couldn't contact xenstore");
+    if (!(path = strdup("/local/domain/0/device-model/")))
+        errx(1, "can't get domain path in store");
+    if (!(path = realloc(path, strlen(path) 
+                         + 10 
+                         + strlen("/logdirty/next-active") + 1))) 
+        errx(1, "no memory for constructing xenstore path");
+    snprintf(path + strlen(path), 11, "%i", domid);
+    strcat(path, "/logdirty/");
+    p = path + strlen(path);
+
+    strcpy(p, "key");
+    snprintf(key_ascii, 17, "%16.16llx", (unsigned long long) key);
+    if (!xs_write(xs, XBT_NULL, path, key_ascii, 16))
+        errx(1, "can't write key (%s) to store path (%s)\n", key_ascii, path);
+
+    /* Watch for qemu's indication of the active buffer, and request it 
+     * to allocate the shared-memory segment */
+    strcpy(p, "active");
+    if (!xs_watch(xs, path, "qemu-active-buffer"))
+        errx(1, "can't set watch in store (%s)\n", path);
+    if (!(qemu_active_path = strdup(path)))
+        errx(1, "no memory for copying xenstore path");
+
+    strcpy(p, "next-active");
+    if (!(qemu_next_active_path = strdup(path)))
+        errx(1, "no memory for copying xenstore path");
+
+    qemu_flip_buffer(domid, 0);
+
+    /* Get the ring-ref from xenstore */
+    strcpy(p, "ring-ref");
+    ring_str = xs_read(xs, XBT_NULL, path, &len);
+    if (!ring_str || !len)
+        errx(1, "can't get ring-ref path (%s) in store\n", path);
+    ring_ref = atoi(ring_str);
+    free(ring_str);
+
+    /* Get the stub domain id from xenstore */
+    strcpy(p, "domid");
+    stub_str = xs_read(xs, XBT_NULL, path, &len);
+    if (!stub_str || !len)
+        errx(1, "can't get domid path (%s) in store\n", path);
+    stub_domid = atoi(stub_str);
+    free(stub_str);
+
+    /* Remember to tidy up after ourselves */
+    atexit(stubdom_destroy_buffer);
+
+    /* Map the shared-memory segment using libxc gnttab interface */
+    gnt_handle = xc_gnttab_open();
+    if (gnt_handle == -1)
+        errx(1, "can't get gnttab handle");
+
+    logdirty_sh_info = (struct logdirty_shared_info *)
+                       xc_gnttab_map_grant_ref(gnt_handle,
+                                               stub_domid,
+                                               ring_ref,
+                                               PROT_READ | PROT_WRITE);
+    if (!logdirty_sh_info)
+        errx(1, "can't map ring-ref %u of domain %u", ring_ref, stub_domid);
+
+    for (i = 0; i < logdirty_sh_info->count; i++)
+        domids[i] = stub_domid;
+    logdirty_seg = xc_gnttab_map_grant_refs(gnt_handle,
+                                            logdirty_sh_info->count,
+                                            domids,
+                                            logdirty_sh_info->gref,
+                                            PROT_READ | PROT_WRITE);
+    if (!logdirty_seg)
+        errx(1, "can't map logdirty bitmap segment\n");
+
+    /* Check that the bitmaps are the size we expect */
+    if (bitmap_size != *(uint32_t *)logdirty_seg) {
+        errx(1, "Allocated bitmap size %u differs from expected size %u",
+             *(uint32_t *)logdirty_seg, bitmap_size);
+    }
+
+    free(path);
+    return logdirty_seg;
+}
+
 
 int
 main(int argc, char **argv)
 {
     unsigned int maxit, max_f;
     int io_fd, ret;
+    void *(*init_maps_fn)(int, unsigned);
 
     if (argc != 6)
         errx(1, "usage: %s iofd domid maxit maxf flags", argv[0]);
@@ -326,10 +465,13 @@ main(int argc, char **argv)
     if (suspend_evtchn_init(si.xc_fd, si.domid) < 0)
         warnx("suspend event channel initialization failed, using slow path");
 
+    init_maps_fn = !!(si.flags & XCFLAGS_STUBDOM)
+                   ? init_stubdom_maps
+                   : init_qemu_maps;
     ret = xc_domain_save(si.xc_fd, io_fd, si.domid, maxit, max_f, si.flags, 
                          &suspend, !!(si.flags & XCFLAGS_HVM),
-                         &init_qemu_maps, &qemu_flip_buffer);
-
+                         init_maps_fn, &qemu_flip_buffer);
+ 
     suspend_evtchn_release();
 
     xc_interface_close(si.xc_fd);
diff -r 6595393a3d28 xen/include/public/io/logdirty.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/io/logdirty.h	Tue Dec 16 14:39:49 2008 +0900
@@ -0,0 +1,52 @@
+/******************************************************************************
+ * logdirty.h
+ * 
+ * Log-dirty interface for Xen stubdom-dms and dom0.
+ * 
+ * Copyright (c) 2008, NEC Corporation.
+ *      Yosuke Iwamatsu <y-iwamatsu at ab jp nec com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __XEN_PUBLIC_IO_LOGDIRTY_H__
+#define __XEN_PUBLIC_IO_LOGDIRTY_H__
+
+#include "../grant_table.h"
+
+/* Should not exceed (PAGE_SIZE-sizeof(unsigned int))/sizeof(grant_ref_t) */
+#define LOGDIRTY_MAX_PAGE_COUNT 1023
+
+struct logdirty_shared_info
+{
+    unsigned int count;
+    grant_ref_t gref[LOGDIRTY_MAX_PAGE_COUNT];
+};
+
+#endif /* __XEN_PUBLIC_IO_LOGDIRTY_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */

