qemu-kvm/rbd: small fixes and cosmetics
Subsystems (2)
PATCH 1/1 qemu-kvm/rbd: small fixes and cosmetics
Attached is a patch with small fixes and cosmetics for the qemu-kvm/rbd driver:
- conditional linking of librados
- reduced header size
- followed the variable names of the kernel driver
Could you put it in the git repository, please?
Christian
--- Makefile | 2 ++ block/rbd.c | 56 ++++++++++++++++++++++++++++---------------------------- 2 files changed, 30 insertions(+), 28 deletions(-)
Makefile +2 -0
@@ -27,7 +27,9 @@ configure: ; $(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw) LIBS+=-lz $(LIBS_TOOLS) +ifdef CONFIG_RBD LIBS+=-lrados +endif ifdef BUILD_DOCS DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8
block/rbd.c +28 -28
153 lines not on this page · raw message
Signature · 8 lines
1.6.6.1
--
Christian Brunner MUC.DE e.V.
Joseph-Dollinger-Bogen 14
D-80807 MuenchenQuoted 9 lines · Christian Brunner
Attached is a patch with small fixes and cosmetics for the qemu-kvm/rbd driver:
- conditional linking of librados
- reduced header size
- followed the variable names of the kernel driverCould you put it in the git repository, please?
Pushed, thanks!
Yehuda
qemu-kvm/rbd: first attempt to implement aio
In reply to Christian BrunnerTo increase the performance of the qemu rbd driver I started to implement aio functions. Attached is an intial aio implementation. However it is missing the callback of rados_aio_read or _write from time to time. This leads to a lockup of the disk driver until the guest OS is perfomring a bus reset.
If someone has an explanation for the cause of the lost callbacks. I would be happy.
Regards, Christian
block/rbd.c +200 -1
@@ -47,6 +47,17 @@#define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER) +typedef struct RBDAIOCB { +BlockDriverAIOCB common; +QEMUIOVector *qiov; +int64_t sector_num; +int nb_sectors; +QEMUBH *bh; +int write; +char *buf; +int ret; +int aiocnt; +}RBDAIOCB ; typedef struct RBDRVRBDState { rados_pool_t pool;
@@ -341,6 +352,192 @@ static int rbd_read(BlockDriverState *bs, int64_t sector_num,return (0 ); } +static int rbd_schedule_bh (QEMUBHFunc *cb,RBDAIOCB *acb) { +if (acb->bh) { +fprintf (stderr,"rbd_schedule_bh: bh should be NULL\n" ); +return -EIO ; + } + + acb->bh =qemu_bh_new (cb, acb); +if (!acb->bh) { +fprintf (stderr,"rbd_schedule_bh: qemu_bh_new failed\n" ); +return -EIO ; + } + +qemu_bh_schedule (acb->bh); + +return 0 ; +} + +static void rbd_finish_aiocb (rados_completion_t c,RBDAIOCB *acb) { +if (rados_aio_is_complete (c) && !rados_aio_is_safe (c)) { + acb->aiocnt--; +if (acb->write ==0 ) { +fprintf (stderr,"rbd_finish_aiocb: read complete - aiocnt=%i\n" , acb->aiocnt); + }else { +fprintf (stderr,"rbd_finish_aiocb: write complete - aiocnt=%i\n" , acb->aiocnt); + } + }else { +//fprintf(stderr, "rbd_finish_aiocb: returning\n"); +return ; + } +if (acb->aiocnt ==0 ) { +if (acb->write ==0 ) { +qemu_iovec_from_buffer (acb->qiov, acb->buf, acb->nb_sectors*512 ); + } + acb->common.cb (acb->common.opaque, acb->ret); +//qemu_free(acb->buf); +qemu_aio_release (acb); + } +} + +static void rbd_readv_bh_cb (void *p) +{ +RBDAIOCB *acb = p; +RBDRVRBDState *s = acb->common.bs->opaque; +rados_completion_t c; +char *buf; +char n[RBD_MAX_SEG_NAME_SIZE ]; +int64_t segnr, segoffs, segsize; +int64_t off, size; + + off = acb->sector_num *512 ; + size = acb->nb_sectors *512 ; + segnr = (int64_t ) (off / s->objsize); + segoffs = (int64_t ) (off % s->objsize); + segsize = (int64_t ) (s->objsize - segoffs); + + buf = acb->buf; + +while (size >0 ) { +if (size < segsize) { + segsize = size; + } + +snprintf (n,RBD_MAX_SEG_NAME_SIZE ,"%s.%012llx" , s->name, (long long unsigned int ) segnr); + acb->aiocnt++; +fprintf (stderr,"rbd_readv_bh_cb: aiocnt=%i: reading %s (segoffs: %lld, segsize %lld)\n" , acb->aiocnt, n, (long long int ) segoffs, (long long int ) segsize); +rados_aio_read (s->pool, n, segoffs, (char *) buf, segsize, &c); +rados_aio_set_callback (c, (rados_callback_t ) rbd_finish_aiocb, acb); + buf += segsize; + size -= segsize; + segoffs =0 ; + segsize = s->objsize; + segnr++; + } + +return ; +} + +static void rbd_writev_bh_cb (void *p) +{ +RBDAIOCB *acb = p; +RBDRVRBDState *s = acb->common.bs->opaque; +rados_completion_t c; +char *buf; +char n[RBD_MAX_SEG_NAME_SIZE ]; +int64_t segnr, segoffs, segsize; +int64_t off, size; + + off = acb->sector_num *512 ; + size = acb->nb_sectors *512 ; + segnr = (int64_t ) (off / s->objsize); + segoffs = (int64_t ) (off % s->objsize); + segsize = (int64_t ) (s->objsize - segoffs); + + buf =malloc (acb->qiov->size); +if (!buf) { +/* XXX: error */ + } + +qemu_iovec_to_buffer (acb->qiov, buf); + +while (size >0 ) { +if (size < segsize) { + segsize = size; + } + +snprintf (n,RBD_MAX_SEG_NAME_SIZE ,"%s.%012llx" , s->name, (long long unsigned int ) segnr); + acb->aiocnt++; +fprintf (stderr,"rbd_readv_bh_cb: aiocnt=%i: writing %s (segoffs: %lld, segsize %lld)\n" , acb->aiocnt, n, (long long int ) segoffs, (long long int ) segsize); +rados_aio_write (s->pool, n, segoffs, (char *) buf, segsize, &c); +rados_aio_set_callback (c, (rados_callback_t ) rbd_finish_aiocb, acb); + + buf += segsize; + size -= segsize; + segoffs =0 ; + segsize = s->objsize; + segnr++; + } + +return ; +} + +static void rbd_aio_cancel (BlockDriverAIOCB *blockacb) { +// Do we have to implement canceling? Seems to work without... +} + +static AIOPool rbd_aio_pool = { + .aiocb_size =sizeof (RBDAIOCB ), + .cancel = rbd_aio_cancel, +}; + +static RBDAIOCB *rbd_aio_setup (BlockDriverState *bs, +int write,QEMUIOVector *qiov, +int64_t sector_num,int nb_sectors, +BlockDriverCompletionFunc *cb, +void *opaque) { +RBDAIOCB *acb; + + acb =qemu_aio_get (&rbd_aio_pool, bs, cb, opaque); + acb->qiov = qiov; + acb->sector_num = sector_num; + acb->nb_sectors = nb_sectors; + acb->write = write; + acb->bh =NULL ; + acb->aiocnt =0 ; + +if (acb->buf) { +qemu_free (acb->buf); + } + acb->buf =qemu_malloc (nb_sectors *512 ); +if (write ==0 ) { +memset (acb->buf,0 , nb_sectors *512 ); + } + +return (acb); +} + +static BlockDriverAIOCB *rbd_aio_readv (BlockDriverState *bs, +int64_t sector_num,QEMUIOVector *qiov,int nb_sectors, +BlockDriverCompletionFunc *cb,void *opaque) +{ +RBDAIOCB *acb; + + acb =rbd_aio_setup (bs,0 , qiov, sector_num, nb_sectors, cb, opaque); + +rbd_schedule_bh (rbd_readv_bh_cb, acb); +return &acb->common; +} + + + +static BlockDriverAIOCB *rbd_aio_writev (BlockDriverState *bs, +int64_t sector_num, +QEMUIOVector *qiov, +int nb_sectors, +BlockDriverCompletionFunc *cb, +void *opaque) +{ +RBDAIOCB *acb; + + acb =rbd_aio_setup (bs,1 , qiov, sector_num, nb_sectors, cb, opaque); + +rbd_schedule_bh (rbd_writev_bh_cb, acb); +return &acb->common; +} + +static int rbd_getinfo (BlockDriverState *bs,BlockDriverInfo *bdi) {RBDRVRBDState *s = bs->opaque;
@@ -381,6 +578,9 @@ static BlockDriver bdrv_rbd = { .create_options = rbd_create_options, .bdrv_getlength = rbd_getlength, .protocol_name = "rbd", + + .bdrv_aio_readv = rbd_aio_readv, + .bdrv_aio_writev= rbd_aio_writev, };static void bdrv_rbd_init (void ) {
@@ -389,4 +589,3 @@ static void bdrv_rbd_init(void) {block_init (bdrv_rbd_init); -
Re: qemu-kvm/rbd: first attempt to implement aio
Quoted 9 lines · Christian Brunner
To increase the performance of the qemu rbd driver I started to implement aio functions. Attached is an intial aio implementation. However it is missing the callback of
rados_aio_reador_writefrom time to time. This leads to a lockup of the disk driver until the guest OS is perfomring a bus reset.If someone has an explanation for the cause of the lost callbacks. I would be happy.
Yeah, it looks like the rados aio interface is racy. You should be able to first set aio completion and only then to do the read/write and not the other way around as it is now. I've just pushed a fix to the unstable branch that changes the interface a bit. Now you first need to do a rados_aio_create_completion() first and use it in the rados_aio_read()/write() call. Note that I haven't tested it yet, so let me know if there's any problem.
Thanks,
Yehuda
AW: qemu-kvm/rbd: first attempt to implement aio
Quoted 10 lines
Yeah, it looks like the rados aio interface is racy. You should be able to first set aio completion and only then to do the read/write and not the other way around as it is now. I've just pushed a fix to the unstable branch that changes the interface a bit. Now you first need to do a
rados_aio_create_completion()first and use it in the rados_aio_read()/write() call. Note that I haven't tested it yet, so let me know if there's any problem.Thanks,
Yehuda
Thank you - the race condition seems to be fixed.
I'm still experiencing some cases where the callback function is being called a few hundred times, but I've to dig into this a little bit, before I can tell about it.
Christian