+++ /dev/null
-Index: new/qapi-schema.json
-===================================================================
---- new.orig/qapi-schema.json 2012-09-19 12:53:31.000000000 +0200
-+++ new/qapi-schema.json 2012-09-19 12:54:14.000000000 +0200
-@@ -2493,3 +2493,12 @@
- # Since: 1.2.0
- ##
- { 'command': 'query-target', 'returns': 'TargetInfo' }
-+
-+
-+{ 'command': 'snapshot-start' 'data': { '*statefile': 'str' } }
-+
-+{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
-+
-+{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } }
-+
-+{ 'command': 'snapshot-end' }
-Index: new/qmp.c
-===================================================================
---- new.orig/qmp.c 2012-09-19 12:53:31.000000000 +0200
-+++ new/qmp.c 2012-09-19 14:04:48.000000000 +0200
-@@ -479,3 +479,196 @@
- return arch_query_cpu_definitions(errp);
- }
-
-+static struct SnapshotState {
-+ int in_progress;
-+ int saved_vm_running;
-+} snap_state;
-+
-+void qmp_snapshot_start(bool has_statefile, const char *statefile, Error **errp)
-+{
-+ BlockDriverState *bs = NULL;
-+ BlockDriver *drv = NULL;
-+ int bdrv_oflags = BDRV_O_CACHE_WB | BDRV_O_RDWR;
-+ int64_t pos;
-+ QEMUFile *f;
-+ int ret;
-+
-+ if (snap_state.in_progress) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "VM snapshot already started\n");
-+ return;
-+ }
-+
-+ snap_state.in_progress = 1;
-+
-+ snap_state.saved_vm_running = runstate_is_running();
-+
-+ vm_stop(RUN_STATE_SAVE_VM);
-+
-+ if (!has_statefile) {
-+ return;
-+ }
-+
-+ /* Open the image */
-+ bs = bdrv_new("vmstate");
-+ ret = bdrv_open(bs, statefile, bdrv_oflags, drv);
-+ if (ret < 0) {
-+ error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
-+ goto restart;
-+ }
-+
-+ f = qemu_fopen_bdrv(bs, 1);
-+ if (!f) {
-+ error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
-+ goto restart;
-+ }
-+
-+ ret = qemu_savevm_state(f);
-+
-+ // try to truncate, but ignore errors (will fail on block devices).
-+ // note: bdrv_read() need whole blocks, so we round up
-+ pos = qemu_ftell(f);
-+ bdrv_truncate(bs, (pos + BDRV_SECTOR_SIZE) & BDRV_SECTOR_MASK);
-+
-+ qemu_fclose(f);
-+
-+ if (ret < 0) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "Error %d while writing VM state\n", ret);
-+ goto restart;
-+ }
-+out:
-+ if (bs) {
-+ bdrv_delete(bs);
-+ }
-+ return;
-+
-+restart:
-+
-+ snap_state.in_progress = 0;
-+
-+ if (snap_state.saved_vm_running) {
-+ vm_start();
-+ }
-+
-+ goto out;
-+}
-+
-+void qmp_snapshot_end(Error **errp)
-+{
-+ if (!snap_state.in_progress) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "VM snapshot not started\n");
-+ return;
-+ }
-+ snap_state.in_progress = 0;
-+
-+ if (snap_state.saved_vm_running) {
-+ vm_start();
-+ }
-+}
-+
-+void qmp_snapshot_drive(const char *device, const char *name, Error **errp)
-+{
-+ BlockDriverState *bs;
-+ QEMUSnapshotInfo sn1, *sn = &sn1;
-+ int ret;
-+#ifdef _WIN32
-+ struct _timeb tb;
-+#else
-+ struct timeval tv;
-+#endif
-+
-+ if (!snap_state.in_progress) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "VM snapshot not started\n");
-+ return;
-+ }
-+
-+ bs = bdrv_find(device);
-+ if (!bs) {
-+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
-+ return;
-+ }
-+
-+ if (!bdrv_is_inserted(bs)) {
-+ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
-+ return;
-+ }
-+
-+ if (bdrv_is_read_only(bs)) {
-+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
-+ return;
-+ }
-+
-+ if (!bdrv_can_snapshot(bs)) {
-+ error_set(errp, QERR_NOT_SUPPORTED);
-+ return;
-+ }
-+
-+ if (bdrv_snapshot_find(bs, sn, name) >= 0) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "snapshot '%s' already exists", name);
-+ return;
-+ }
-+
-+ sn = &sn1;
-+ memset(sn, 0, sizeof(*sn));
-+
-+#ifdef _WIN32
-+ _ftime(&tb);
-+ sn->date_sec = tb.time;
-+ sn->date_nsec = tb.millitm * 1000000;
-+#else
-+ gettimeofday(&tv, NULL);
-+ sn->date_sec = tv.tv_sec;
-+ sn->date_nsec = tv.tv_usec * 1000;
-+#endif
-+ sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
-+
-+ pstrcpy(sn->name, sizeof(sn->name), name);
-+
-+ sn->vm_state_size = 0; /* do not save state */
-+
-+ ret = bdrv_snapshot_create(bs, sn);
-+ if (ret < 0) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "Error while creating snapshot on '%s'\n", device);
-+ return;
-+ }
-+}
-+
-+void qmp_delete_drive_snapshot(const char *device, const char *name,
-+ Error **errp)
-+{
-+ BlockDriverState *bs;
-+ QEMUSnapshotInfo sn1, *sn = &sn1;
-+ int ret;
-+
-+ bs = bdrv_find(device);
-+ if (!bs) {
-+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
-+ return;
-+ }
-+ if (bdrv_is_read_only(bs)) {
-+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
-+ return;
-+ }
-+
-+ if (!bdrv_can_snapshot(bs)) {
-+ error_set(errp, QERR_NOT_SUPPORTED);
-+ return;
-+ }
-+
-+ if (bdrv_snapshot_find(bs, sn, name) < 0) {
-+ /* return success if snapshot does not exists */
-+ return;
-+ }
-+
-+ ret = bdrv_snapshot_delete(bs, name);
-+ if (ret < 0) {
-+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
-+ "Error while deleting snapshot on '%s'\n", device);
-+ return;
-+ }
-+}
-Index: new/qmp-commands.hx
-===================================================================
---- new.orig/qmp-commands.hx 2012-09-19 12:53:31.000000000 +0200
-+++ new/qmp-commands.hx 2012-09-19 12:54:14.000000000 +0200
-@@ -2514,3 +2514,27 @@
- .args_type = "",
- .mhandler.cmd_new = qmp_marshal_input_query_target,
- },
-+
-+ {
-+ .name = "snapshot-start",
-+ .args_type = "statefile:s?",
-+ .mhandler.cmd_new = qmp_marshal_input_snapshot_start,
-+ },
-+
-+ {
-+ .name = "snapshot-drive",
-+ .args_type = "device:s,name:s",
-+ .mhandler.cmd_new = qmp_marshal_input_snapshot_drive,
-+ },
-+
-+ {
-+ .name = "delete-drive-snapshot",
-+ .args_type = "device:s,name:s",
-+ .mhandler.cmd_new = qmp_marshal_input_delete_drive_snapshot,
-+ },
-+
-+ {
-+ .name = "snapshot-end",
-+ .args_type = "",
-+ .mhandler.cmd_new = qmp_marshal_input_snapshot_end,
-+ },
-Index: new/hmp.c
-===================================================================
---- new.orig/hmp.c 2012-09-19 12:53:31.000000000 +0200
-+++ new/hmp.c 2012-09-19 12:54:14.000000000 +0200
-@@ -1102,3 +1102,40 @@
- qmp_closefd(fdname, &errp);
- hmp_handle_error(mon, &errp);
- }
-+
-+void hmp_snapshot_start(Monitor *mon, const QDict *qdict)
-+{
-+ Error *errp = NULL;
-+ const char *statefile = qdict_get_try_str(qdict, "statefile");
-+
-+ qmp_snapshot_start(statefile != NULL, statefile, &errp);
-+ hmp_handle_error(mon, &errp);
-+}
-+
-+void hmp_snapshot_drive(Monitor *mon, const QDict *qdict)
-+{
-+ Error *errp = NULL;
-+ const char *name = qdict_get_str(qdict, "name");
-+ const char *device = qdict_get_str(qdict, "device");
-+
-+ qmp_snapshot_drive(device, name, &errp);
-+ hmp_handle_error(mon, &errp);
-+}
-+
-+void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict)
-+{
-+ Error *errp = NULL;
-+ const char *name = qdict_get_str(qdict, "name");
-+ const char *device = qdict_get_str(qdict, "device");
-+
-+ qmp_delete_drive_snapshot(device, name, &errp);
-+ hmp_handle_error(mon, &errp);
-+}
-+
-+void hmp_snapshot_end(Monitor *mon, const QDict *qdict)
-+{
-+ Error *errp = NULL;
-+
-+ qmp_snapshot_end(&errp);
-+ hmp_handle_error(mon, &errp);
-+}
-Index: new/hmp.h
-===================================================================
---- new.orig/hmp.h 2012-09-19 12:53:31.000000000 +0200
-+++ new/hmp.h 2012-09-19 12:54:14.000000000 +0200
-@@ -71,5 +71,9 @@
- void hmp_netdev_del(Monitor *mon, const QDict *qdict);
- void hmp_getfd(Monitor *mon, const QDict *qdict);
- void hmp_closefd(Monitor *mon, const QDict *qdict);
-+void hmp_snapshot_start(Monitor *mon, const QDict *qdict);
-+void hmp_snapshot_drive(Monitor *mon, const QDict *qdict);
-+void hmp_delete_drive_snapshot(Monitor *mon, const QDict *qdict);
-+void hmp_snapshot_end(Monitor *mon, const QDict *qdict);
-
- #endif
-Index: new/hmp-commands.hx
-===================================================================
---- new.orig/hmp-commands.hx 2012-09-19 12:53:31.000000000 +0200
-+++ new/hmp-commands.hx 2012-09-19 12:54:14.000000000 +0200
-@@ -1494,3 +1494,35 @@
- STEXI
- @end table
- ETEXI
-+
-+ {
-+ .name = "snapshot-start",
-+ .args_type = "statefile:s?",
-+ .params = "[statefile]",
-+ .help = "Prepare for snapshot and halt VM. Save VM state to statefile.",
-+ .mhandler.cmd = hmp_snapshot_start,
-+ },
-+
-+ {
-+ .name = "snapshot-drive",
-+ .args_type = "device:s,name:s",
-+ .params = "device name",
-+ .help = "Create internal snapshot.",
-+ .mhandler.cmd = hmp_snapshot_drive,
-+ },
-+
-+ {
-+ .name = "delete-drive-snapshot",
-+ .args_type = "device:s,name:s",
-+ .params = "device name",
-+ .help = "Delete internal snapshot.",
-+ .mhandler.cmd = hmp_delete_drive_snapshot,
-+ },
-+
-+ {
-+ .name = "snapshot-end",
-+ .args_type = "",
-+ .params = "",
-+ .help = "Resume VM after snaphot.",
-+ .mhandler.cmd = hmp_snapshot_end,
-+ },
-Index: new/sysemu.h
-===================================================================
---- new.orig/sysemu.h 2012-09-19 12:53:31.000000000 +0200
-+++ new/sysemu.h 2012-09-19 12:54:14.000000000 +0200
-@@ -84,6 +84,7 @@
- int qemu_savevm_state_iterate(QEMUFile *f);
- int qemu_savevm_state_complete(QEMUFile *f);
- void qemu_savevm_state_cancel(QEMUFile *f);
-+int qemu_savevm_state(QEMUFile *f);
- int qemu_loadvm_state(QEMUFile *f);
-
- /* SLIRP */
-Index: new/savevm.c
-===================================================================
---- new.orig/savevm.c 2012-09-19 12:54:11.000000000 +0200
-+++ new/savevm.c 2012-09-19 14:09:29.000000000 +0200
-@@ -407,7 +407,6 @@
-
- static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
- {
-- int ret;
- int64_t maxlen = bdrv_getlength(opaque);
- if (pos > maxlen) {
- return -EIO;
-@@ -1754,7 +1753,7 @@
- }
- }
-
--static int qemu_savevm_state(QEMUFile *f)
-+int qemu_savevm_state(QEMUFile *f)
- {
- int ret;
- MigrationParams params = {