Index: xen-3.4.1-testing/tools/ioemu-remote/savevm.c =================================================================== --- xen-3.4.1-testing.orig/tools/ioemu-remote/savevm.c +++ xen-3.4.1-testing/tools/ioemu-remote/savevm.c @@ -28,6 +28,7 @@ #include "sysemu.h" #include "qemu-timer.h" #include "qemu-char.h" +#include "block_int.h" #include "block.h" #include "audio/audio.h" #include "migration.h" @@ -1015,6 +1016,86 @@ static int bdrv_snapshot_find(BlockDrive return ret; } +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; + + /* Deal with all aio submit */ + qemu_aio_flush(); + /* Do fsync at backend fs */ + ret = bdrv_flush_all(); + if (ret) + fprintf(stderr, "Fsync error[%d] when do snapshot[%s]\n", ret, name); + + saved_vm_running = vm_running; + vm_stop(0); + + /* 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; +} + #ifndef CONFIG_DM void do_savevm(const char *name) Index: xen-3.4.1-testing/tools/ioemu-remote/i386-dm/helper2.c =================================================================== --- xen-3.4.1-testing.orig/tools/ioemu-remote/i386-dm/helper2.c +++ xen-3.4.1-testing/tools/ioemu-remote/i386-dm/helper2.c @@ -109,6 +109,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; @@ -551,6 +554,7 @@ int main_loop(void) int evtchn_fd = xce_handle == -1 ? -1 : xc_evtchn_fd(xce_handle); char *qemu_file; fd_set fds; + int ret; main_loop_prepare(); @@ -578,11 +582,43 @@ 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); + xenstore_record_dm_state("paused"); + break; + + case SUSPEND_SNAPSHOT: + if (snapshot_name != NULL) { + ret = save_disk_snapshots(snapshot_name); + free(snapshot_name); + snapshot_name = NULL; + + switch (ret) { + case 0: + xenstore_record_dm_state("paused"); + break; + case -ENOTSUP: + xenstore_record_dm_error("Snapshots not supported on all" + " attached read-write disks"); + break; + case -ENOENT: + xenstore_record_dm_error("A snapshot with the same name" + " already exists"); + break; + default: + xenstore_record_dm_error("An error occurred while saving" + " the snapshot"); + break; + } + } else { + xenstore_record_dm_error("No snapshot name given"); + } + break; + } - xenstore_record_dm_state("paused"); /* Wait to be allowed to continue */ while (xen_pause_requested) { Index: xen-3.4.1-testing/tools/ioemu-remote/qemu-xen.h =================================================================== --- xen-3.4.1-testing.orig/tools/ioemu-remote/qemu-xen.h +++ xen-3.4.1-testing/tools/ioemu-remote/qemu-xen.h @@ -34,6 +34,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); @@ -68,6 +77,7 @@ int xenstore_fd(void); void xenstore_process_event(void *opaque); void xenstore_record_dm(const char *subpath, const char *state); void xenstore_record_dm_state(const char *state); +void xenstore_record_dm_error(char *errmsg); void xenstore_check_new_media_present(int timeout); void xenstore_write_vncport(int vnc_display); void xenstore_read_vncpasswd(int domid, char *pwbuf, size_t pwbuflen); Index: xen-3.4.1-testing/tools/ioemu-remote/xenstore.c =================================================================== --- xen-3.4.1-testing.orig/tools/ioemu-remote/xenstore.c +++ xen-3.4.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" @@ -849,6 +850,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) { @@ -861,7 +863,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; @@ -966,6 +979,13 @@ void xenstore_record_dm_state(const char xenstore_record_dm("state", state); } +void xenstore_record_dm_error(char *errmsg) +{ + fprintf(logfile, "%s\n", errmsg); + xenstore_record_dm("error", errmsg); + xenstore_record_dm_state("error"); +} + void xenstore_process_media_change_event(char **vec) { char *media_present = NULL;