Index: xen-3.3.1-testing/tools/ioemu-remote/xen-vl-extra.c =================================================================== --- xen-3.3.1-testing.orig/tools/ioemu-remote/xen-vl-extra.c +++ xen-3.3.1-testing/tools/ioemu-remote/xen-vl-extra.c @@ -8,12 +8,18 @@ * there is only one place where this file is included. */ #include "qemu-xen.h" +#include "block_int.h" /* forward declarations of things in vl.c */ static int qemu_savevm_state(QEMUFile *f); static int qemu_loadvm_state(QEMUFile *f); +static int bdrv_can_snapshot(BlockDriverState *bs); +static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, + const char *name); + + /* We use simpler state save/load functions for Xen */ void do_savevm(const char *name) @@ -85,6 +91,81 @@ void do_loadvm(const char *name) vm_start(); } +int save_disk_snapshots(const char* name) +{ + BlockDriverState *bs; + QEMUSnapshotInfo sn, old_sn; + struct timeval tv; + int saved_vm_running; + int can_snapshot; + int i; + int ret = 0; + + saved_vm_running = vm_running; + vm_stop(0); + + qemu_aio_flush(); + + /* Ensure that all images support snapshots or are read-only */ + for(i = 0; i < MAX_DRIVES; i++) { + bs = drives_table[i].bdrv; + + if (!bs || !bs->drv) + continue; + + can_snapshot = bs->drv->bdrv_snapshot_create && bdrv_can_snapshot(bs); + if (!bdrv_is_read_only(bs) && !can_snapshot) { + fprintf(stderr, "Error: bdrv %s (%s) doesn't support snapshots\n", + bdrv_get_device_name(bs), bs->drv->format_name); + ret = -ENOTSUP; + goto the_end; + } + } + + /* fill auxiliary fields */ + memset(&sn, 0, sizeof(sn)); + gettimeofday(&tv, NULL); + sn.date_sec = tv.tv_sec; + sn.date_nsec = tv.tv_usec * 1000; + sn.vm_clock_nsec = qemu_get_clock(vm_clock); + pstrcpy(sn.name, sizeof(sn.name), name); + + for(i = 0; i < MAX_DRIVES; i++) { + bs = drives_table[i].bdrv; + + /* No snapshots on read-only images */ + if (!bs || !bs->drv || bdrv_is_read_only(bs)) + continue; + + /* Delete old snapshot of the same name */ + if (bdrv_snapshot_find(bs, &old_sn, name) >= 0) { + ret = bdrv_snapshot_delete(bs, old_sn.id_str); + if (ret < 0) { + fprintf(stderr, "Error while deleting snapshot on '%s'\n", + bdrv_get_device_name(bs)); + } + } + + /* Create the snapshot */ + fprintf(stderr, "Creating snapshot on '%s' (%s)\n", + bdrv_get_device_name(bs), bs->drv->format_name); + ret = bdrv_snapshot_create(bs, &sn); + if (ret < 0) { + fprintf(stderr, "Error while creating snapshot on '%s': %d (%s)\n", + bdrv_get_device_name(bs), ret, strerror(-ret)); + goto the_end; + } + } + + fprintf(stderr, "Created all snapshots\n"); + +the_end: + if (saved_vm_running) + vm_start(); + + return ret; +} + struct qemu_alarm_timer; static int unix_start_timer(struct qemu_alarm_timer *t) { return 0; } static void unix_stop_timer(struct qemu_alarm_timer *t) { } Index: xen-3.3.1-testing/tools/ioemu-remote/i386-dm/helper2.c =================================================================== --- xen-3.3.1-testing.orig/tools/ioemu-remote/i386-dm/helper2.c +++ xen-3.3.1-testing/tools/ioemu-remote/i386-dm/helper2.c @@ -101,6 +101,9 @@ int send_vcpu = 0; #define NR_CPUS 32 evtchn_port_t ioreq_local_port[NR_CPUS]; +/** Name of the snapshot which should be saved */ +char* snapshot_name; + CPUX86State *cpu_x86_init(const char *cpu_model) { CPUX86State *env; @@ -574,9 +577,24 @@ int main_loop(void) main_loop_wait(1); /* For the select() on events */ /* Save the device state */ - asprintf(&qemu_file, "/var/lib/xen/qemu-save.%d", domid); - do_savevm(qemu_file); - free(qemu_file); + switch (xen_pause_requested) { + case SUSPEND_SAVEVM: + asprintf(&qemu_file, "/var/lib/xen/qemu-save.%d", domid); + do_savevm(qemu_file); + free(qemu_file); + break; + + case SUSPEND_SNAPSHOT: + // TODO Error reporting + if (snapshot_name != NULL) { + save_disk_snapshots(snapshot_name); + free(snapshot_name); + snapshot_name = NULL; + } else { + fprintf(logfile, "No snapshot name given\n"); + } + break; + } xenstore_record_dm_state("paused"); Index: xen-3.3.1-testing/tools/ioemu-remote/qemu-xen.h =================================================================== --- xen-3.3.1-testing.orig/tools/ioemu-remote/qemu-xen.h +++ xen-3.3.1-testing/tools/ioemu-remote/qemu-xen.h @@ -14,6 +14,15 @@ void qemu_invalidate_map_cache(void) #define mapcache_lock() ((void)0) #define mapcache_unlock() ((void)0) +/* Reason for xen_pause_requested */ +enum { + SUSPEND_SAVEVM = 1, + SUSPEND_SNAPSHOT = 2 +}; + +/* xen-vl-extra.c */ +int save_disk_snapshots(const char* name); + /* helper2.c */ extern long time_offset; void timeoffset_get(void); Index: xen-3.3.1-testing/tools/ioemu-remote/xenstore.c =================================================================== --- xen-3.3.1-testing.orig/tools/ioemu-remote/xenstore.c +++ xen-3.3.1-testing/tools/ioemu-remote/xenstore.c @@ -24,6 +24,7 @@ #include "exec-all.h" #include "sysemu.h" +#include "qemu-xen.h" #include "hw.h" #include "pci.h" @@ -598,6 +599,7 @@ static void xenstore_process_dm_command_ { char *path = NULL, *command = NULL, *par = NULL; unsigned int len; + extern char* snapshot_name; if (pasprintf(&path, "/local/domain/0/device-model/%u/command", domid) == -1) { @@ -610,7 +612,18 @@ static void xenstore_process_dm_command_ if (!strncmp(command, "save", len)) { fprintf(logfile, "dm-command: pause and save state\n"); - xen_pause_requested = 1; + xen_pause_requested = SUSPEND_SAVEVM; + } else if (!strncmp(command, "snapshot", len)) { + fprintf(logfile, "dm-command: pause and snapshot disks\n"); + xen_pause_requested = SUSPEND_SNAPSHOT; + + if (pasprintf(&path, + "/local/domain/0/device-model/%u/parameter", domid) == -1) { + fprintf(logfile, "out of memory reading dm command parameter\n"); + goto out; + } + + snapshot_name = xs_read(xsh, XBT_NULL, path, &len); } else if (!strncmp(command, "continue", len)) { fprintf(logfile, "dm-command: continue after state save\n"); xen_pause_requested = 0;