Patchwork [1/4] qmp: add block_stream command

login
register
mail settings
Submitter Stefan Hajnoczi
Date Aug. 23, 2011, 12:58 p.m.
Message ID <1314104305-20523-2-git-send-email-stefanha@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/111090/
State New
Headers show

Comments

Stefan Hajnoczi - Aug. 23, 2011, 12:58 p.m.
This patch introduces the block_stream HMP/QMP command.  It is currently
unimplemented and returns the 'NotSupported' error.

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.

Arguments:

- device: device name (json-string)
- base:   common backing file (json-string, optional)

Errors:

DeviceInUse:    streaming is already active on this device
DeviceNotFound: device name is invalid
NotSupported:   image streaming is not supported by this device

Events:

On completion the BLOCK_JOB_COMPLETED event is raised with the following
fields:

- type:     job type ("stream" for image streaming, json-string)
- device:   device name (json-string)
- end:      maximum progress value (json-int)
- position: current progress value (json-int)
- speed:    rate limit, bytes per second (json-int)
- error:    error message (json-string, only on error)

The completion event is raised both on success and on failure.  On
success position is equal to end.  On failure position and end can be
used to indicate at which point the operation failed.

On failure the error 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.

Examples:

-> { "execute": "block_stream", "arguments": { "device": "virtio0" } }
<- { "return":  {} }

Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
---
 blockdev.c      |   18 +++++++++++++++
 blockdev.h      |    1 +
 hmp-commands.hx |   14 +++++++++++
 monitor.c       |    3 ++
 monitor.h       |    1 +
 qerror.h        |    3 ++
 qmp-commands.hx |   65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 105 insertions(+), 0 deletions(-)
Adam Litke - Aug. 23, 2011, 4:33 p.m.
Under libvirt, I get the following error when trying to start a block
stream:

qerror: bad call in function 'do_block_stream':
qerror: -> error format '{ 'class': 'NotSupported', 'data': {} }' not found
qerror: call at blockdev.c:808
2011-08-23 11:30:09.974: shutting down

Is this patch missing a part of the qerror definition?

On Tue, 2011-08-23 at 13:58 +0100, Stefan Hajnoczi wrote:
> This patch introduces the block_stream HMP/QMP command.  It is currently
> unimplemented and returns the 'NotSupported' error.
> 
> 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.
> 
> Arguments:
> 
> - device: device name (json-string)
> - base:   common backing file (json-string, optional)
> 
> Errors:
> 
> DeviceInUse:    streaming is already active on this device
> DeviceNotFound: device name is invalid
> NotSupported:   image streaming is not supported by this device
> 
> Events:
> 
> On completion the BLOCK_JOB_COMPLETED event is raised with the following
> fields:
> 
> - type:     job type ("stream" for image streaming, json-string)
> - device:   device name (json-string)
> - end:      maximum progress value (json-int)
> - position: current progress value (json-int)
> - speed:    rate limit, bytes per second (json-int)
> - error:    error message (json-string, only on error)
> 
> The completion event is raised both on success and on failure.  On
> success position is equal to end.  On failure position and end can be
> used to indicate at which point the operation failed.
> 
> On failure the error 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.
> 
> Examples:
> 
> -> { "execute": "block_stream", "arguments": { "device": "virtio0" } }
> <- { "return":  {} }
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
> ---
>  blockdev.c      |   18 +++++++++++++++
>  blockdev.h      |    1 +
>  hmp-commands.hx |   14 +++++++++++
>  monitor.c       |    3 ++
>  monitor.h       |    1 +
>  qerror.h        |    3 ++
>  qmp-commands.hx |   65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 105 insertions(+), 0 deletions(-)
> 
> diff --git a/blockdev.c b/blockdev.c
> index d272659..208bfc9 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -790,3 +790,21 @@ int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data)
> 
>      return 0;
>  }
> +
> +int do_block_stream(Monitor *mon, const QDict *params, QObject **ret_data)
> +{
> +    const char *device = qdict_get_str(params, "device");
> +    BlockDriverState *bs;
> +
> +    bs = bdrv_find(device);
> +    if (!bs) {
> +        qerror_report(QERR_DEVICE_NOT_FOUND, device);
> +        return -1;
> +    }
> +
> +    /* This command is not yet implemented.  The device not found check above
> +     * is done so that error ordering will not change when fully implemented.
> +     */
> +    qerror_report(QERR_NOT_SUPPORTED);
> +    return -1;
> +}
> diff --git a/blockdev.h b/blockdev.h
> index 3587786..ad98d37 100644
> --- a/blockdev.h
> +++ b/blockdev.h
> @@ -65,5 +65,6 @@ int do_change_block(Monitor *mon, const char *device,
>  int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
>  int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data);
>  int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data);
> +int do_block_stream(Monitor *mon, const QDict *qdict, QObject **ret_data);
> 
>  #endif
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index 0ccfb28..2a16fd9 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -70,6 +70,20 @@ 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",
> +        .user_print = monitor_user_noop,
> +        .mhandler.cmd_new = do_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/monitor.c b/monitor.c
> index ada51d0..dc55fca 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -468,6 +468,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 4f2d328..135c927 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/qerror.h b/qerror.h
> index 8058456..eba9238 100644
> --- a/qerror.h
> +++ b/qerror.h
> @@ -139,6 +139,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 03f67da..60c9bdf 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -694,6 +694,71 @@ Example:
>  EQMP
> 
>      {
> +        .name       = "block_stream",
> +        .args_type  = "device:B,base:s?",
> +        .params     = "device [base]",
> +        .user_print = monitor_user_noop,
> +        .mhandler.cmd_new = do_block_stream,
> +    },
> +
> +SQMP
> +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.
> +
> +Arguments:
> +
> +- device: device name (json-string)
> +- base:   common backing file (json-string, optional)
> +
> +Errors:
> +
> +DeviceInUse:    streaming is already active on this device
> +DeviceNotFound: device name is invalid
> +NotSupported:   image streaming is not supported by this device
> +
> +Events:
> +
> +On completion the BLOCK_JOB_COMPLETED event is raised with the following
> +fields:
> +
> +- type:     job type ("stream" for image streaming, json-string)
> +- device:   device name (json-string)
> +- end:      maximum progress value (json-int)
> +- position: current progress value (json-int)
> +- speed:    rate limit, bytes per second (json-int)
> +- error:    error message (json-string, only on error)
> +
> +The completion event is raised both on success and on failure.  On
> +success position is equal to end.  On failure position and end can be
> +used to indicate at which point the operation failed.
> +
> +On failure the error 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.
> +
> +Examples:
> +
> +-> { "execute": "block_stream", "arguments": { "device": "virtio0" } }
> +<- { "return":  {} }
> +
> +EQMP
> +
> +    {
>          .name       = "blockdev-snapshot-sync",
>          .args_type  = "device:B,snapshot-file:s?,format:s?",
>          .params     = "device [new-image-file] [format]",
Stefan Hajnoczi - Aug. 30, 2011, 9:43 a.m.
On Tue, Aug 23, 2011 at 11:33:25AM -0500, Adam Litke wrote:
> Under libvirt, I get the following error when trying to start a block
> stream:
> 
> qerror: bad call in function 'do_block_stream':
> qerror: -> error format '{ 'class': 'NotSupported', 'data': {} }' not found
> qerror: call at blockdev.c:808
> 2011-08-23 11:30:09.974: shutting down
> 
> Is this patch missing a part of the qerror definition?

Thanks Adam.  I need to fix this, will send out a v2.

Stefan

Patch

diff --git a/blockdev.c b/blockdev.c
index d272659..208bfc9 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -790,3 +790,21 @@  int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data)
 
     return 0;
 }
