qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 5/6] Add blkmirror block driver


From: Paolo Bonzini
Subject: [Qemu-devel] [PATCH 5/6] Add blkmirror block driver
Date: Wed, 29 Feb 2012 14:37:29 +0100

From: Marcelo Tosatti <address@hidden>

Mirrored writes are used by live block copy.

The blkmirror driver is for internal use only, because it requires
bdrv_append to set up a backing_hd for it.  It relies on a quirk
of bdrv_append, which leaves the old image open for writes.

The source is hardcoded as the backing_hd for the destination, so that
copy-on-write functions properly.  Since the source is not yet available
at the time blkmirror_open is called, the backing_hd is set later.

Signed-off-by: Marcelo Tosatti <address@hidden>
Signed-off-by: Federico Simoncelli <address@hidden>
Signed-off-by: Paolo Bonzini <address@hidden>
---
        This version of the driver is almost entirely rewritten to
        use bs->backing_hd and bs->file.  This is necessary in order
        to share as much code as possible with group snapshots.

 Makefile.objs      |    2 +-
 block/blkmirror.c  |  153 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 docs/blkmirror.txt |   16 ++++++
 3 files changed, 170 insertions(+), 1 deletions(-)
 create mode 100644 block/blkmirror.c
 create mode 100644 docs/blkmirror.txt

diff --git a/Makefile.objs b/Makefile.objs
index 808de6a..982f44b 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -74,7 +74,7 @@ fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, 
$(fsdev-nested-y))
 # suppress *all* target specific code in case of system emulation, i.e. a
 # single QEMU executable should support all CPUs and machines.
 
-common-obj-y = $(block-obj-y) blockdev.o
+common-obj-y = $(block-obj-y) blockdev.o block/blkmirror.o
 common-obj-y += $(net-obj-y)
 common-obj-y += $(qobject-obj-y)
 common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
diff --git a/block/blkmirror.c b/block/blkmirror.c
new file mode 100644
index 0000000..4862364
--- /dev/null
+++ b/block/blkmirror.c
@@ -0,0 +1,153 @@
+/*
+ * Block driver for mirrored writes.
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdarg.h>
+#include "block_int.h"
+
+/* Valid blkmirror filenames look like
+ * blkmirror:path/to/image1:path/to/image2 */
+static int blkmirror_open(BlockDriverState *bs, const char *filename, int 
flags)
+{
+    int ret, n;
+    const char *filename2;
+    char *format;
+    BlockDriver *drv;
+
+    /* Parse the blkmirror: prefix */
+    if (strncmp(filename, "blkmirror:", strlen("blkmirror:"))) {
+        return -EINVAL;
+    }
+    filename += strlen("blkmirror:");
+
+    /* The source image filename is added by bdrv_append.  We only need
+     * to parse and open the destination image and format.  */
+    n = strcspn(filename, ":");
+    if (filename[n] == 0) {
+        format = NULL;
+        filename2 = filename;
+    } else {
+        format = g_strdup(filename);
+        format[n] = 0;
+        filename2 = format + n + 1;
+    }
+
+    drv = bdrv_find_whitelisted_format(format);
+    if (!drv) {
+        ret = -ENOENT;
+        goto out;
+    }
+
+    bs->file = bdrv_new("");
+    if (bs->file == NULL) {
+        ret = -ENOMEM;
+        goto out;
+    }
+
+    /* If we crash, we cannot assume that the destination is a
+     * valid mirror and we have to start over.  So speed up things
+     * by effectively operating on the destination in cache=unsafe
+     * mode.
+     */
+    ret = bdrv_open(bs->file, filename2,
+                    flags | BDRV_O_NO_BACKING | BDRV_O_NO_FLUSH | 
BDRV_O_CACHE_WB,
+                    drv);
+    if (ret < 0) {
+        goto out;
+    }
+
+out:
+    g_free(format);
+    return ret;
+}
+
+static void blkmirror_close(BlockDriverState *bs)
+{
+    bs->file->backing_hd = NULL;
+
+    /* backing_hd and file closed by the caller.  */
+}
+
+static coroutine_fn int blkmirror_co_flush(BlockDriverState *bs)
+{
+    return bdrv_co_flush(bs->backing_hd);
+}
+
+static int64_t blkmirror_getlength(BlockDriverState *bs)
+{
+    return bdrv_getlength(bs->file);
+}
+
+static int coroutine_fn blkmirror_co_is_allocated(BlockDriverState *bs,
+                                                  int64_t sector_num,
+                                                  int nb_sectors, int *pnum)
+{
+    return bdrv_is_allocated(bs->file, sector_num, nb_sectors, pnum);
+}
+
+static int blkmirror_co_readv(BlockDriverState *bs,
+                              int64_t sector_num, int nb_sectors,
+                              QEMUIOVector *qiov)
+{
+    return bdrv_co_readv(bs->backing_hd, sector_num, nb_sectors, qiov);
+}
+
+static int blkmirror_co_writev(BlockDriverState *bs,
+                               int64_t sector_num, int nb_sectors,
+                               QEMUIOVector *qiov)
+{
+    int ret;
+
+    /* bs->backing_hd is set after initialization.  */
+    bs->file->backing_hd = bs->backing_hd;
+
+    ret = bdrv_co_writev(bs->backing_hd, sector_num, nb_sectors, qiov);
+    if (ret >= 0) {
+        ret = bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov);
+    }
+
+    return ret;
+}
+
+static coroutine_fn int blkmirror_co_discard(BlockDriverState *bs,
+                             int64_t sector_num, int nb_sectors)
+{
+    int ret;
+
+    ret = bdrv_co_discard(bs->backing_hd, sector_num, nb_sectors);
+    if (ret >= 0) {
+        ret = bdrv_co_discard(bs->file, sector_num, nb_sectors);
+    }
+
+    return ret;
+}
+
+
+static BlockDriver bdrv_blkmirror = {
+    .format_name        = "blkmirror",
+    .protocol_name      = "blkmirror",
+    .instance_size      = 0,
+
+    .bdrv_getlength     = blkmirror_getlength,
+
+    .bdrv_file_open     = blkmirror_open,
+    .bdrv_close         = blkmirror_close,
+    .bdrv_co_flush_to_disk = blkmirror_co_flush,
+    .bdrv_co_discard    = blkmirror_co_discard,
+
+    .bdrv_co_is_allocated = blkmirror_co_is_allocated,
+    .bdrv_co_readv      = blkmirror_co_readv,
+    .bdrv_co_writev     = blkmirror_co_writev,
+};
+
+static void bdrv_blkmirror_init(void)
+{
+    bdrv_register(&bdrv_blkmirror);
+}
+
+block_init(bdrv_blkmirror_init);
diff --git a/docs/blkmirror.txt b/docs/blkmirror.txt
new file mode 100644
index 0000000..cf73f3f
--- /dev/null
+++ b/docs/blkmirror.txt
@@ -0,0 +1,16 @@
+Block mirror driver
+-------------------
+
+This driver will mirror writes to two distinct images.
+It's used internally by live block copy.
+
+Format
+------
+
+blkmirror:/image1.img:/image2.img
+
+'\' (backslash) can be used to escape colon processing
+as a separator, in the first image filename.
+Backslashes themselves also can be escaped as '\\'.
+
+
-- 
1.7.7.6





reply via email to

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