qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v4 07/11] qapi: Convert savevm


From: Markus Armbruster
Subject: Re: [Qemu-devel] [PATCH v4 07/11] qapi: Convert savevm
Date: Tue, 09 Apr 2013 18:04:18 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux)

Patch no longer applies.

Pavel Hrdina <address@hidden> writes:

> QMP command "vm-snapshot-save" has also extra optional force parameter
> to specify whether replace existing snapshot or not. It also returns
> information about created snapshot.

Took me a minute to realize that you're comparing it to HMP command
savevm.

> Signed-off-by: Pavel Hrdina <address@hidden>
> ---
>  hmp-commands.hx         |  4 ++--
>  hmp.c                   | 11 +++++++++
>  hmp.h                   |  1 +
>  include/sysemu/sysemu.h |  1 -
>  qapi-schema.json        | 22 ++++++++++++++++++
>  qmp-commands.hx         | 43 ++++++++++++++++++++++++++++++++++
>  savevm.c                | 62 
> +++++++++++++++++++++++++++++++------------------
>  7 files changed, 118 insertions(+), 26 deletions(-)
>
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index 3d98604..382b87d 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -310,7 +310,7 @@ ETEXI
>          .args_type  = "name:s?",
>          .params     = "[tag|id]",
>          .help       = "save a VM snapshot. If no tag or id are provided, a 
> new snapshot is created",
> -        .mhandler.cmd = do_savevm,
> +        .mhandler.cmd = hmp_vm_snapshot_save,
>      },
>  
>  STEXI
> @@ -318,7 +318,7 @@ STEXI
>  @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 tag or ID, it is replaced. More info at
> +a snapshot with the same @var{tag} or @var{id}, it is replaced. More info at
>  @ref{vm_snapshots}.
>  ETEXI
>  

Markup fix squashed in.  Acceptable, because it's really minor.

> diff --git a/hmp.c b/hmp.c
> index dbe9b90..b38b6ce 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -1433,3 +1433,14 @@ void hmp_chardev_remove(Monitor *mon, const QDict 
> *qdict)
>      qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
>      hmp_handle_error(mon, &local_err);
>  }
> +
> +void hmp_vm_snapshot_save(Monitor *mon, const QDict *qdict)
> +{
> +    const char *name = qdict_get_try_str(qdict, "name");
> +    Error *err = NULL;
> +    SnapshotInfo *info = NULL;
> +
> +    info = qmp_vm_snapshot_save(!!name, name, true, true, &err);
> +    qapi_free_SnapshotInfo(info);
> +    hmp_handle_error(mon, &err);
> +}
> diff --git a/hmp.h b/hmp.h
> index 80e8b41..1bb8590 100644
> --- a/hmp.h
> +++ b/hmp.h
> @@ -86,5 +86,6 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
>  void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
>  void hmp_chardev_add(Monitor *mon, const QDict *qdict);
>  void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
> +void hmp_vm_snapshot_save(Monitor *mon, const QDict *qdict);
>  
>  #endif
> diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
> index 9e6a4a9..87b82d7 100644
> --- a/include/sysemu/sysemu.h
> +++ b/include/sysemu/sysemu.h
> @@ -65,7 +65,6 @@ void qemu_remove_exit_notifier(Notifier *notify);
>  
>  void qemu_add_machine_init_done_notifier(Notifier *notify);
>  
> -void do_savevm(Monitor *mon, const QDict *qdict);
>  int load_vmstate(const char *name);
>  void do_delvm(Monitor *mon, const QDict *qdict);
>  void do_info_snapshots(Monitor *mon, const QDict *qdict);
> diff --git a/qapi-schema.json b/qapi-schema.json
> index f629a24..cbb73d9 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -3453,3 +3453,25 @@
>  # Since: 1.5
>  ##
>  { 'command': 'query-tpm', 'returns': ['TPMInfo'] }
> +
> +##
> +# @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, the force argument needs to be true to replace it.

