qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH RFC] mirror: allow mirroring an intermediate image


From: Alberto Garcia
Subject: [Qemu-devel] [PATCH RFC] mirror: allow mirroring an intermediate image
Date: Thu, 9 Apr 2015 17:33:46 +0300

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 <address@hidden>
---
 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 --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
-- 
2.1.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]