qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH v4 3/8] block: add drive-backup QMP command


From: Kevin Wolf
Subject: Re: [Qemu-devel] [PATCH v4 3/8] block: add drive-backup QMP command
Date: Wed, 22 May 2013 11:53:44 +0200
User-agent: Mutt/1.5.21 (2010-09-15)

Am 16.05.2013 um 10:36 hat Stefan Hajnoczi geschrieben:
> @drive-backup
> 
> Start a point-in-time copy of a block device to a new destination.  The
> status of ongoing drive-backup operations can be checked with
> query-block-jobs where the BlockJobInfo.type field has the value 'backup'.
> The operation can be stopped before it has completed using the
> block-job-cancel command.
> 
> @device: the name of the device whose writes should be mirrored.
> 
> @target: the target of the new image. If the file exists, or if it
>          is a device, the existing file/device will be used as the new
>          destination.  If it does not exist, a new file will be created.
> 
> @format: #optional the format of the new destination, default is to
>          probe if @mode is 'existing', else the format of the source
> 
> @mode: #optional whether and how QEMU should create a new image, default is
>        'absolute-paths'.
> 
> @speed: #optional the maximum speed, in bytes per second
> 
> Returns: nothing on success
>          If @device is not a valid block device, DeviceNotFound
> 
> Since 1.6
> 
> Signed-off-by: Stefan Hajnoczi <address@hidden>
> ---
>  blockdev.c       | 92 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  qapi-schema.json | 32 ++++++++++++++++++++
>  qmp-commands.hx  | 37 +++++++++++++++++++++++
>  3 files changed, 161 insertions(+)
> 
> diff --git a/blockdev.c b/blockdev.c
> index d1ec99a..c7a5e1e 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -1353,6 +1353,98 @@ void qmp_block_commit(const char *device,
>      drive_get_ref(drive_get_by_blockdev(bs));
>  }
>  
> +void qmp_drive_backup(const char *device, const char *target,
> +                      bool has_format, const char *format,
> +                      bool has_mode, enum NewImageMode mode,
> +                      bool has_speed, int64_t speed,
> +                      Error **errp)
> +{
> +    BlockDriverState *bs;
> +    BlockDriverState *target_bs;
> +    BlockDriver *proto_drv;
> +    BlockDriver *drv = NULL;
> +    Error *local_err = NULL;
> +    int flags;
> +    uint64_t size;
> +    int ret;
> +
> +    if (!has_speed) {
> +        speed = 0;
> +    }
> +    if (!has_mode) {
> +        mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
> +    }
> +
> +    bs = bdrv_find(device);
> +    if (!bs) {
> +        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
> +        return;
> +    }
> +
> +    if (!bdrv_is_inserted(bs)) {
> +        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
> +        return;
> +    }
> +
> +    if (!has_format) {
> +        format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : 
> bs->drv->format_name;
> +    }
> +    if (format) {
> +        drv = bdrv_find_format(format);
> +        if (!drv) {
> +            error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
> +            return;
> +        }
> +    }
> +
> +    if (bdrv_in_use(bs)) {
> +        error_set(errp, QERR_DEVICE_IN_USE, device);
> +        return;
> +    }
> +
> +    flags = bs->open_flags | BDRV_O_RDWR;
> +
> +    proto_drv = bdrv_find_protocol(target);
> +    if (!proto_drv) {
> +        error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
> +        return;
> +    }

I see that other block job commands are doing the same, but there are
two things unclear for me about this:

1. Shouldn't bdrv_img_create() and/or bdrv_open() already return an error
   if the protocol can't be found? The error check is the only thing
   that proto_drv is used for.

2. Why do we complain about a wrong _format_ here? If I ask for a qcow2
   image called foo:bar.qcow2, qemu won't find the protocol "foo" and
   complain that qcow2 is an invalid format.

> +
> +    bdrv_get_geometry(bs, &size);
> +    size *= 512;

I was going to suggest BDRV_SECTOR_SIZE at first, but...

Why not use bdrv_getlength() in the first place if you need it in bytes
anyway? As a nice bonus you would get -errno instead of size 0 on
failure.

> +    if (mode != NEW_IMAGE_MODE_EXISTING) {
> +        assert(format && drv);
> +        bdrv_img_create(target, format,
> +                        NULL, NULL, NULL, size, flags, &local_err, false);
> +    }
> +
> +    if (error_is_set(&local_err)) {
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    target_bs = bdrv_new("");
> +    ret = bdrv_open(target_bs, target, NULL, flags, drv);
> +
> +    if (ret < 0) {

Why the empty line between bdrv_open and checking its return value?

> +        bdrv_delete(target_bs);
> +        error_set(errp, QERR_OPEN_FILE_FAILED, target);
> +        return;
> +    }
> +
> +    backup_start(bs, target_bs, speed, block_job_cb, bs, &local_err);
> +    if (local_err != NULL) {
> +        bdrv_delete(target_bs);
> +        error_propagate(errp, local_err);
> +        return;
> +    }
> +
> +    /* Grab a reference so hotplug does not delete the BlockDriverState from
> +     * underneath us.
> +     */
> +    drive_get_ref(drive_get_by_blockdev(bs));
> +}
> +

Kevin



reply via email to

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