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