From: Luiz Capitulino <lcapitulino@redhat.com>
To: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Cc: Kevin Wolf <kwolf@redhat.com>,
Marcelo Tosatti <mtosatti@redhat.com>,
qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v4 06/15] qmp: add block_stream command
Date: Wed, 11 Jan 2012 15:23:47 -0200 [thread overview]
Message-ID: <20120111152347.367d00c2@doriath> (raw)
In-Reply-To: <1325858501-25741-7-git-send-email-stefanha@linux.vnet.ibm.com>
On Fri, 6 Jan 2012 14:01:32 +0000
Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> wrote:
> Add the block_stream command, which starts copy backing file contents
> into the image file. Also add the BLOCK_JOB_COMPLETED QMP event which
> is emitted when image streaming completes. Later patches add control
> over the background copy speed, cancelation, and querying running
> streaming operations.
>
> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
> ---
> QMP/qmp-events.txt | 29 ++++++++++++++++++++++
> blockdev.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> hmp-commands.hx | 13 ++++++++++
> hmp.c | 11 ++++++++
> hmp.h | 1 +
> monitor.c | 3 ++
> monitor.h | 1 +
> qapi-schema.json | 32 ++++++++++++++++++++++++
> qerror.c | 4 +++
> qerror.h | 3 ++
> qmp-commands.hx | 6 ++++
> trace-events | 4 +++
> 12 files changed, 174 insertions(+), 0 deletions(-)
>
> diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
> index af586ec..a80e604 100644
> --- a/QMP/qmp-events.txt
> +++ b/QMP/qmp-events.txt
> @@ -264,3 +264,32 @@ Example:
>
> Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
> followed respectively by the RESET, SHUTDOWN, or STOP events.
> +
> +
> +BLOCK_JOB_COMPLETED
> +-------------------
> +
> +Emitted when a block job has completed.
> +
> +Data:
> +
> +- "type": Job type ("stream" for image streaming, json-string)
> +- "device": Device name (json-string)
> +- "len": Maximum progress value (json-int)
> +- "offset": Current progress value (json-int)
> + On success this is equal to len.
> + On failure this is less than len.
> +- "speed": Rate limit, bytes per second (json-int)
> +- "error": Error message (json-string)
"error" is optional, so it should be "(json-string, optional)"
> + Only present on failure. This field contains a human-readable
> + error message. There are no semantics other than that streaming
> + has failed and clients should not try to interpret the error
> + string.
> +
> +Example:
> +
> +{ "event": "BLOCK_JOB_COMPLETED",
> + "data": { "type": "stream", "device": "virtio-disk0",
> + "len": 10737418240, "offset": 10737418240,
> + "speed": 0 },
> + "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
> diff --git a/blockdev.c b/blockdev.c
> index 6d78b36..ba973b0 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -13,9 +13,11 @@
> #include "qerror.h"
> #include "qemu-option.h"
> #include "qemu-config.h"
> +#include "qemu-objects.h"
> #include "sysemu.h"
> #include "block_int.h"
> #include "qmp-commands.h"
> +#include "trace.h"
>
> static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
>
> @@ -880,3 +882,68 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
> return;
> }
> }
> +
> +static QObject *qobject_from_block_job(BlockJob *job)
> +{
> + return qobject_from_jsonf("{ 'type': %s,"
> + "'device': %s,"
> + "'len': %" PRId64 ","
> + "'offset': %" PRId64 ","
> + "'speed': %" PRId64 " }",
> + job->job_type->job_type,
> + bdrv_get_device_name(job->bs),
> + job->len,
> + job->offset,
> + job->speed);
> +}
> +
> +static void block_stream_cb(void *opaque, int ret)
> +{
> + BlockDriverState *bs = opaque;
> + QObject *obj;
> +
> + trace_block_stream_cb(bs, bs->job, ret);
> +
> + assert(bs->job);
> + obj = qobject_from_block_job(bs->job);
> + if (ret < 0) {
> + QDict *dict = qobject_to_qdict(obj);
> + qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
> + }
> +
> + monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj);
> + qobject_decref(obj);
> +}
> +
> +void qmp_block_stream(const char *device, bool has_base,
> + const char *base, Error **errp)
> +{
> + BlockDriverState *bs;
> + int ret;
> +
> + bs = bdrv_find(device);
> + if (!bs) {
> + error_set(errp, QERR_DEVICE_NOT_FOUND, device);
> + return;
> + }
> +
> + /* Base device not supported */
> + if (base) {
> + error_set(errp, QERR_NOT_SUPPORTED);
> + return;
> + }
> +
> + ret = stream_start(bs, NULL, block_stream_cb, bs);
> + if (ret < 0) {
> + switch (ret) {
> + case -EBUSY:
> + error_set(errp, QERR_DEVICE_IN_USE, device);
> + return;
> + default:
> + error_set(errp, QERR_NOT_SUPPORTED);
> + return;
> + }
> + }
> +
> + trace_qmp_block_stream(bs, bs->job);
> +}
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index 14838b7..8d9dbd6 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -69,6 +69,19 @@ but should be used with extreme caution. Note that this command only
> resizes image files, it can not resize block devices like LVM volumes.
> ETEXI
>
> + {
> + .name = "block_stream",
> + .args_type = "device:B,base:s?",
> + .params = "device [base]",
> + .help = "copy data from a backing file into a block device",
> + .mhandler.cmd = hmp_block_stream,
> + },
> +
> +STEXI
> +@item block_stream
> +@findex block_stream
> +Copy data from a backing file into a block device.
> +ETEXI
>
> {
> .name = "eject",
> diff --git a/hmp.c b/hmp.c
> index e7659d5..b6e5913 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -679,3 +679,14 @@ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
> int64_t value = qdict_get_int(qdict, "value");
> qmp_migrate_set_speed(value, NULL);
> }
> +
> +void hmp_block_stream(Monitor *mon, const QDict *qdict)
> +{
> + Error *error = NULL;
> + const char *device = qdict_get_str(qdict, "device");
> + const char *base = qdict_get_try_str(qdict, "base");
> +
> + qmp_block_stream(device, base != NULL, base, &error);
> +
> + hmp_handle_error(mon, &error);
> +}
> diff --git a/hmp.h b/hmp.h
> index 093242d..b55c295 100644
> --- a/hmp.h
> +++ b/hmp.h
> @@ -49,5 +49,6 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
> void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
> void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
> void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
> +void hmp_block_stream(Monitor *mon, const QDict *qdict);
>
> #endif
> diff --git a/monitor.c b/monitor.c
> index 7334401..bb42580 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -479,6 +479,9 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
> case QEVENT_SPICE_DISCONNECTED:
> event_name = "SPICE_DISCONNECTED";
> break;
> + case QEVENT_BLOCK_JOB_COMPLETED:
> + event_name = "BLOCK_JOB_COMPLETED";
> + break;
> default:
> abort();
> break;
> diff --git a/monitor.h b/monitor.h
> index cfa2f67..7324236 100644
> --- a/monitor.h
> +++ b/monitor.h
> @@ -35,6 +35,7 @@ typedef enum MonitorEvent {
> QEVENT_SPICE_CONNECTED,
> QEVENT_SPICE_INITIALIZED,
> QEVENT_SPICE_DISCONNECTED,
> + QEVENT_BLOCK_JOB_COMPLETED,
> QEVENT_MAX,
> } MonitorEvent;
>
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 44cf764..2b1cc8c 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -1275,3 +1275,35 @@
> { 'command': 'qom-set',
> 'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
> 'gen': 'no' }
> +
> +##
> +# @block_stream:
> +#
> +# Copy data from a backing file into a block device.
> +#
> +# The block streaming operation is performed in the background until the entire
> +# backing file has been copied. This command returns immediately once streaming
> +# has started. The status of ongoing block streaming operations can be checked
> +# with query-block-jobs. The operation can be stopped before it has completed
> +# using the block_job_cancel command.
> +#
> +# If a base file is specified then sectors are not copied from that base file and
> +# its backing chain. When streaming completes the image file will have the base
> +# file as its backing file. This can be used to stream a subset of the backing
> +# file chain instead of flattening the entire image.
> +#
> +# On successful completion the image file is updated to drop the backing file
> +# and the BLOCK_JOB_COMPLETED event is emitted.
> +#
> +# @device: the device name
> +#
> +# @base: the common backing file name
@base is optional, so it should be documented like this:
@base: #optional the common backing file name
> +#
> +# Returns: Nothing on success
> +# If streaming is already active on this device, DeviceInUse
> +# If @device is does not exist, DeviceNotFound
> +# If image streaming is not supported by this device, NotSupported
> +#
> +# Since: 1.1
> +##
> +{ 'command': 'block_stream', 'data': { 'device': 'str', '*base': 'str' } }
> diff --git a/qerror.c b/qerror.c
> index 9a75d06..feb3d35 100644
> --- a/qerror.c
> +++ b/qerror.c
> @@ -182,6 +182,10 @@ static const QErrorStringTable qerror_table[] = {
> .desc = "No '%(bus)' bus found for device '%(device)'",
> },
> {
> + .error_fmt = QERR_NOT_SUPPORTED,
> + .desc = "Not supported",
> + },
> + {
> .error_fmt = QERR_OPEN_FILE_FAILED,
> .desc = "Could not open '%(filename)'",
> },
> diff --git a/qerror.h b/qerror.h
> index efda232..095ba9d 100644
> --- a/qerror.h
> +++ b/qerror.h
> @@ -153,6 +153,9 @@ QError *qobject_to_qerror(const QObject *obj);
> #define QERR_NO_BUS_FOR_DEVICE \
> "{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
>
> +#define QERR_NOT_SUPPORTED \
> + "{ 'class': 'NotSupported', 'data': {} }"
> +
> #define QERR_OPEN_FILE_FAILED \
> "{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
>
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index 7e3f4b9..b9ebb76 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -655,6 +655,12 @@ Example:
> EQMP
>
> {
> + .name = "block_stream",
> + .args_type = "device:B,base:s?",
> + .mhandler.cmd_new = qmp_marshal_input_block_stream,
> + },
> +
> + {
> .name = "blockdev-snapshot-sync",
> .args_type = "device:B,snapshot-file:s,format:s?",
> .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,
> diff --git a/trace-events b/trace-events
> index c5368fa..6ff0d43 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -74,6 +74,10 @@ bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t clus
> stream_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d"
> stream_start(void *bs, void *base, void *s, void *co, void *opaque) "bs %p base %p s %p co %p opaque %p"
>
> +# blockdev.c
> +block_stream_cb(void *bs, void *job, int ret) "bs %p job %p ret %d"
> +qmp_block_stream(void *bs, void *job) "bs %p job %p"
> +
> # hw/virtio-blk.c
> virtio_blk_req_complete(void *req, int status) "req %p status %d"
> virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
next prev parent reply other threads:[~2012-01-11 17:24 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-01-06 14:01 [Qemu-devel] [PATCH v4 00/15] block: generic image streaming Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 01/15] coroutine: add co_sleep_ns() coroutine sleep function Stefan Hajnoczi
2012-01-12 10:13 ` Kevin Wolf
2012-01-12 10:58 ` Stefan Hajnoczi
2012-01-12 11:07 ` Paolo Bonzini
2012-01-12 13:11 ` Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 02/15] block: check bdrv_in_use() before blockdev operations Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 03/15] block: add BlockJob interface for long-running operations Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 04/15] block: add image streaming block job Stefan Hajnoczi
2012-01-11 17:18 ` Luiz Capitulino
2012-01-12 9:11 ` Stefan Hajnoczi
2012-01-12 10:59 ` Kevin Wolf
2012-01-12 11:39 ` Stefan Hajnoczi
2012-01-12 12:53 ` Kevin Wolf
2012-01-12 13:05 ` Stefan Hajnoczi
2012-01-12 13:17 ` Kevin Wolf
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 05/15] block: rate-limit streaming operations Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 06/15] qmp: add block_stream command Stefan Hajnoczi
2012-01-11 17:23 ` Luiz Capitulino [this message]
2012-01-12 9:25 ` Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 07/15] qmp: add block_job_set_speed command Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 08/15] qmp: add block_job_cancel command Stefan Hajnoczi
2012-01-20 0:02 ` Eric Blake
2012-01-20 8:30 ` Kevin Wolf
2012-01-20 12:08 ` Luiz Capitulino
2012-01-20 19:55 ` Eric Blake
2012-02-07 15:44 ` Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 09/15] qmp: add query-block-jobs Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 10/15] blockdev: make image streaming safe across hotplug Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 11/15] block: add bdrv_find_backing_image Stefan Hajnoczi
2012-01-12 12:17 ` Kevin Wolf
2012-01-12 13:01 ` Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 12/15] add QERR_BASE_ID_NOT_FOUND Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 13/15] block stream: add support for partial streaming Stefan Hajnoczi
2012-01-12 12:42 ` Kevin Wolf
2012-01-12 16:14 ` Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 14/15] add doc to describe live block operations Stefan Hajnoczi
2012-01-06 14:01 ` [Qemu-devel] [PATCH v4 15/15] test: add image streaming test cases Stefan Hajnoczi
2012-01-11 17:58 ` [Qemu-devel] [PATCH v4 00/15] block: generic image streaming Luiz Capitulino
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120111152347.367d00c2@doriath \
--to=lcapitulino@redhat.com \
--cc=kwolf@redhat.com \
--cc=mtosatti@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).