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 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 + * + * 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 +#include +#include +#include +#include + +#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 #include #include +#include #include #include #include #include #include +#include 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 + * + * 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: + */