Signed-off-by: Pavel Hrdina <phrd...@redhat.com>
---
 hmp-commands.hx  |  4 ++--
 hmp.c            |  9 ++++++++
 hmp.h            |  1 +
 monitor.c        | 12 -----------
 qapi-schema.json | 15 +++++++++++++
 qmp-commands.hx  | 25 ++++++++++++++++++++++
 savevm.c         | 65 ++++++++++++++++++++++++++++----------------------------
 sysemu.h         |  1 -
 vl.c             |  6 +++++-
 9 files changed, 90 insertions(+), 48 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 3b781f7..5194f15 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -327,14 +327,14 @@ ETEXI
         .args_type  = "name:s",
         .params     = "tag|id",
         .help       = "restore a VM snapshot from its tag or id",
-        .mhandler.cmd = do_loadvm,
+        .mhandler.cmd = hmp_vm_snapshot_load,
     },
 
 STEXI
 @item loadvm @var{tag}|@var{id}
 @findex loadvm
 Set the whole virtual machine to the snapshot identified by the tag
-@var{tag} or the unique snapshot ID @var{id}.
+@var{tag} or the unique snapshot ID @var{id}. It must be snapshot of whole VM.
 ETEXI
 
     {
diff --git a/hmp.c b/hmp.c
index 2dbdcbf..29f60a8 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1344,3 +1344,12 @@ void hmp_vm_snapshot_save(Monitor *mon, const QDict 
*qdict)
     qmp_vm_snapshot_save(!!name, name, &err);
     hmp_handle_error(mon, &err);
 }
+
+void hmp_vm_snapshot_load(Monitor *mon, const QDict *qdict)
+{
+    const char *name = qdict_get_str(qdict, "name");
+    Error *err = NULL;
+
+    qmp_vm_snapshot_load(name, &err);
+    hmp_handle_error(mon, &err);
+}
diff --git a/hmp.h b/hmp.h
index 0bd7e47..3f61b32 100644
--- a/hmp.h
+++ b/hmp.h
@@ -81,5 +81,6 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
 void hmp_vm_snapshot_save(Monitor *mon, const QDict *qdict);
+void hmp_vm_snapshot_load(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/monitor.c b/monitor.c
index c0e32d6..b8abff2 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2065,18 +2065,6 @@ void qmp_closefd(const char *fdname, Error **errp)
     error_set(errp, QERR_FD_NOT_FOUND, fdname);
 }
 
