From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:34348) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QOwtL-00051Y-WE for qemu-devel@nongnu.org; Tue, 24 May 2011 15:03:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QOwtJ-000480-Ri for qemu-devel@nongnu.org; Tue, 24 May 2011 15:03:43 -0400 Received: from mail-qw0-f45.google.com ([209.85.216.45]:36524) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QOwtJ-00047k-Ot for qemu-devel@nongnu.org; Tue, 24 May 2011 15:03:41 -0400 Received: by qwj8 with SMTP id 8so4249369qwj.4 for ; Tue, 24 May 2011 12:03:41 -0700 (PDT) MIME-Version: 1.0 In-Reply-To: <20110523213410.726580546@amt.cnet> References: <20110523213115.164535428@amt.cnet> <20110523213410.726580546@amt.cnet> From: Blue Swirl Date: Tue, 24 May 2011 22:03:21 +0300 Message-ID: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [patch 2/7] Add blkmirror block driver List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Marcelo Tosatti Cc: kwolf@redhat.com, Jes.Sorensen@redhat.com, dlaor@redhat.com, qemu-devel@nongnu.org, avi@redhat.com On Tue, May 24, 2011 at 12:31 AM, Marcelo Tosatti wro= te: > Mirrored writes are used by live block copy. > > Signed-off-by: Marcelo Tosatti > > Index: qemu-block-copy/block/blkmirror.c > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- /dev/null > +++ qemu-block-copy/block/blkmirror.c > @@ -0,0 +1,239 @@ > +/* > + * 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 la= ter. > + * See the COPYING file in the top-level directory. > + */ > + > +#include > +#include "block_int.h" > + > +typedef struct { > + =C2=A0 =C2=A0BlockDriverState *bs[2]; > +} BdrvMirrorState; > + > +/* Valid blkmirror filenames look like blkmirror:path/to/image1:path/to/= image2 */ > +static int blkmirror_open(BlockDriverState *bs, const char *filename, in= t flags) > +{ > + =C2=A0 =C2=A0BdrvMirrorState *m =3D bs->opaque; > + =C2=A0 =C2=A0int ret; > + =C2=A0 =C2=A0char *raw, *c; > + > + =C2=A0 =C2=A0/* Parse the blkmirror: prefix */ > + =C2=A0 =C2=A0if (strncmp(filename, "blkmirror:", strlen("blkmirror:")))= { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return -EINVAL; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0filename +=3D strlen("blkmirror:"); > + > + =C2=A0 =C2=A0/* Parse the raw image filename */ > + =C2=A0 =C2=A0c =3D strchr(filename, ':'); > + =C2=A0 =C2=A0if (c =3D=3D NULL) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return -EINVAL; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0raw =3D strdup(filename); > + =C2=A0 =C2=A0raw[c - filename] =3D '\0'; > + =C2=A0 =C2=A0ret =3D bdrv_file_open(&m->bs[0], raw, flags); > + =C2=A0 =C2=A0free(raw); > + =C2=A0 =C2=A0if (ret < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return ret; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0filename =3D c + 1; > + > + =C2=A0 =C2=A0ret =3D bdrv_file_open(&m->bs[1], filename, flags); > + =C2=A0 =C2=A0if (ret < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0bdrv_delete(m->bs[0]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return ret; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0return 0; > +} > + > +static void blkmirror_close(BlockDriverState *bs) > +{ > + =C2=A0 =C2=A0BdrvMirrorState *m =3D bs->opaque; > + =C2=A0 =C2=A0int i; > + > + =C2=A0 =C2=A0for (i=3D0; i<2; i++) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0bdrv_delete(m->bs[i]); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0m->bs[i] =3D NULL; > + =C2=A0 =C2=A0} > +} > + > +static int blkmirror_flush(BlockDriverState *bs) > +{ > + =C2=A0 =C2=A0BdrvMirrorState *m =3D bs->opaque; > + > + =C2=A0 =C2=A0bdrv_flush(m->bs[0]); > + =C2=A0 =C2=A0bdrv_flush(m->bs[1]); > + > + =C2=A0 =C2=A0return 0; > +} > + > +static int64_t blkmirror_getlength(BlockDriverState *bs) > +{ > + =C2=A0 =C2=A0BdrvMirrorState *m =3D bs->opaque; > + > + =C2=A0 =C2=A0return bdrv_getlength(m->bs[0]); > +} > + > +static BlockDriverAIOCB *blkmirror_aio_readv(BlockDriverState *bs, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 int64_t sector_num, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 QEMUIOVector *qiov, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 int nb_sectors, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 BlockDriverCompletionFunc *cb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 void *opaque) > +{ > + =C2=A0 =C2=A0BdrvMirrorState *m =3D bs->opaque; > + =C2=A0 =C2=A0return bdrv_aio_readv(m->bs[0], sector_num, qiov, nb_secto= rs, cb, opaque); > +} > + > +typedef struct DupAIOCB { > + =C2=A0 =C2=A0BlockDriverAIOCB common; > + =C2=A0 =C2=A0int count; > + > + =C2=A0 =C2=A0BlockDriverCompletionFunc *cb; > + =C2=A0 =C2=A0void *opaque; > + > + =C2=A0 =C2=A0BlockDriverAIOCB *src_aiocb; > + =C2=A0 =C2=A0BlockDriverAIOCB *dest_aiocb; > + > + =C2=A0 =C2=A0int ret; > +} DupAIOCB; Usually all types are defined at the top of the file. > + > +static void dup_aio_cancel(BlockDriverAIOCB *blockacb) > +{ > + =C2=A0 =C2=A0DupAIOCB *acb =3D container_of(blockacb, DupAIOCB, common)= ; > + > + =C2=A0 =C2=A0bdrv_aio_cancel(acb->src_aiocb); > + =C2=A0 =C2=A0bdrv_aio_cancel(acb->dest_aiocb); > + =C2=A0 =C2=A0qemu_aio_release(acb); > +} > + > +static AIOPool dup_aio_pool =3D { > + =C2=A0 =C2=A0.aiocb_size =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D sizeof(DupAIOC= B), > + =C2=A0 =C2=A0.cancel =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D dup_= aio_cancel, > +}; > + > +static void blkmirror_aio_cb(void *opaque, int ret) > +{ > + =C2=A0 =C2=A0DupAIOCB *dcb =3D opaque; > + > + =C2=A0 =C2=A0dcb->count--; > + =C2=A0 =C2=A0assert(dcb->count >=3D 0); > + =C2=A0 =C2=A0if (dcb->count =3D=3D 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (dcb->ret < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ret =3D dcb->ret; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0dcb->common.cb(dcb->opaque, ret); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_aio_release(dcb); > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0dcb->ret =3D ret; > +} > + > +static DupAIOCB *dup_aio_get(BlockDriverState *bs, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 BlockDriverCompletionFunc *cb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 void *opaque) > +{ > + =C2=A0 =C2=A0DupAIOCB *dcb; > + > + =C2=A0 =C2=A0dcb =3D qemu_aio_get(&dup_aio_pool, bs, cb, opaque); > + =C2=A0 =C2=A0if (!dcb) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return NULL; Please use QEMU's scripts/checkpatch.pl. > + =C2=A0 =C2=A0dcb->count =3D 2; > + =C2=A0 =C2=A0dcb->ret =3D 0; > + =C2=A0 =C2=A0dcb->opaque =3D opaque; > + > + =C2=A0 =C2=A0return dcb; > +} > + > +static BlockDriverAIOCB *blkmirror_aio_writev(BlockDriverState *bs, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0int64_t sector_num, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0QEMUIOVector *qiov, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0int nb_sectors, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0BlockDriverCompletionFunc *cb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0void *opaque) > +{ > + =C2=A0 =C2=A0BdrvMirrorState *m =3D bs->opaque; > + =C2=A0 =C2=A0DupAIOCB *dcb =3D dup_aio_get(bs, cb, opaque); > + > + =C2=A0 =C2=A0dcb->src_aiocb =3D bdrv_aio_writev(m->bs[0], sector_num, q= iov, nb_sectors, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &blkmirror_aio_cb, = dcb); > + =C2=A0 =C2=A0if (!dcb->src_aiocb) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_aio_release(dcb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return NULL; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0dcb->dest_aiocb =3D bdrv_aio_writev(m->bs[1], sector_num, = qiov, nb_sectors, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&blkmirror_ai= o_cb, dcb); > + =C2=A0 =C2=A0if (!dcb->dest_aiocb) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0bdrv_aio_cancel(dcb->src_aiocb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_aio_release(dcb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return NULL; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0return &dcb->common; > +} > + > +static BlockDriverAIOCB *blkmirror_aio_flush(BlockDriverState *bs, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 BlockDriverCompletionFunc *cb, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 void *opaque) > +{ > + =C2=A0 =C2=A0BdrvMirrorState *m =3D bs->opaque; > + =C2=A0 =C2=A0DupAIOCB *dcb =3D dup_aio_get(bs, cb, opaque); > + > + =C2=A0 =C2=A0dcb->src_aiocb =3D bdrv_aio_flush(m->bs[0], &blkmirror_aio= _cb, dcb); > + =C2=A0 =C2=A0if (!dcb->src_aiocb) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_aio_release(dcb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return NULL; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0dcb->dest_aiocb =3D bdrv_aio_flush(m->bs[1], &blkmirror_ai= o_cb, dcb); > + =C2=A0 =C2=A0if (!dcb->dest_aiocb) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0bdrv_aio_cancel(dcb->src_aiocb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_aio_release(dcb); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return NULL; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0return &dcb->common; > +} > + > +static int blkmirror_discard(BlockDriverState *bs, int64_t sector_num, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 int nb_sectors) > +{ > + =C2=A0 =C2=A0BdrvMirrorState *m =3D bs->opaque; > + =C2=A0 =C2=A0int ret; > + > + =C2=A0 =C2=A0ret =3D bdrv_discard(m->bs[0], sector_num, nb_sectors); > + =C2=A0 =C2=A0if (ret < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return ret; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0return bdrv_discard(m->bs[1], sector_num, nb_sectors); > +} > + > + > +static BlockDriver bdrv_blkmirror =3D { > + =C2=A0 =C2=A0.format_name =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D "blkmirror", > + =C2=A0 =C2=A0.protocol_name =C2=A0 =C2=A0 =C2=A0=3D "blkmirror", > + =C2=A0 =C2=A0.instance_size =C2=A0 =C2=A0 =C2=A0=3D sizeof(BdrvMirrorSt= ate), > + > + =C2=A0 =C2=A0.bdrv_getlength =C2=A0 =C2=A0 =3D blkmirror_getlength, > + > + =C2=A0 =C2=A0.bdrv_file_open =C2=A0 =C2=A0 =3D blkmirror_open, > + =C2=A0 =C2=A0.bdrv_close =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D blkmirror_clos= e, > + =C2=A0 =C2=A0.bdrv_flush =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D blkmirror_flus= h, > + =C2=A0 =C2=A0.bdrv_discard =C2=A0 =C2=A0 =C2=A0 =3D blkmirror_discard, > + > + =C2=A0 =C2=A0.bdrv_aio_readv =C2=A0 =C2=A0 =3D blkmirror_aio_readv, > + =C2=A0 =C2=A0.bdrv_aio_writev =C2=A0 =C2=A0=3D blkmirror_aio_writev, > + =C2=A0 =C2=A0.bdrv_aio_flush =C2=A0 =C2=A0 =3D blkmirror_aio_flush, > +}; > + > +static void bdrv_blkmirror_init(void) > +{ > + =C2=A0 =C2=A0bdrv_register(&bdrv_blkmirror); > +} > + > +block_init(bdrv_blkmirror_init); > Index: qemu-block-copy/Makefile.objs > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > --- qemu-block-copy.orig/Makefile.objs > +++ qemu-block-copy/Makefile.objs > @@ -22,7 +22,7 @@ block-nested-y +=3D raw.o cow.o qcow.o vdi > =C2=A0block-nested-y +=3D qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-= snapshot.o qcow2-cache.o > =C2=A0block-nested-y +=3D qed.o qed-gencb.o qed-l2-cache.o qed-table.o qe= d-cluster.o > =C2=A0block-nested-y +=3D qed-check.o > -block-nested-y +=3D parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o > +block-nested-y +=3D parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o = blkmirror.o > =C2=A0block-nested-$(CONFIG_WIN32) +=3D raw-win32.o > =C2=A0block-nested-$(CONFIG_POSIX) +=3D raw-posix.o > =C2=A0block-nested-$(CONFIG_CURL) +=3D curl.o > > > >