"tag or id"?

HMP command savevm's argument is matched against both QEMUSnapshotInfo
member id_str (a.k.a. id) and name (a.k.a. tag).  Do we really want that
kind of overloading in QMP?  Shouldn't we make it tag vs. id explicit
there?

> +#
> +# 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

Should we make this mandatory?  We have to keep the argument optional in
HMP, but that needn't concern us here.

> +#
> +# @force: #optional specify whether existing snapshot is replaced or not,
> +#         default is false
> +#
> +# Returns: SnapshotInfo on success
> +#
> +# Since: 1.5
> +##
> +{ 'command': 'vm-snapshot-save', 'data': {'*name': 'str', '*force': 'bool'},
> +  'returns': 'SnapshotInfo' }
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index 1e0e11e..119e7a5 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -1445,6 +1445,49 @@ Example:
>  
>  EQMP
>      {
> +        .name       = "vm-snapshot-save",
> +        .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
> +    },
> +
> +SQMP
> +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, 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)
> +
> +- "force": specify whether existing snapshot is replaced or not,
> +           default is false (json-bool, optional)
> +
> +Example:
> +
> +-> { "execute": "vm-snapshot-save", "arguments": { "name": "my_snapshot" } }
> +<- {
> +      "return": {
> +         "id": "1",
> +         "name": "my_snapshot",
> +         "date-sec": 1364480534,
> +         "date-nsec": 978215000,
> +         "vm-clock-sec": 5,
> +         "vm-clock-nsec": 153620449,
> +         "vm-state-size": 5709953
> +      }
> +   }
> +
> +EQMP
> +    {
>          .name       = "qmp_capabilities",
>          .args_type  = "",
>          .params     = "",
> diff --git a/savevm.c b/savevm.c
> index 3c1ac9e..7b127eb 100644
> --- a/savevm.c
> +++ b/savevm.c
> @@ -2249,17 +2249,18 @@ static int del_existing_snapshots(const char *name, 
> Error **errp)
>      return 0;
>  }
>  
> -void do_savevm(Monitor *mon, const QDict *qdict)
> +SnapshotInfo *qmp_vm_snapshot_save(bool has_name, const char *name,
> +                                   bool has_force, bool force, Error **errp)
>  {
>      BlockDriverState *bs, *bs1;
>      QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
> +    SnapshotInfo *info = NULL;
>      int ret;
>      QEMUFile *f;
>      int saved_vm_running;
>      uint64_t vm_state_size;
>      qemu_timeval tv;
>      struct tm tm;
> -    const char *name = qdict_get_try_str(qdict, "name");
>      Error *local_err = NULL;
>  
>      /* Verify if there is a device that doesn't support snapshots and is 
> writable */
> @@ -2271,16 +2272,16 @@ void do_savevm(Monitor *mon, const QDict *qdict)
>          }
>  
>          if (!bdrv_can_snapshot(bs)) {
> -            monitor_printf(mon, "Device '%s' is writable but does not 
> support snapshots.\n",
> -                               bdrv_get_device_name(bs));
> -            return;
> +            error_setg(errp, "device '%s' is writable but does not support "
> +                       "snapshots", bdrv_get_device_name(bs));
> +            return NULL;

Any particular reason for de-capitalizing "Device"?  More of the same below.

>          }
>      }
>  
>      bs = bdrv_snapshots();
>      if (!bs) {
> -        monitor_printf(mon, "No block device can accept snapshots\n");
> -        return;
> +        error_setg(errp, "no block device can accept snapshots");
> +        return NULL;
>      }
>  
>      saved_vm_running = runstate_is_running();
> @@ -2294,11 +2295,23 @@ void do_savevm(Monitor *mon, const QDict *qdict)
>      sn->date_nsec = tv.tv_usec * 1000;
>      sn->vm_clock_nsec = qemu_get_clock_ns(vm_clock);
>  
> -    if (name) {
> +    if (has_name) {
>          ret = bdrv_snapshot_find(bs, old_sn, name);
>          if (ret >= 0) {
> -            pstrcpy(sn->name, sizeof(sn->name), old_sn->name);
> -            pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);
> +            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);
> +
> +                /* Delete old snapshots of the same name */
> +                if (del_existing_snapshots(name, &local_err) < 0) {
> +                    error_propagate(errp, local_err);
> +                    goto the_end;
> +                }
> +            } else {
> +                error_setg(errp, "snapshot '%s' exists, for override use "
> +                           "'force' parameter", name);
> +                goto the_end;
> +            }
>          } else {
>              pstrcpy(sn->name, sizeof(sn->name), name);
>          }
       } else {
           /* cast below needed for OpenBSD where tv_sec is still 'long' */
           localtime_r((const time_t *)&tv.tv_sec, &tm);
> @@ -2308,24 +2321,17 @@ void do_savevm(Monitor *mon, const QDict *qdict)
>          strftime(sn->name, sizeof(sn->name), "vm-%Y%m%d%H%M%S", &tm);

Interestingly, we do not check whether this auto-generated name already
exists.  Not your fault, but could use fixing.

>      }
>  
> -    /* Delete old snapshots of the same name */
> -    if (name && del_existing_snapshots(name, &local_err) < 0) {
> -        monitor_printf(mon, "%s\n", error_get_pretty(local_err));
> -        error_free(local_err);
> -        goto the_end;
> -    }
> -

