Re: [Qemu-devel] [PATCHv3] Add blkmirror block driver

2012-02-29 Thread Federico Simoncelli
- Original Message -
> From: "Federico Simoncelli" 
> To: qemu-devel@nongnu.org
> Cc: mtosa...@redhat.com, kw...@redhat.com, pbonz...@redhat.com, 
> stefa...@gmail.com, "Federico Simoncelli"
> 
> Sent: Wednesday, February 29, 2012 1:28:21 PM
> Subject: [PATCHv3] Add blkmirror block driver
> 
> Mirrored writes are used by live block copy.
> 
> Signed-off-by: Marcelo Tosatti 
> Signed-off-by: Federico Simoncelli 
> ---
>  Makefile.objs  |2 +-
>  block/blkmirror.c  |  255
>  
>  cutils.c   |   30 ++
>  docs/blkmirror.txt |   15 +++
>  qemu-common.h  |1 +
>  5 files changed, 302 insertions(+), 1 deletions(-)
>  create mode 100644 block/blkmirror.c
>  create mode 100644 docs/blkmirror.txt
> 
> diff --git a/block/blkmirror.c b/block/blkmirror.c
> new file mode 100644
> index 000..c98b162
> --- /dev/null
> +++ b/block/blkmirror.c
[...]
> +if (!drv1 || !drv2) {
> +ret = -EINVAL;
> +goto out;
> +}
> +
> +ret = bdrv_open(m->bs[0], tok[1], flags, drv1);
> +if (ret < 0) {
> +goto out;
> +}
> +
> +ret = bdrv_open(m->bs[0], tok[3], flags, drv2);
> +if (ret < 0) {
> +goto out;
> +}

There's a small mistake here, the second one is m->bs[1].

-- 
Federico



[Qemu-devel] [PATCHv3] Add blkmirror block driver

2012-02-29 Thread Federico Simoncelli
Mirrored writes are used by live block copy.

Signed-off-by: Marcelo Tosatti 
Signed-off-by: Federico Simoncelli 
---
 Makefile.objs  |2 +-
 block/blkmirror.c  |  255 
 cutils.c   |   30 ++
 docs/blkmirror.txt |   15 +++
 qemu-common.h  |1 +
 5 files changed, 302 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..2302c96 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -34,7 +34,7 @@ block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o 
dmg.o bochs.o vpc.o vv
 block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o 
qcow2-cache.o
 block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
 block-nested-y += qed-check.o
-block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
+block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o 
blkmirror.o
 block-nested-y += stream.o
 block-nested-$(CONFIG_WIN32) += raw-win32.o
 block-nested-$(CONFIG_POSIX) += raw-posix.o
diff --git a/block/blkmirror.c b/block/blkmirror.c
new file mode 100644
index 000..c98b162
--- /dev/null
+++ b/block/blkmirror.c
@@ -0,0 +1,255 @@
+/*
+ * Block driver for mirrored writes.
+ *
+ * Copyright (C) 2011-2012 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 
+#include "block_int.h"
+
+typedef struct {
+BlockDriverState *bs[2];
+} BdrvMirrorState;
+
+typedef struct DupAIOCB DupAIOCB;
+
+typedef struct SingleAIOCB {
+BlockDriverAIOCB *aiocb;
+int finished;
+DupAIOCB *parent;
+} SingleAIOCB;
+
+struct DupAIOCB {
+BlockDriverAIOCB common;
+int count;
+
+BlockDriverCompletionFunc *cb;
+SingleAIOCB aios[2];
+int ret;
+};
+
+/* Valid blkmirror filenames look like
+ * blkmirror:fmt1:path/to/image1:fmt2:path/to/image2 */
+static int blkmirror_open(BlockDriverState *bs, const char *filename, int 
flags)
+{
+int ret = 0, i;
+char *tmpbuf, *tok[4], *next;
+BlockDriver *drv1, *drv2;
+BdrvMirrorState *m = bs->opaque;
+
+m->bs[0] = bdrv_new("");
+if (m->bs[0] == NULL) {
+return -ENOMEM;
+}
+
+m->bs[1] = bdrv_new("");
+if (m->bs[1] == NULL) {
+bdrv_delete(m->bs[0]);
+return -ENOMEM;
+}
+
+tmpbuf = g_malloc(strlen(filename) + 1);
+pstrcpy(tmpbuf, strlen(filename) + 1, filename);
+
+/* Parse the blkmirror: prefix */
+if (!strstart(tmpbuf, "blkmirror:", (const char **) &next)) {
+next = tmpbuf;
+}
+
+for (i = 0; i < 4; i++) {
+if (!next) {
+ret = -EINVAL;
+goto out;
+}
+tok[i] = pstrtok_r(NULL, ":", '\\', &next);
+}
+
+drv1 = bdrv_find_whitelisted_format(tok[0]);
+drv2 = bdrv_find_whitelisted_format(tok[2]);
+
+if (!drv1 || !drv2) {
+ret = -EINVAL;
+goto out;
+}
+
+ret = bdrv_open(m->bs[0], tok[1], flags, drv1);
+if (ret < 0) {
+goto out;
+}
+
+ret = bdrv_open(m->bs[0], tok[3], flags, drv2);
+if (ret < 0) {
+goto out;
+}
+
+ out:
+g_free(tmpbuf);
+
+if (ret < 0) {
+for (i = 0; i < 2; i++) {
+bdrv_delete(m->bs[i]);
+m->bs[i] = NULL;
+}
+}
+
+return ret;
+}
+
+static void blkmirror_close(BlockDriverState *bs)
+{
+BdrvMirrorState *m = bs->opaque;
+int i;
+
+for (i = 0; i < 2; i++) {
+bdrv_delete(m->bs[i]);
+m->bs[i] = NULL;
+}
+}
+
+static coroutine_fn int blkmirror_co_flush(BlockDriverState *bs)
+{
+BdrvMirrorState *m = bs->opaque;
+int ret;
+
+ret = bdrv_co_flush(m->bs[0]);
+if (ret < 0) {
+return ret;
+}
+
+return bdrv_co_flush(m->bs[1]);
+}
+
+static int64_t blkmirror_getlength(BlockDriverState *bs)
+{
+BdrvMirrorState *m = bs->opaque;
+
+return bdrv_getlength(m->bs[0]);
+}
+
+static BlockDriverAIOCB *blkmirror_aio_readv(BlockDriverState *bs,
+ int64_t sector_num,
+ QEMUIOVector *qiov,
+ int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+BdrvMirrorState *m = bs->opaque;
+return bdrv_aio_readv(m->bs[0], sector_num, qiov, nb_sectors, cb, opaque);
+}
+
+static void dup_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+DupAIOCB *acb = container_of(blockacb, DupAIOCB, common);
+int i;
+
+for (i = 0 ; i < 2; i++) {
+if (!acb->aios[i].finished) {
+bdrv_aio_cancel(acb->aios[i].aiocb);
+}
+}
+qemu_aio_release(acb);
+}
+
+static AIOPool dup_aio_pool = {
+.aiocb_size = sizeof(DupAIOCB),
+.cancel = dup_