@@ -1245,6 +1245,8 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
bs->backing_blocker);
bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_STREAM,
bs->backing_blocker);
+ bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_MIRROR,
+ bs->backing_blocker);
out:
bdrv_refresh_limits(bs, NULL);
}
@@ -340,6 +340,7 @@ static void mirror_exit(BlockJob *job, void *opaque)
}
if (s->should_complete && data->ret == 0) {
+ BlockDriverState *bdrv;
BlockDriverState *to_replace = s->common.bs;
if (s->to_replace) {
to_replace = s->to_replace;
@@ -355,6 +356,39 @@ static void mirror_exit(BlockJob *job, void *opaque)
bdrv_set_backing_hd(s->base, NULL);
bdrv_unref(p);
}
+
+ /* If a BlockDriverState was pointing to the image that we
+ * have just replaced, it must point now to the new one. */
+ for (bdrv = bdrv_next(NULL); bdrv; bdrv = bdrv_next(bdrv)) {
+ BlockDriverState *overlay;
+ AioContext *aio_context = bdrv_get_aio_context(bdrv);
+ aio_context_acquire(aio_context);
+ overlay = bdrv_find_overlay(bdrv, to_replace);
+ if (overlay) {
+ int ret, flags;
+ const char *filename, *format;
+
+ /* Change backing file in the header of the overlay image */
+ filename = to_replace->filename;
+ format = to_replace->drv ? to_replace->drv->format_name : "";
+ flags = bdrv_get_flags(overlay);
+ if (!(flags & BDRV_O_RDWR)) {
+ bdrv_reopen(overlay, flags | BDRV_O_RDWR, NULL);
+ }
+ ret = bdrv_change_backing_file(overlay, filename, format);
+ if (!(flags & BDRV_O_RDWR)) {
+ bdrv_reopen(overlay, flags, NULL);
+ }
+
+ /* If everything went well, update the BlockDriverState */
+ if (ret == 0) {
+ bdrv_set_backing_hd(overlay, to_replace);
+ } else {
+ data->ret = ret;
+ }
+ }
+ aio_context_release(aio_context);
+ }
}
if (s->to_replace) {
bdrv_op_unblock_all(s->to_replace, s->replace_blocker);
@@ -608,8 +642,8 @@ static void mirror_complete(BlockJob *job, Error **errp)
}
if (!s->synced) {
error_setg(errp,
- "The active block job for device '%s' cannot be completed",
- bdrv_get_device_name(job->bs));
+ "The active block job for node '%s' cannot be completed",
+ bdrv_get_device_or_node_name(job->bs));
return;
}
@@ -2464,7 +2464,6 @@ void qmp_drive_mirror(const char *device, const char *target,
bool has_on_target_error, BlockdevOnError on_target_error,
Error **errp)
{
- BlockBackend *blk;
BlockDriverState *bs;
BlockDriverState *source, *target_bs;
AioContext *aio_context;
@@ -2504,12 +2503,10 @@ void qmp_drive_mirror(const char *device, const char *target,
return;
}
- blk = blk_by_name(device);
- if (!blk) {
- error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ bs = bdrv_lookup_bs(device, device, errp);
+ if (!bs) {
return;
}
- bs = blk_bs(blk);
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
@@ -903,7 +903,7 @@
#
# Start mirroring a block device's writes to a new destination.
#
-# @device: the name of the device whose writes should be mirrored.
+# @device: the device or node name of the image 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
@@ -1397,7 +1397,7 @@ of the source.
Arguments:
-- "device": device name to operate on (json-string)
+- "device": device or node name to operate on (json-string)
- "target": name of new image file (json-string)
- "format": format of new image (json-string, optional)
- "node-name": the name of the new block driver state in the node graph
This extends the drive-mirror command by allowing it to operate on intermediate images. The device parameter can now take the node name of the image to be mirrored. After the operation its overlay image will point to the new one. Signed-off-by: Alberto Garcia <berto@igalia.com> --- block.c | 2 ++ block/mirror.c | 38 ++++++++++++++++++++++++++++++++++++-- blockdev.c | 7 ++----- qapi/block-core.json | 2 +- qmp-commands.hx | 2 +- 5 files changed, 42 insertions(+), 9 deletions(-)