+
+int do_block_stream(Monitor *mon, const QDict *params, QObject **ret_data)
+{
+    const char *device = qdict_get_str(params, "device");
+    BlockDriverState *bs;
+
+    bs = bdrv_find(device);
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, device);
+        return -1;
+    }
+
+    /* This command is not yet implemented.  The device not found check above
+     * is done so that error ordering will not change when fully implemented.
+     */
+    qerror_report(QERR_NOT_SUPPORTED);
+    return -1;
+}
diff --git a/blockdev.h b/blockdev.h
index 3587786..ad98d37 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -65,5 +65,6 @@  int do_change_block(Monitor *mon, const char *device,
 int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
 int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data);
 int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_block_stream(Monitor *mon, const QDict *qdict, QObject **ret_data);
 
 #endif
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 0ccfb28..2a16fd9 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -70,6 +70,20 @@  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",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_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/monitor.c b/monitor.c
index ada51d0..dc55fca 100644
--- a/monitor.c
+++ b/monitor.c
@@ -468,6 +468,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 4f2d328..135c927 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/qerror.h b/qerror.h
index 8058456..eba9238 100644
--- a/qerror.h
+++ b/qerror.h
@@ -139,6 +139,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 03f67da..60c9bdf 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -694,6 +694,71 @@  Example:
 EQMP
 
     {
+        .name       = "block_stream",
+        .args_type  = "device:B,base:s?",
+        .params     = "device [base]",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = do_block_stream,
+    },
+
+SQMP
+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.
+
+Arguments:
+
+- device: device name (json-string)
+- base:   common backing file (json-string, optional)
+
+Errors:
+
+DeviceInUse:    streaming is already active on this device
+DeviceNotFound: device name is invalid
+NotSupported:   image streaming is not supported by this device
+
+Events:
+
+On completion the BLOCK_JOB_COMPLETED event is raised with the following
+fields:
+
+- type:     job type ("stream" for image streaming, json-string)
+- device:   device name (json-string)
+- end:      maximum progress value (json-int)
+- position: current progress value (json-int)
+- speed:    rate limit, bytes per second (json-int)
+- error:    error message (json-string, only on error)
+
+The completion event is raised both on success and on failure.  On
+success position is equal to end.  On failure position and end can be
+used to indicate at which point the operation failed.
+
+On failure the error 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.
+
+Examples:
+
+-> { "execute": "block_stream", "arguments": { "device": "virtio0" } }
+<- { "return":  {} }
+
+EQMP
+
+    {
         .name       = "blockdev-snapshot-sync",
         .args_type  = "device:B,snapshot-file:s?,format:s?",
         .params     = "device [new-image-file] [format]",