Re: [Qemu-devel] [PATCH 1/2 v2] Add blkmirror block driver
- Original Message - From: Luiz Capitulino lcapitul...@redhat.com To: Federico Simoncelli fsimo...@redhat.com Cc: qemu-devel@nongnu.org, mtosa...@redhat.com, pbonz...@redhat.com, kw...@redhat.com, arm...@redhat.com Sent: Friday, February 24, 2012 7:17:22 PM Subject: Re: [PATCH 1/2 v2] Add blkmirror block driver On Fri, 24 Feb 2012 16:49:03 + Federico Simoncelli fsimo...@redhat.com wrote: +/* Parse the raw image filename */ +filename2 = g_malloc(strlen(filename)+1); +escape = 0; +for (i = n = 0; i strlen(filename); i++) { +if (!escape filename[i] == ':') { +break; +} +if (!escape filename[i] == '\\') { +escape = 1; +} else { +escape = 0; +} + +if (!escape) { +filename2[n++] = filename[i]; +} +} +filename2[n] = '\0'; You're escaping only the first image name string, is that intentional? Yes, it was also documented here by Marcelo: diff --git a/docs/blkmirror.txt b/docs/blkmirror.txt new file mode 100644 index 000..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 '\\'. + + Anyway this format is encapsulated by blockdev-migrate. -- Federico
[Qemu-devel] [PATCH 1/2 v2] Add blkmirror block driver
From: Marcelo Tosatti mtosa...@redhat.com Mirrored writes are used by live block copy. Signed-off-by: Marcelo Tosatti mtosa...@redhat.com Signed-off-by: Federico Simoncelli fsimo...@redhat.com --- Makefile.objs |2 +- block/blkmirror.c | 247 docs/blkmirror.txt | 16 3 files changed, 264 insertions(+), 1 deletions(-) create mode 100644 block/blkmirror.c create mode 100644 docs/blkmirror.txt diff --git a/Makefile.objs b/Makefile.objs index 67ee3df..6020308 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..49e3381 --- /dev/null +++ b/block/blkmirror.c @@ -0,0 +1,247 @@ +/* + * 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 + +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:path/to/image1:path/to/image2 */ +static int blkmirror_open(BlockDriverState *bs, const char *filename, int flags) +{ +BdrvMirrorState *m = bs-opaque; +int ret, escape, i, n; +char *filename2; + +/* Parse the blkmirror: prefix */ +if (strncmp(filename, blkmirror:, strlen(blkmirror:))) { +return -EINVAL; +} +filename += strlen(blkmirror:); + +/* Parse the raw image filename */ +filename2 = g_malloc(strlen(filename)+1); +escape = 0; +for (i = n = 0; i strlen(filename); i++) { +if (!escape filename[i] == ':') { +break; +} +if (!escape filename[i] == '\\') { +escape = 1; +} else { +escape = 0; +} + +if (!escape) { +filename2[n++] = filename[i]; +} +} +filename2[n] = '\0'; + +m-bs[0] = bdrv_new(); +if (m-bs[0] == NULL) { +g_free(filename2); +return -ENOMEM; +} +ret = bdrv_open(m-bs[0], filename2, flags, NULL); +g_free(filename2); +if (ret 0) { +return ret; +} +filename += i + 1; + +m-bs[1] = bdrv_new(); +if (m-bs[1] == NULL) { +bdrv_delete(m-bs[0]); +return -ENOMEM; +} +ret = bdrv_open(m-bs[1], filename, flags | BDRV_O_NO_BACKING, NULL); +if (ret 0) { +bdrv_delete(m-bs[0]); +return ret; +} + +return 0; +} + +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_aio_cancel, +}; + +static void blkmirror_aio_cb(void
Re: [Qemu-devel] [PATCH 1/2 v2] Add blkmirror block driver
On 02/24/2012 09:49 AM, Federico Simoncelli wrote: From: Marcelo Tosatti mtosa...@redhat.com Mirrored writes are used by live block copy. Signed-off-by: Marcelo Tosatti mtosa...@redhat.com Signed-off-by: Federico Simoncelli fsimo...@redhat.com --- +++ b/block/blkmirror.c @@ -0,0 +1,247 @@ +/* + * Block driver for mirrored writes. + * + * Copyright (C) 2011 Red Hat, Inc. It's 2012 now. +++ 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 '\\'. Is the escaping of : and \ only necessary for image1.img, or for both image1 and image2? I need to know if the parser is consistent for both arguments, but this wording makes it sound like it is only for the first argument. -- Eric Blake ebl...@redhat.com+1-919-301-3266 Libvirt virtualization library http://libvirt.org signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [PATCH 1/2 v2] Add blkmirror block driver
- Original Message - From: Eric Blake ebl...@redhat.com To: Federico Simoncelli fsimo...@redhat.com Cc: qemu-devel@nongnu.org, kw...@redhat.com, mtosa...@redhat.com, arm...@redhat.com, lcapitul...@redhat.com, pbonz...@redhat.com Sent: Friday, February 24, 2012 6:02:36 PM Subject: Re: [Qemu-devel] [PATCH 1/2 v2] Add blkmirror block driver +++ 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 '\\'. Is the escaping of : and \ only necessary for image1.img, or for both image1 and image2? I need to know if the parser is consistent for both arguments, but this wording makes it sound like it is only for the first argument. Yes it is only for the first argument. -- Federico
Re: [Qemu-devel] [PATCH 1/2 v2] Add blkmirror block driver
On Fri, 24 Feb 2012 16:49:03 + Federico Simoncelli fsimo...@redhat.com wrote: From: Marcelo Tosatti mtosa...@redhat.com Mirrored writes are used by live block copy. Signed-off-by: Marcelo Tosatti mtosa...@redhat.com Signed-off-by: Federico Simoncelli fsimo...@redhat.com --- Makefile.objs |2 +- block/blkmirror.c | 247 docs/blkmirror.txt | 16 3 files changed, 264 insertions(+), 1 deletions(-) create mode 100644 block/blkmirror.c create mode 100644 docs/blkmirror.txt diff --git a/Makefile.objs b/Makefile.objs index 67ee3df..6020308 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..49e3381 --- /dev/null +++ b/block/blkmirror.c @@ -0,0 +1,247 @@ +/* + * 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 + +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:path/to/image1:path/to/image2 */ +static int blkmirror_open(BlockDriverState *bs, const char *filename, int flags) +{ +BdrvMirrorState *m = bs-opaque; +int ret, escape, i, n; +char *filename2; + +/* Parse the blkmirror: prefix */ +if (strncmp(filename, blkmirror:, strlen(blkmirror:))) { +return -EINVAL; +} +filename += strlen(blkmirror:); Minor: you can use strstart() here. + +/* Parse the raw image filename */ +filename2 = g_malloc(strlen(filename)+1); +escape = 0; +for (i = n = 0; i strlen(filename); i++) { +if (!escape filename[i] == ':') { +break; +} +if (!escape filename[i] == '\\') { +escape = 1; +} else { +escape = 0; +} + +if (!escape) { +filename2[n++] = filename[i]; +} +} +filename2[n] = '\0'; You're escaping only the first image name string, is that intentional? + +m-bs[0] = bdrv_new(); +if (m-bs[0] == NULL) { +g_free(filename2); +return -ENOMEM; +} +ret = bdrv_open(m-bs[0], filename2, flags, NULL); +g_free(filename2); +if (ret 0) { Leaking m-bs[0]? +return ret; +} +filename += i + 1; + +m-bs[1] = bdrv_new(); +if (m-bs[1] == NULL) { +bdrv_delete(m-bs[0]); +return -ENOMEM; +} +ret = bdrv_open(m-bs[1], filename, flags | BDRV_O_NO_BACKING, NULL); +if (ret 0) { +bdrv_delete(m-bs[0]); What about m-bs[1]? +return ret; +} + +return 0; +} + +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) +{
Re: [Qemu-devel] [PATCH 1/2 v2] Add blkmirror block driver
On 02/24/2012 06:02 PM, Eric Blake wrote: Is the escaping of : and \ only necessary for image1.img, or for both image1 and image2? I need to know if the parser is consistent for both arguments, but this wording makes it sound like it is only for the first argument. libvirt is completely insulated from this. Paolo