diff options
Diffstat (limited to 'blockdev.c')
| -rw-r--r-- | blockdev.c | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/blockdev.c b/blockdev.c index d11a74f837..ded13268f7 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2932,12 +2932,13 @@ static void block_job_cb(void *opaque, int ret) void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, bool has_base, const char *base, + bool has_base_node, const char *base_node, bool has_backing_file, const char *backing_file, bool has_speed, int64_t speed, bool has_on_error, BlockdevOnError on_error, Error **errp) { - BlockDriverState *bs; + BlockDriverState *bs, *iter; BlockDriverState *base_bs = NULL; AioContext *aio_context; Error *local_err = NULL; @@ -2947,7 +2948,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, on_error = BLOCKDEV_ON_ERROR_REPORT; } - bs = qmp_get_root_bs(device, errp); + bs = bdrv_lookup_bs(device, device, errp); if (!bs) { return; } @@ -2955,7 +2956,9 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); - if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_STREAM, errp)) { + if (has_base && has_base_node) { + error_setg(errp, "'base' and 'base-node' cannot be specified " + "at the same time"); goto out; } @@ -2969,6 +2972,27 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device, base_name = base; } + if (has_base_node) { + base_bs = bdrv_lookup_bs(NULL, base_node, errp); + if (!base_bs) { + goto out; + } + if (bs == base_bs || !bdrv_chain_contains(bs, base_bs)) { + error_setg(errp, "Node '%s' is not a backing image of '%s'", + base_node, device); + goto out; + } + assert(bdrv_get_aio_context(base_bs) == aio_context); + base_name = base_bs->filename; + } + + /* Check for op blockers in the whole chain between bs and base */ + for (iter = bs; iter && iter != base_bs; iter = backing_bs(iter)) { + if (bdrv_op_is_blocked(iter, BLOCK_OP_TYPE_STREAM, errp)) { + goto out; + } + } + /* if we are streaming the entire chain, the result will have no backing * file, and specifying one is therefore an error */ if (base_bs == NULL && has_backing_file) { @@ -3001,6 +3025,7 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, Error **errp) { BlockDriverState *bs; + BlockDriverState *iter; BlockDriverState *base_bs, *top_bs; AioContext *aio_context; Error *local_err = NULL; @@ -3067,8 +3092,10 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, assert(bdrv_get_aio_context(base_bs) == aio_context); - if (bdrv_op_is_blocked(base_bs, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) { - goto out; + for (iter = top_bs; iter != backing_bs(base_bs); iter = backing_bs(iter)) { + if (bdrv_op_is_blocked(iter, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) { + goto out; + } } /* Do not allow attempts to commit an image into itself */ @@ -3086,6 +3113,10 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device, commit_active_start(has_job_id ? job_id : NULL, bs, base_bs, speed, on_error, block_job_cb, bs, &local_err, false); } else { + BlockDriverState *overlay_bs = bdrv_find_overlay(bs, top_bs); + if (bdrv_op_is_blocked(overlay_bs, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) { + goto out; + } commit_start(has_job_id ? job_id : NULL, bs, base_bs, top_bs, speed, on_error, block_job_cb, bs, has_backing_file ? backing_file : NULL, &local_err); |