diff mbox

[RFC] mirror: allow mirroring an intermediate image

Message ID 1428590026-1496-1-git-send-email-berto@igalia.com
State New
Headers show

Commit Message

Alberto Garcia April 9, 2015, 2:33 p.m. UTC
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(-)
diff mbox

Patch

diff --git a/block.c b/block.c
index e892cb4..7bbae5a 100644
--- a/block.c
+++ b/block.c
@@ -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);
 }
diff --git a/block/mirror.c b/block/mirror.c
index 189e8f8..c05598f 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -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;
     }
 
diff --git a/blockdev.c b/blockdev.c
index f24cf2d..eb2e5c1 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -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);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 60b9664..3c10f89 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -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
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 3a42ad0..91902a1 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -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