@@ -1869,22 +1869,54 @@ static void block_job_cb(void *opaque, int ret)
bdrv_put_ref_bh_schedule(bs);
}
-void qmp_block_stream(const char *device, bool has_base,
- const char *base, bool has_speed, int64_t speed,
+void qmp_block_stream(bool has_device, const char *device,
+ bool has_base, const char *base,
+ bool has_base_node_name, const char *base_node_name,
+ bool has_speed, int64_t speed,
bool has_on_error, BlockdevOnError on_error,
Error **errp)
{
- BlockDriverState *bs;
+ BlockDriverState *bs = NULL;
BlockDriverState *base_bs = NULL;
Error *local_err = NULL;
+ const char *base_name = NULL;
if (!has_on_error) {
on_error = BLOCKDEV_ON_ERROR_REPORT;
}
- bs = bdrv_find(device);
+ if (has_base && has_base_node_name) {
+ error_setg(errp, "'base' and 'base-node-name' are mutually exclusive");
+ return;
+ }
+
+ if (!has_base_node_name && !has_device) {
+ error_setg(errp, "'device' required if 'base-node-name' not specified");
+ return;
+ }
+
+ if (has_device) {
+ bs = bdrv_find(device);
+ if (!bs) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
+ }
+ }
+
+ if (has_base_node_name) {
+ base_bs = bdrv_lookup_bs(NULL, base_node_name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ /* the overlay->backing_file may not always be equal to
+ * base_bs->filename, due to how relative paths are calculated */
+ base_name = base_bs->overlay ? base_bs->overlay->backing_file : NULL;
+ bs = bs ?: bdrv_find_active(base_bs);
+ }
+
if (!bs) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ error_setg(errp, "Could not find active layer");
return;
}
@@ -1892,15 +1924,24 @@ void qmp_block_stream(const char *device, bool has_base,
return;
}
- if (base) {
+ if (has_base) {
base_bs = bdrv_find_backing_image(bs, base);
- if (base_bs == NULL) {
- error_set(errp, QERR_BASE_NOT_FOUND, base);
- return;
- }
+ base_name = base;
+ }
+
+ if (base_bs == NULL && (has_base || has_base_node_name)) {
+ error_set(errp, QERR_BASE_NOT_FOUND, base);
+ return;
+ }
+
+ /* Verify that 'base' is in the same chain as 'bs', if 'base' was
+ * specified */
+ if (base_bs && !bdrv_chain_contains(bs, base_bs)) {
+ error_setg(errp, "'device' and 'base' are not in the same chain");
+ return;
}
- stream_start(bs, base_bs, base, has_speed ? speed : 0,
+ stream_start(bs, base_bs, base_name, has_speed ? speed : 0,
on_error, block_job_cb, bs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -1172,8 +1172,8 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict)
const char *base = qdict_get_try_str(qdict, "base");
int64_t speed = qdict_get_try_int(qdict, "speed", 0);
- qmp_block_stream(device, base != NULL, base,
- qdict_haskey(qdict, "speed"), speed,
+ qmp_block_stream(true, device, base != NULL, base,
+ false, NULL, qdict_haskey(qdict, "speed"), speed,
true, BLOCKDEV_ON_ERROR_REPORT, &error);
hmp_handle_error(mon, &error);
@@ -2600,9 +2600,18 @@
# 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
+# @device: #optional The device name. Optional only if @base-node-name
+# is used.
+#
+# For 'base', either @base or @base-node-name may be set but not both. If
+# neither is specified, the entire chain will be streamed into the active image,
+# and the chain will consist of a single image (the current active layer) with
+# no backing file.
#
-# @base: #optional the common backing file name
+# @base: #optional the common backing file name
+#
+# @base-node-name: #optional the block driver state node name of the
+# common backing file. (Since 2.1)
#
# @speed: #optional the maximum speed, in bytes per second
#
@@ -2616,8 +2625,8 @@
# Since: 1.1
##
{ 'command': 'block-stream',
- 'data': { 'device': 'str', '*base': 'str', '*speed': 'int',
- '*on-error': 'BlockdevOnError' } }
+ 'data': { '*device': 'str', '*base': 'str', '*base-node-name': 'str',
+ '*speed': 'int', '*on-error': 'BlockdevOnError' } }
##
# @block-job-set-speed:
@@ -979,7 +979,7 @@ EQMP
{
.name = "block-stream",
- .args_type = "device:B,base:s?,speed:o?,on-error:s?",
+ .args_type = "device:B?,base:s?,base-node-name:s?,speed:o?,on-error:s?",
.mhandler.cmd_new = qmp_marshal_input_block_stream,
},
This adds the ability for block-stream to use node-name arguments for base, to specify the backing image to stream from. Both 'base' and 'base-node-name' are optional, but mutually exclusive. Either can be specified, but not both together. The argument for "device" is now optional as well, so long as base-node-name is specified. From the node-name, we can determine the full device chain. Signed-off-by: Jeff Cody <jcody@redhat.com> --- blockdev.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++---------- hmp.c | 4 ++-- qapi-schema.json | 17 +++++++++++---- qmp-commands.hx | 2 +- 4 files changed, 68 insertions(+), 18 deletions(-)