qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH v4 10/10] block: add QAPI command to allow live


From: Benoît Canet
Subject: Re: [Qemu-devel] [PATCH v4 10/10] block: add QAPI command to allow live backing file change
Date: Thu, 5 Jun 2014 13:53:55 +0200
User-agent: Mutt/1.5.21 (2010-09-15)

The Wednesday 04 Jun 2014 à 09:51:12 (-0400), Jeff Cody wrote :
> This allows a user to make a live change to the backing file recorded in
> an open image.
> 
> The image file to modify can be specified 2 ways:
> 
> 1) image filename
> 2) image node-name
> 
> Note: this does not cause the backing file itself to be reopened; it
> merely changes the backing filename in the image file structure, and
> in internal BDS structures.
> 
> It is the responsibility of the user to pass a filename string that
> can be resolved when the image chain is reopened, and the filename
> string is not validated.
> 
> A good analogy for this command is that it is a live version of
> 'qemu-img rebase -u', with respect to changing the backing file string.

If this command was triggering the reopen of the file and drive-mirror was 
accepting
a node-name argument we would have a way to manage tiered storage.

For example we could move one of the backing file in the chain from harddisk to
SSD by mirroring it and swapping the new one in place.

Best regards

Benoît

> 
> Signed-off-by: Jeff Cody <address@hidden>
> ---
>  blockdev.c       | 102 
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  qapi-schema.json |  60 ++++++++++++++++++++++++++++++++
>  qmp-commands.hx  |  74 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 236 insertions(+)
> 
> diff --git a/blockdev.c b/blockdev.c
> index 23a76eb..61150b4 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -2408,6 +2408,108 @@ void qmp_block_job_complete(const char *device, Error 
> **errp)
>      block_job_complete(job, errp);
>  }
>  
> +void qmp_change_backing_file(const char *device,
> +                             bool has_image, const char *image,
> +                             bool has_image_node_name,
> +                             const char *image_node_name,
> +                             const char *backing_file,
> +                             Error **errp)
> +{
> +    BlockDriverState *bs = NULL;
> +    BlockDriverState *image_bs = NULL;
> +    Error *local_err = NULL;
> +    bool ro;
> +    int open_flags;
> +    int ret;
> +
> +    /* validate argument combinations */
> +    if (has_image && has_image_node_name) {
> +        error_setg(errp, "'image' and 'image-node-name' "
> +                         "are mutually exclusive");
> +        return;
> +    }
> +
> +    /* find the top layer BDS of the chain */
> +    bs = bdrv_find(device);
> +    if (!bs) {
> +        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
> +        return;
> +    }
> +
> +    if (has_image_node_name) {
> +        image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err);
> +        if (local_err) {
> +            error_propagate(errp, local_err);
> +            return;
> +        }
> +    }
> +
> +    if (has_image) {
> +        if (!strcmp(bs->filename, image)) {
> +            image_bs = bs;
> +        } else {
> +            image_bs = bdrv_find_backing_image(bs, image);
> +        }
> +    }
> +
> +    if (!has_image && !has_image_node_name) {
> +        image_bs = bs;
> +    }
> +
> +    if (!image_bs) {
> +        error_setg(errp, "image file not found");
> +        return;
> +    }
> +
> +    if (bdrv_find_base(image_bs) == image_bs) {
> +        error_setg(errp, "not allowing backing file change on an image "
> +                         "without a backing file");
> +        return;
> +    }
> +
> +    /* even though we are not necessarily operating on bs, we need it to
> +     * determine if block ops are currently prohibited on the chain */
> +    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
> +        return;
> +    }
> +
> +    /* final sanity check */
> +    if (!bdrv_chain_contains(bs, image_bs)) {
> +        error_setg(errp, "'%s' and image file are not in the same chain",
> +                   device);
> +        return;
> +    }
> +
> +    /* if not r/w, reopen to make r/w */
> +    open_flags = image_bs->open_flags;
> +    ro = bdrv_is_read_only(image_bs);
> +
> +    if (ro) {
> +        bdrv_reopen(image_bs, open_flags | BDRV_O_RDWR, &local_err);
> +        if (local_err) {
> +            error_propagate(errp, local_err);
> +            return;
> +        }
> +    }
> +
> +    ret = bdrv_change_backing_file(image_bs, backing_file,
> +                               image_bs->drv ? image_bs->drv->format_name : 
> "");
> +
> +    if (ret < 0) {
> +        error_setg_errno(errp, -ret, "Could not change backing file to '%s'",
> +                         backing_file);
> +        /* don't exit here, so we can try to restore open flags if
> +         * appropriate */
> +    }
> +
> +    if (ro) {
> +        bdrv_reopen(image_bs, open_flags, &local_err);
> +        if (local_err) {
> +            error_propagate(errp, local_err); /* will preserve prior errp */
> +        }
> +    }
> +}
> +
>  void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
>  {
>      QmpOutputVisitor *ov = qmp_output_visitor_new();
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 3400561..e57396b 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -2092,6 +2092,66 @@
>    'returns': 'str' }
>  
>  ##
> +# @change-backing-file
> +#
> +# Change the backing file in the image file metadata.  This does not cause 
> QEMU
> +# to reopen the image file to reparse the backing filename (it may, however,
> +# perform a reopen to change permissions from r/o -> r/w -> r/o, if needed).
> +# The new backing file string is written into the image file metadata, and 
> the
> +# QEMU internal strings are updated.
> +#
> +# The image file to perform the operation on can be specified by two 
> different
> +# methods:
> +#
> +#  Method 1: Supply the device name (e.g. 'virtio0'), and optionally the 
> image
> +#            filename.  This would use arguments @device and @image.
> +#
> +#  Method 2: Supply the device name, and the node-name of the image to 
> modify,
> +#            via @image-node-name.
> +#
> +# Arguments @image and @image-node-name are mutually exclusive.
> +#
> +# Method 1 interface
> +#---------------------
> +# @image:          #optional The file name of the image to modify.  If 
> omitted,
> +#                            and @image-node-name is not supplied, then the
> +#                            default is the active layer of the chain 
> described
> +#                            by @device.
> +#
> +# Method 2 interface
> +#---------------------
> +# @image-node-name #optional The name of the block driver state node of the
> +#                            image to modify.  The @device argumen is used to
> +#                            verify @image-node-name is in the chain 
> described
> +#                            by @device.
> +#
> +# Common arguments
> +#---------------------
> +# @device:          The name of the device.
> +#
> +# @backing-file:    The string to write as the backing file.  This string is
> +#                   not validated, so care should be taken when specifying
> +#                   the string or the image chain may not be able to be
> +#                   reopened again.
> +#
> +#                   If a pathname string is such that it cannot be
> +#                   resolved by QEMU, that means that subsequent QMP or
> +#                   HMP commands must use node-names for the image in
> +#                   question, as filename lookup methods will fail.
> +#
> +#
> +# Returns: Nothing on success
> +#          If @device does not exist or cannot be determined, DeviceNotFound
> +#          If @image is specified, but not @device, GenericError
> +#          If both @image and @image-node-name are specified, GenericError
> +#
> +# Since: 2.1
> +##
> +{ 'command': 'change-backing-file',
> +  'data': { 'device': 'str', '*image': 'str', '*image-node-name': 'str',
> +            'backing-file': 'str' } }
> +
> +##
>  # @block-commit
>  #
>  # Live commit of data from overlay image nodes into backing nodes - i.e.,
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index 69d29ae..a17d3d5 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -1438,6 +1438,80 @@ Example:
>  EQMP
>  
>      {
> +        .name       = "change-backing-file",
> +        .args_type  = "device:s,image:s?,image-node-name:s?,backing-file:s",
> +        .mhandler.cmd_new = qmp_marshal_input_change_backing_file,
> +    },
> +
> +SQMP
> +change-backing-file
> +-------------------
> +Since: 2.1
> +
> +Change the backing file in the image file metadata.  This does not cause QEMU
> +to reopen the image file to reparse the backing filename (it may, however,
> +perform a reopen to change permissions from r/o -> r/w -> r/o, if needed).
> +The new backing file string is written into the image file metadata, and the
> +QEMU internal strings are updated.
> +
> +The image file to perform the operation on can be specified by two different
> +methods:
> +
> + Method 1: Supply the device name (e.g. 'virtio0'), and optionally the image
> +           filename.  This would use arguments "device" and "image".
> +
> + Method 2: Supply the device name, and the node-name of the image to modify,
> +           via "image-node-name".
> +
> +Arguments:
> +
> +Arguments "image" or "image-node-name" are mutually exclusive.
> +
> +
> +Method 1 interface
> +--------------------
> +- "image":              The file name of the image to modify.  If omitted,
> +                        and "image-node-name" is not supplied, then the
> +                        default is the active layer of the chain described
> +                        by device.
> +                        (json-string, optional)
> +
> +
> +Method 2 interface
> +--------------------
> +- "image-node-name":    The name of the block driver state node of the
> +                        image to modify.  The "device" is argument is used to
> +                        verify "image-node-name" is in the chain described by
> +                        "device".
> +                        (json-string, optional)
> +
> +
> +Common arguments
> +--------------------
> +- "device":             The name of the device.
> +                        (json-string)
> +
> +- "backing-file":       The string to write as the backing file.  This 
> string is
> +                        not validated, so care should be taken when 
> specifying
> +                        the string or the image chain may not be able to be
> +                        reopened again.
> +                        (json-string)
> +
> +                        If a pathname string is such that it cannot be
> +                        resolved by QEMU, that means that subsequent QMP or
> +                        HMP commands must use node-names for the image in
> +                        question, as filename lookup methods will fail.
> +
> +
> +Returns: Nothing on success
> +         If "device" does not exist or cannot be determined, DeviceNotFound
> +         If "image" is specified, but not "device, GenericError
> +         If both "image" and "image-node-name" are specified, GenericError
> +
> +
> +EQMP
> +
> +    {
>          .name       = "balloon",
>          .args_type  = "value:M",
>          .mhandler.cmd_new = qmp_marshal_input_balloon,
> -- 
> 1.9.3
> 



reply via email to

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