HMP command "savevm" now takes extra optional force parameter to specifi whether replace existing snapshot or not.
QMP command "vm-snapshot-save" has also extra optional force parameter and name parameter isn't optional anymore. Signed-off-by: Pavel Hrdina <phrd...@redhat.com> --- hmp-commands.hx | 16 ++++++++-------- hmp.c | 25 ++++++++++++++++++++++++- qapi-schema.json | 9 ++++++--- qmp-commands.hx | 15 +++++++++------ savevm.c | 34 +++++++++++++--------------------- 5 files changed, 60 insertions(+), 39 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 0b3d783..04cee55 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -307,19 +307,19 @@ ETEXI { .name = "savevm", - .args_type = "name:s?", - .params = "[tag|id]", - .help = "save a VM snapshot. If no tag or id are provided, a new snapshot is created", + .args_type = "force:-b,name:s?,", + .params = "[-f] [tag|id]", + .help = "save a VM snapshot. To replace existing snapshot use force flag.", .mhandler.cmd = hmp_vm_snapshot_save, }, STEXI -@item savevm [@var{tag}|@var{id}] +@item savevm [@var{-f}] [@var{tag}|@var{id}] @findex savevm -Create a snapshot of the whole virtual machine. If @var{tag} is -provided, it is used as human readable identifier. If there is already -a snapshot with the same @var{tag} or @var{id}, it is replaced. More info at -@ref{vm_snapshots}. +Create a snapshot of the whole virtual machine. Paramtere "name" is optional. +If @var{tag} is provided, it is used as human readable identifier. If there is +already a snapshot with the same @var{tag} or @var{id}, @var{-f} flag needs to +be specified. More info at @ref{vm_snapshots}. ETEXI { diff --git a/hmp.c b/hmp.c index 1983210..f5e7334 100644 --- a/hmp.c +++ b/hmp.c @@ -1372,9 +1372,32 @@ void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict) void hmp_vm_snapshot_save(Monitor *mon, const QDict *qdict) { const char *name = qdict_get_try_str(qdict, "name"); + char new_name[256]; + bool force = qdict_get_try_bool(qdict, "force", 0); Error *err = NULL; +#ifdef _WIN32 + struct _timeb tb; + struct tm *ptm; +#else + struct timeval tv; + struct tm tm; +#endif + + if (!name) { +#ifdef _WIN32 + time_t t = tb.time; + ptm = localtime(&t); + strftime(new_name, sizeof(new_name), "vm-%Y%m%d%H%M%S", ptm); +#else + /* cast below needed for OpenBSD where tv_sec is still 'long' */ + localtime_r((const time_t *)&tv.tv_sec, &tm); + strftime(new_name, sizeof(new_name), "vm-%Y%m%d%H%M%S", &tm); +#endif + } else { + pstrcpy(new_name, sizeof(new_name), name); + } - qmp_vm_snapshot_save(!!name, name, &err); + qmp_vm_snapshot_save(new_name, !!force, force, &err); hmp_handle_error(mon, &err); } diff --git a/qapi-schema.json b/qapi-schema.json index a8742a1..452b52b 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3036,19 +3036,22 @@ # # Create a snapshot of the whole virtual machine. If tag is provided as @name, # it is used as human readable identifier. If there is already a snapshot -# with the same tag or ID, it is replaced. +# with the same tag or id, the force argument needs to be true to replace it. # # The VM is automatically stopped and resumed and saving a snapshot can take # a long time. # -# @name: #optional tag of new snapshot or tag|id of existing snapshot +# @name: tag of new snapshot or tag|id of existing snapshot +# +# @force: #optional specify whether existing snapshot is replaced or not, +# default is false # # Returns: Nothing on success # If an error occurs, GenericError with error message # # Since: 1.4.0 ## -{ 'command': 'vm-snapshot-save', 'data': {'*name': 'str'} } +{ 'command': 'vm-snapshot-save', 'data': {'name': 'str', '*force': 'bool'} } ## # @vm-snapshot-load: diff --git a/qmp-commands.hx b/qmp-commands.hx index f839c40..077276e 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1349,9 +1349,9 @@ Example: EQMP { .name = "vm-snapshot-save", - .args_type = "name:s?", - .params = "name", - .help = "save a VM snapshot. If no tag or id are provided, a new snapshot is created", + .args_type = "name:s,force:b?", + .params = "name [force]", + .help = "save a VM snapshot. To replace existing snapshot use force parameter.", .mhandler.cmd_new = qmp_marshal_input_vm_snapshot_save }, @@ -1360,15 +1360,18 @@ vm-snapshot-save ------ Create a snapshot of the whole virtual machine. If tag is provided as name, -it is used as human readable identifier. If there is already a snapshot -with the same tag or id, it is replaced. +it is used as human readable identifier. If there is already a snapshot with +the same tag, the force argument needs to be true to replace it. The VM is automatically stopped and resumed and saving a snapshot can take a long time. Arguments: -- "name": tag of new snapshot or tag|id of existing snapshot (json-string, optional) +- "name": tag of new snapshot or tag|id of existing snapshot (json-string) + +- "force": specify whether existing snapshot is replaced or not, + default is false (json-bool, optional) Example: diff --git a/savevm.c b/savevm.c index 36ccc46..effb4df 100644 --- a/savevm.c +++ b/savevm.c @@ -2141,7 +2141,7 @@ static int del_existing_snapshots(const char *name, return 0; } -void qmp_vm_snapshot_save(bool has_name, const char *name, Error **errp) +void qmp_vm_snapshot_save(const char *name, bool has_force, bool force, Error **errp) { BlockDriverState *bs, *bs1; QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1; @@ -2151,10 +2151,8 @@ void qmp_vm_snapshot_save(bool has_name, const char *name, Error **errp) uint64_t vm_state_size; #ifdef _WIN32 struct _timeb tb; - struct tm *ptm; #else struct timeval tv; - struct tm tm; #endif /* Verify if there is a device that doesn't support snapshots and is writable */ @@ -2195,29 +2193,23 @@ void qmp_vm_snapshot_save(bool has_name, const char *name, Error **errp) #endif sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock); - if (has_name) { - ret = bdrv_snapshot_find(bs, old_sn, name, NULL); - if (ret >= 0) { + ret = bdrv_snapshot_find(bs, old_sn, name, NULL); + if (ret >= 0) { + if (has_force && force) { pstrcpy(sn->name, sizeof(sn->name), old_sn->name); pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str); + + del_existing_snapshots(name, errp); + if (error_is_set(errp)) { + goto the_end; + } } else { - pstrcpy(sn->name, sizeof(sn->name), name); + error_setg(errp, "Snapshot '%s' exist. For override specify " + "'force=yes'.", name); + goto the_end; } } else { -#ifdef _WIN32 - time_t t = tb.time; - ptm = localtime(&t); - strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", ptm); -#else - /* cast below needed for OpenBSD where tv_sec is still 'long' */ - localtime_r((const time_t *)&tv.tv_sec, &tm); - strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", &tm); -#endif - } - - /* Delete old snapshots of the same name */ - if (has_name && del_existing_snapshots(name, errp) < 0) { - goto the_end; + pstrcpy(sn->name, sizeof(sn->name), name); } /* save the VM state */ -- 1.8.0.2