-static void do_loadvm(Monitor *mon, const QDict *qdict)
-{
-    int saved_vm_running  = runstate_is_running();
-    const char *name = qdict_get_str(qdict, "name");
-
-    vm_stop(RUN_STATE_RESTORE_VM);
-
-    if (load_vmstate(name) == 0 && saved_vm_running) {
-        vm_start();
-    }
-}
-
 int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
 {
     mon_fd_t *monfd;
diff --git a/qapi-schema.json b/qapi-schema.json
index 08543d2..f8ab4d9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3036,3 +3036,18 @@
 # Since: 1.4.0
 ##
 { 'command': 'vm-snapshot-save', 'data': {'*name': 'str'} }
+
+##
+# @vm-snapshot-load:
+#
+# Set the whole virtual machine to the snapshot identified by the tag
+# or the unique snapshot id. It must be snapshot of whole VM.
+#
+# @name: tag|id of existing snapshot
+#
+# Returns: Nothing on success
+#          If an error occurs, GenericError with error message
+#
+# Since: 1.3
+##
+{ 'command': 'vm-snapshot-load', 'data': {'name': 'str'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 58e2d0a..62da843 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1377,6 +1377,31 @@ Example:
 
 EQMP
     {
+        .name       = "vm-snapshot-load",
+        .args_type  = "name:s",
+        .params     = "name",
+        .help       = "restore a VM snapshot from its tag or id",
+        .mhandler.cmd_new = qmp_marshal_input_vm_snapshot_load
+    },
+
+SQMP
+vm-snapshot-load
+------
+
+Set the whole virtual machine to the snapshot identified by the tag
+or the unique snapshot id. It must be snapshot of whole VM.
+
+Arguments:
+
+- "name": tag|id of existing snapshot (json-string)
+
+Example:
+
+-> { "execute": "vm-snapshot-load", "arguments": { "name": "my_snapshot" } }
+<- { "return": {} }
+
+EQMP
+    {
         .name       = "qmp_capabilities",
         .args_type  = "",
         .params     = "",
diff --git a/savevm.c b/savevm.c
index 91120c4..636cca8 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2081,7 +2081,7 @@ out:
     if (ret == 0) {
         ret = qemu_file_get_error(f);
         if (ret < 0) {
-            error_set(errp, QERR_GENERIC_ERROR, ret);
+            error_setg(errp, "%s", strerror(errno));
         }
     }
 
@@ -2274,27 +2274,28 @@ void qmp_xen_save_devices_state(const char *filename, 
Error **errp)
         vm_start();
 }
 
-int load_vmstate(const char *name)
+void qmp_vm_snapshot_load(const char *name, Error **errp)
 {
     BlockDriverState *bs, *bs_vm_state;
     QEMUSnapshotInfo sn;
     QEMUFile *f;
-    int ret;
+    int ret, saved_vm_running;
 
     bs_vm_state = bdrv_snapshots();
     if (!bs_vm_state) {
-        error_report("No block device supports snapshots");
-        return -ENOTSUP;
+        error_setg(errp, "No block device supports snapshots.");
+        return;
     }
 
     /* Don't even try to load empty VM states */
-    ret = bdrv_snapshot_find(bs_vm_state, &sn, name, NULL);
-    if (ret < 0) {
-        return ret;
-    } else if (sn.vm_state_size == 0) {
-        error_report("This is a disk-only snapshot. Revert to it offline "
-            "using qemu-img.");
-        return -EINVAL;
+    bdrv_snapshot_find(bs_vm_state, &sn, name, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+    if (sn.vm_state_size == 0) {
+        error_setg(errp, "This is a disk-only snapshot. Revert to it offline "
+                   "using qemu-img.");
+        return;
     }
 
     /* Verify if there is any device that doesn't support snapshots and is
@@ -2307,30 +2308,29 @@ int load_vmstate(const char *name)
         }
 
         if (!bdrv_can_snapshot(bs)) {
-            error_report("Device '%s' is writable but does not support 
snapshots.",
-                               bdrv_get_device_name(bs));
-            return -ENOTSUP;
+            error_setg(errp, "Device '%s' is writable but does not support "
+                       "snapshots.", bdrv_get_device_name(bs));
+            return;
         }
 
-        ret = bdrv_snapshot_find(bs, &sn, name, NULL);
-        if (ret < 0) {
-            error_report("Device '%s' does not have the requested snapshot 
'%s'",
-                           bdrv_get_device_name(bs), name);
-            return ret;
+        bdrv_snapshot_find(bs, &sn, name, errp);
+        if (error_is_set(errp)) {
+            return;
         }
     }
 
+    saved_vm_running = runstate_is_running();
+    vm_stop(RUN_STATE_RESTORE_VM);
+
     /* Flush all IO requests so they don't interfere with the new state.  */
     bdrv_drain_all();
 
     bs = NULL;
     while ((bs = bdrv_next(bs))) {
         if (bdrv_can_snapshot(bs)) {
-            ret = bdrv_snapshot_goto(bs, name, NULL);
-            if (ret < 0) {
-                error_report("Error %d while activating snapshot '%s' on '%s'",
-                             ret, name, bdrv_get_device_name(bs));
-                return ret;
+            ret = bdrv_snapshot_goto(bs, name, errp);
+            if (error_is_set(errp)) {
+                return;
             }
         }
     }
@@ -2338,20 +2338,21 @@ int load_vmstate(const char *name)
     /* restore the VM state */
     f = qemu_fopen_bdrv(bs_vm_state, 0);
     if (!f) {
-        error_report("Could not open VM state file");
-        return -EINVAL;
+        error_setg(errp, "Failed to open '%s' file.", 
bdrv_get_device_name(bs));
+        return;
     }
 
     qemu_system_reset(VMRESET_SILENT);
-    ret = qemu_loadvm_state(f, NULL);
+    qemu_loadvm_state(f, errp);
 
     qemu_fclose(f);
-    if (ret < 0) {
-        error_report("Error %d while loading VM state", ret);
-        return ret;
+    if (error_is_set(errp)) {
+        return;
     }
 
-    return 0;
+    if (saved_vm_running) {
+        vm_start();
+    }
 }
 
 void do_delvm(Monitor *mon, const QDict *qdict)
diff --git a/sysemu.h b/sysemu.h
index 96b4879..83fc17e 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -65,7 +65,6 @@ void qemu_remove_exit_notifier(Notifier *notify);
 
 void qemu_add_machine_init_done_notifier(Notifier *notify);
 
-int load_vmstate(const char *name);
 void do_delvm(Monitor *mon, const QDict *qdict);
 void do_info_snapshots(Monitor *mon);
 
diff --git a/vl.c b/vl.c
index a3ab384..4774092 100644
--- a/vl.c
+++ b/vl.c
@@ -3976,8 +3976,12 @@ int main(int argc, char **argv, char **envp)
 
     qemu_system_reset(VMRESET_SILENT);
     if (loadvm) {
-        if (load_vmstate(loadvm) < 0) {
+        Error *errp = NULL;
+        qmp_vm_snapshot_load(loadvm, &errp);
+
+        if (error_is_set(&errp)) {
             autostart = 0;
+            handle_error(&errp);
         }
     }
 
-- 
1.8.0.2


Reply via email to