Index: xen-3.3.0-testing/tools/ioemu/vl.c =================================================================== --- xen-3.3.0-testing.orig/tools/ioemu/vl.c +++ xen-3.3.0-testing/tools/ioemu/vl.c @@ -108,6 +108,8 @@ #include "exec-all.h" +#include "block_int.h" + #define DEFAULT_NETWORK_SCRIPT "/etc/xen/qemu-ifup" #ifdef _BSD #define DEFAULT_BRIDGE "bridge0" @@ -5155,6 +5157,83 @@ void do_loadvm(const char *name) if (saved_vm_running) 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_DISKS; i++) { + bs = bs_table[i]; + + 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_DISKS; i++) { + bs = bs_table[i]; + + /* 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; +} + + #else void do_savevm(const char *name) { Index: xen-3.3.0-testing/tools/ioemu/target-i386-dm/helper2.c =================================================================== --- xen-3.3.0-testing.orig/tools/ioemu/target-i386-dm/helper2.c +++ xen-3.3.0-testing/tools/ioemu/target-i386-dm/helper2.c @@ -92,6 +92,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(void) { CPUX86State *env; @@ -556,9 +559,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 (suspend_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.0-testing/tools/ioemu/vl.h =================================================================== --- xen-3.3.0-testing.orig/tools/ioemu/vl.h +++ xen-3.3.0-testing/tools/ioemu/vl.h @@ -59,7 +59,6 @@ extern int qemu_ftruncate64(int, int64_t); #define ftruncate qemu_ftruncate64 - static inline char *realpath(const char *path, char *resolved_path) { _fullpath(resolved_path, path, _MAX_PATH); @@ -72,6 +71,11 @@ static inline char *realpath(const char #define PRIo64 "I64o" #endif +enum { + SUSPEND_SAVEVM = 1, + SUSPEND_SNAPSHOT = 2 +}; + #ifdef QEMU_TOOL /* we use QEMU_TOOL in the command line tools which do not depend on @@ -557,6 +561,8 @@ void do_loadvm(const char *name); void do_delvm(const char *name); void do_info_snapshots(void); +int save_disk_snapshots(const char* name); + /* bottom halves */ typedef void QEMUBHFunc(void *opaque); Index: xen-3.3.0-testing/tools/ioemu/xenstore.c =================================================================== --- xen-3.3.0-testing.orig/tools/ioemu/xenstore.c +++ xen-3.3.0-testing/tools/ioemu/xenstore.c @@ -536,6 +536,7 @@ static void xenstore_process_dm_command_ char *path = NULL, *command = NULL, *par = NULL; unsigned int len; extern int suspend_requested; + extern char* snapshot_name; if (pasprintf(&path, "/local/domain/0/device-model/%u/command", domid) == -1) { @@ -548,7 +549,18 @@ static void xenstore_process_dm_command_ if (!strncmp(command, "save", len)) { fprintf(logfile, "dm-command: pause and save state\n"); - suspend_requested = 1; + suspend_requested = SUSPEND_SAVEVM; + } else if (!strncmp(command, "snapshot", len)) { + fprintf(logfile, "dm-command: pause and snapshot disks\n"); + suspend_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"); suspend_requested = 0; Index: xen-3.3.0-testing/tools/ioemu/hw/xen_blktap.c =================================================================== --- xen-3.3.0-testing.orig/tools/ioemu/hw/xen_blktap.c +++ xen-3.3.0-testing/tools/ioemu/hw/xen_blktap.c @@ -221,8 +221,12 @@ static int open_disk(struct td_state *s, struct disk_id id; BlockDriverState* bs; +#ifndef QEMU_TOOL + int i; +#endif + DPRINTF("Opening %s\n", path); - bs = calloc(1, sizeof(*bs)); + bs = bdrv_new("blktap"); memset(&id, 0, sizeof(struct disk_id)); @@ -238,6 +242,15 @@ static int open_disk(struct td_state *s, s->info = ((s->flags & TD_RDONLY) ? VDISK_READONLY : 0); +#ifndef QEMU_TOOL + for (i = 0; i < MAX_DISKS + MAX_SCSI_DISKS; i++) { + if (bs_table[i] == NULL) { + bs_table[i] = bs; + break; + } + } +#endif + return 0; }