Index: new/qapi-schema.json
===================================================================
---- new.orig/qapi-schema.json 2012-09-04 12:52:21.000000000 +0200
-+++ new/qapi-schema.json 2012-09-04 12:53:35.000000000 +0200
-@@ -2493,3 +2493,10 @@
+--- new.orig/qapi-schema.json 2012-09-07 07:41:45.000000000 +0200
++++ new/qapi-schema.json 2012-09-13 09:22:06.000000000 +0200
+@@ -2493,3 +2493,12 @@
# Since: 1.2.0
##
{ 'command': 'query-target', 'returns': 'TargetInfo' }
+
+
-+{ 'command': 'snapshot-start' 'data': { 'statefile': 'str' } }
++{ '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-04 12:52:21.000000000 +0200
-+++ new/qmp.c 2012-09-04 12:53:35.000000000 +0200
-@@ -479,3 +479,145 @@
+--- new.orig/qmp.c 2012-09-07 07:41:45.000000000 +0200
++++ new/qmp.c 2012-09-14 14:06:56.000000000 +0200
+@@ -479,3 +479,224 @@
return arch_query_cpu_definitions(errp);
}
+ int saved_vm_running;
+} snap_state;
+
-+void qmp_snapshot_start(const char *statefile, Error **errp)
++static int block_put_buffer(void *opaque, const uint8_t *buf,
++ int64_t pos, int size)
++{
++ bdrv_pwrite(opaque, pos, buf, size);
++ return size;
++}
++
++static int bdrv_fclose(void *opaque)
+{
++ return bdrv_flush(opaque);
++}
++
++void qmp_snapshot_start(bool has_statefile, const char *statefile, Error **errp)
++{
++ BlockDriverState *bs = NULL;
++ BlockDriver *drv = NULL;
++ int bdrv_oflags = BDRV_O_NOCACHE | BDRV_O_RDWR;
+ QEMUFile *f;
+ int ret;
+
+ "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);
+
-+ f = qemu_fopen(statefile, "wb");
++ 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_ops(bs, block_put_buffer, NULL, bdrv_fclose,
++ NULL, NULL, NULL);
+ if (!f) {
+ error_set(errp, QERR_OPEN_FILE_FAILED, statefile);
-+ return;
++ goto restart;
+ }
+
-+ /* todo: does that save complete state? */
-+ ret = qemu_savevm_state_complete(f);
++ ret = qemu_savevm_state(f);
++
++ bdrv_truncate(bs, qemu_ftell(f)); // ignore errors
++
+ qemu_fclose(f);
++
+ if (ret < 0) {
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+ "Error %d while writing VM state\n", ret);
-+ return;
++ goto restart;
+ }
++end:
++ if (bs)
++ bdrv_delete(bs);
++
++ return;
++
++restart:
++
++ snap_state.in_progress = 0;
++
++ if (snap_state.saved_vm_running) {
++ vm_start();
++ }
++
++ goto end;
+}
+
+void qmp_snapshot_end(Error **errp)
+ 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-04 12:52:21.000000000 +0200
-+++ new/qmp-commands.hx 2012-09-04 12:53:35.000000000 +0200
-@@ -2514,3 +2514,21 @@
+--- new.orig/qmp-commands.hx 2012-09-07 07:41:45.000000000 +0200
++++ new/qmp-commands.hx 2012-09-13 09:30:33.000000000 +0200
+@@ -2514,3 +2514,27 @@
.args_type = "",
.mhandler.cmd_new = qmp_marshal_input_query_target,
},
+
+ {
+ .name = "snapshot-start",
-+ .args_type = "statefile:s",
++ .args_type = "statefile:s?",
+ .mhandler.cmd_new = qmp_marshal_input_snapshot_start,
+ },
+
+ },
+
+ {
++ .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-04 12:52:21.000000000 +0200
-+++ new/hmp.c 2012-09-04 12:53:35.000000000 +0200
-@@ -1102,3 +1102,30 @@
+--- new.orig/hmp.c 2012-09-07 07:41:45.000000000 +0200
++++ new/hmp.c 2012-09-13 09:22:06.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_str(qdict, "statefile");
++ const char *statefile = qdict_get_try_str(qdict, "statefile");
+
-+ qmp_snapshot_start(statefile, &errp);
++ qmp_snapshot_start(statefile != NULL, statefile, &errp);
+ hmp_handle_error(mon, &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;
+}
Index: new/hmp.h
===================================================================
---- new.orig/hmp.h 2012-09-04 12:52:21.000000000 +0200
-+++ new/hmp.h 2012-09-04 12:53:35.000000000 +0200
-@@ -71,5 +71,8 @@
+--- new.orig/hmp.h 2012-09-07 07:41:45.000000000 +0200
++++ new/hmp.h 2012-09-13 09:22:06.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-04 12:52:21.000000000 +0200
-+++ new/hmp-commands.hx 2012-09-04 12:53:35.000000000 +0200
-@@ -1494,3 +1494,28 @@
+--- new.orig/hmp-commands.hx 2012-09-07 07:41:45.000000000 +0200
++++ new/hmp-commands.hx 2012-09-13 09:22:06.000000000 +0200
+@@ -1494,3 +1494,35 @@
STEXI
@end table
ETEXI
+
+ {
+ .name = "snapshot-start",
-+ .args_type = "statefile:s",
-+ .params = "statefile",
++ .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",
+ },
+
+ {
++ .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/savevm.c
+===================================================================
+--- new.orig/savevm.c 2012-09-07 07:41:45.000000000 +0200
++++ new/savevm.c 2012-09-14 11:32:17.000000000 +0200
+@@ -404,7 +404,7 @@
+ return bdrv_flush(opaque);
+ }
+
+-static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
++QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
+ {
+ if (is_writable)
+ return qemu_fopen_ops(bs, block_put_buffer, NULL, bdrv_fclose,
+@@ -1724,7 +1724,7 @@
+ }
+ }
+
+-static int qemu_savevm_state(QEMUFile *f)
++int qemu_savevm_state(QEMUFile *f)
+ {
+ int ret;
+ MigrationParams params = {
+Index: new/sysemu.h
+===================================================================
+--- new.orig/sysemu.h 2012-09-07 07:41:46.000000000 +0200
++++ new/sysemu.h 2012-09-13 09:22:06.000000000 +0200
+@@ -83,6 +83,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/qemu-file.h
+===================================================================
+--- new.orig/qemu-file.h 2012-09-14 11:51:31.000000000 +0200
++++ new/qemu-file.h 2012-09-14 11:51:47.000000000 +0200
+@@ -68,6 +68,7 @@
+ QEMUFile *qemu_fopen(const char *filename, const char *mode);
+ QEMUFile *qemu_fdopen(int fd, const char *mode);
+ QEMUFile *qemu_fopen_socket(int fd);
++QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable);
+ QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
+ QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
+ int qemu_stdio_fd(QEMUFile *f);