qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 6/6] add mirroring to blockdev-transaction


From: Paolo Bonzini
Subject: [Qemu-devel] [PATCH 6/6] add mirroring to blockdev-transaction
Date: Wed, 29 Feb 2012 14:37:30 +0100

Add a new transaction type, "mirror".  It stacks a new blkmirror
file (instead of a snapshot) on top of the existing image.

It is possible to combine snapshot and mirror as two actions in the
same transaction.  Because of atomicity ensured by blockdev-transaction,
this will create a snapshot *and* ensure that _all_ operations that are
sent to it are also mirrored.

Signed-off-by: Paolo Bonzini <address@hidden>
---
 blockdev.c       |   47 +++++++++++++++++++++++++++++++++++------------
 qapi-schema.json |   19 ++++++++++++++++++-
 qmp-commands.hx  |   12 +++++++++++-
 3 files changed, 64 insertions(+), 14 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 61e20f7..eef93f0 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -735,12 +735,13 @@ void qmp_blockdev_transaction(BlockdevActionList 
*dev_list,
     BlockdevAction *dev_info = NULL;
     BlkTransactionStates *states;
     BlockDriver *proto_drv;
-    BlockDriver *drv;
+    BlockDriver *target_drv;
+    BlockDriver *drv = NULL;
     int flags;
     const char *device;
     const char *format;
     const char *new_image_file = NULL;
-    bool do_snapshot;
+    char *new_source_file = NULL;
 
     QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionStates) snap_bdrv_states;
     QSIMPLEQ_INIT(&snap_bdrv_states);
@@ -759,11 +760,23 @@ void qmp_blockdev_transaction(BlockdevActionList 
*dev_list,
         switch (dev_info->kind) {
         case BLOCKDEV_ACTION_KIND_SNAPSHOT:
             device = dev_info->snapshot->device;
-            new_image_file = dev_info->snapshot->snapshot_file;
-            do_snapshot = !dev_info->snapshot->has_reuse || 
!dev_info->snapshot->reuse;
+            if (!dev_info->snapshot->has_reuse || !dev_info->snapshot->reuse) {
+                new_image_file = dev_info->snapshot->snapshot_file;
+            }
+            new_source_file = g_strdup(dev_info->snapshot->snapshot_file);
             format = dev_info->snapshot->format;
             assert(!(dev_info->snapshot->has_format && format));
             break;
+
+        case BLOCKDEV_ACTION_KIND_MIRROR:
+            device = dev_info->mirror->device;
+            if (!dev_info->mirror->has_reuse || !dev_info->mirror->reuse) {
+                new_image_file = dev_info->mirror->target;
+            }
+            format = dev_info->mirror->format;
+            assert(!(dev_info->mirror->has_format && format));
+            drv = bdrv_find_format("blkmirror");
+            break;
         default:
             abort();
         }
@@ -771,12 +784,19 @@ void qmp_blockdev_transaction(BlockdevActionList 
*dev_list,
         if (!format) {
             format = "qcow2";
         }
-
-        drv = bdrv_find_format(format);
-        if (!drv) {
+        target_drv = bdrv_find_format(format);
+        if (!target_drv) {
             error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
             goto delete_and_fail;
         }
+        if (!drv) {
+            drv = target_drv;
+        }
+
+        if (dev_info->kind == BLOCKDEV_ACTION_KIND_MIRROR) {
+            new_source_file = g_strdup_printf("blkmirror:%s:%s", format,
+                                              dev_info->mirror->target);
+        }
 
         states->old_bs = bdrv_find(device);
         if (!states->old_bs) {
@@ -800,32 +820,34 @@ void qmp_blockdev_transaction(BlockdevActionList 
*dev_list,
 
         flags = states->old_bs->open_flags;
 
-        proto_drv = bdrv_find_protocol(new_image_file);
+        proto_drv = bdrv_find_protocol(new_source_file);
         if (!proto_drv) {
             error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
             goto delete_and_fail;
         }
 
         /* create new image w/backing file */
-        if (do_snapshot) {
+        if (new_image_file) {
             ret = bdrv_img_create(new_image_file, format,
                                   states->old_bs->filename,
                                   states->old_bs->drv->format_name,
                                   NULL, -1, flags);
             if (ret) {
-                error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file);
+                error_set(errp, QERR_OPEN_FILE_FAILED, new_source_file);
                 goto delete_and_fail;
             }
         }
 
         /* We will manually add the backing_hd field to the bs later */
         states->new_bs = bdrv_new("");
-        ret = bdrv_open(states->new_bs, new_image_file,
+        ret = bdrv_open(states->new_bs, new_source_file,
                         flags | BDRV_O_NO_BACKING, drv);
         if (ret != 0) {
-            error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file);
+            error_set(errp, QERR_OPEN_FILE_FAILED, new_source_file);
             goto delete_and_fail;
         }
+        g_free(new_source_file);
+        new_source_file = NULL;
     }
 
 
@@ -853,6 +875,7 @@ exit:
     QSIMPLEQ_FOREACH(states, &snap_bdrv_states, entry) {
         g_free(states);
     }
+    g_free(new_source_file);
     return;
 }
 
diff --git a/qapi-schema.json b/qapi-schema.json
index 78df122..5f0fcee 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1131,6 +1131,22 @@
             '*reuse': 'bool' } }
 
 ##
+# @BlockdevMirror
+#
+# @device:  the name of the device to start mirroring.
+#
+# @target: the target of the new image. A new file will be created if
+#          @reuse is absent or false.
+#
+# @format: #optional the format of the snapshot image, default is 'qcow2'.
+#
+# @reuse: #optional whether QEMU should create a new image.
+##
+{ 'type': 'BlockdevMirror',
+  'data': { 'device': 'str', 'target': 'str', '*format': 'str',
+            '*reuse': 'bool' } }
+
+##
 # @BlockdevAction
 #
 # A discriminated record of operations that can be performed with
@@ -1138,7 +1154,8 @@
 ##
 { 'union': 'BlockdevAction',
   'data': {
-       'snapshot': 'BlockdevSnapshot'
+       'snapshot': 'BlockdevSnapshot',
+       'mirror': 'BlockdevMirror',
    } }
 
 ##
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 6728495..b7a9ada 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -701,7 +701,11 @@ operation for now is snapshotting.  If there is any 
failure performing
 any of the operations, all snapshots for the group are abandoned, and
 the original disks pre-snapshot attempt are used.
 
+Mirrored writes keep the previous image file open, and start writing
+data also to the new file specified in the command.
+
 A list of dictionaries is accepted, that contains the actions to be performed.
+
 For snapshots this is the device, the file to use for the new snapshot,
 and the format.  The default format, if not specified, is qcow2.
 Image files can be created by QEMU, or it can be created externally.
@@ -713,7 +717,7 @@ Arguments:
 
 actions array:
     - "type": the operation to perform.  The only supported
-      value is "snapshot". (json-string)
+      values are "snapshot" and "mirror". (json-string)
     - "data": a dictionary.  The contents depend on the value
       of "type".  When "type" is "snapshot":
       - "device": device name to snapshot (json-string)
@@ -721,6 +725,12 @@ actions array:
       - "format": format of new image (json-string, optional)
       - "reuse": whether QEMU should look for an existing image file
         (json-bool, optional, default false)
+      When "type" is "mirror":
+      - "device": device name to snapshot (json-string)
+      - "target": name of destination image file (json-string)
+      - "format": format of new image (json-string, optional)
+      - "reuse": whether QEMU should look for an existing image file
+        (json-bool, optional, default false)
 
 Example:
 
-- 
1.7.7.6




reply via email to

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