Your code motion adds two conditions for calling
del_existing_snapshots():

1. has_force && force: feature.  I guess I'd add the feature in a
separate patch, to keep this one as simple as possible.  Your choice.

2. bdrv_snapshot_find() succeeds.  Care to explain why this one's
correct?

>      /* save the VM state */
>      f = qemu_fopen_bdrv(bs, 1);
>      if (!f) {
> -        monitor_printf(mon, "Could not open VM state file\n");
> +        error_setg(errp, "failed to open '%s' file", 
> bdrv_get_device_name(bs));
>          goto the_end;
>      }
> -    ret = qemu_savevm_state(f, NULL);
> +    ret = qemu_savevm_state(f, &local_err);
>      vm_state_size = qemu_ftell(f);
>      qemu_fclose(f);
>      if (ret < 0) {
> -        monitor_printf(mon, "Error %d while writing VM\n", ret);
> +        error_propagate(errp, local_err);
>          goto the_end;
>      }
>  
> @@ -2336,17 +2342,27 @@ void do_savevm(Monitor *mon, const QDict *qdict)
>          if (bdrv_can_snapshot(bs1)) {
>              /* Write VM state size only to the image that contains the state 
> */
>              sn->vm_state_size = (bs == bs1 ? vm_state_size : 0);
> -            ret = bdrv_snapshot_create(bs1, sn, NULL);
> +            ret = bdrv_snapshot_create(bs1, sn, &local_err);
>              if (ret < 0) {
> -                monitor_printf(mon, "Error while creating snapshot on 
> '%s'\n",
> -                               bdrv_get_device_name(bs1));
> +                error_propagate(errp, local_err);

When we go through this failure...

>              }
>          }
>      }
>  
> +    info = g_malloc0(sizeof(SnapshotInfo));
> +    info->id = g_strdup(sn->id_str);
> +    info->name = g_strdup(sn->name);
> +    info->date_nsec = sn->date_nsec;
> +    info->date_sec = sn->date_sec;
> +    info->vm_state_size = vm_state_size;
> +    info->vm_clock_nsec = sn->vm_clock_nsec % 1000000000;
> +    info->vm_clock_sec = sn->vm_clock_nsec / 1000000000;
> +
>   the_end:
>      if (saved_vm_running)
>          vm_start();
> +
> +    return info;

... we return both info and an Error.  Stupid question: is that okay?

>  }
>  
>  void qmp_xen_save_devices_state(const char *filename, Error **errp)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]