From 9a3edf82a956d1c60c24491d368ca423de84ed92 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig <chellwig@redhat.com> Date: Tue, 24 Nov 2009 19:43:07 -0200 Subject: [PATCH 02/11] block: add aio_flush operation RH-Author: Christoph Hellwig <chellwig@redhat.com> Message-id: <1256889826.9905.4.camel@brick.lst.de> Patchwork-id: 3654 O-Subject: [PATCH 3/5] block: add aio_flush operation Bugzilla: 537646 RH-Acked-by: Rik van Riel <riel@redhat.com> RH-Acked-by: Kevin Wolf <kwolf@redhat.com> RH-Acked-by: Juan Quintela <quintela@redhat.com> commit b2e12bc6e304c17da0bee970fb4776d0731422e6 Author: Christoph Hellwig <hch@lst.de> Date: Fri Sep 4 19:01:49 2009 +0200 block: add aio_flush operation Instead stalling the VCPU while serving a cache flush try to do it asynchronously. Use our good old helper thread pool to issue an asynchronous fdatasync for raw-posix. Note that while Linux AIO implements a fdatasync operation it is not useful for us because it isn't actually implement in asynchronous fashion. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- qemu/block-raw-posix.c | 21 ++++++++++++++++++++- qemu/block.c | 37 +++++++++++++++++++++++++++++++++++++ qemu/block.h | 2 ++ qemu/block_int.h | 2 ++ qemu/posix-aio-compat.c | 31 +++++++++++++++++++++++++------ qemu/posix-aio-compat.h | 3 ++- 6 files changed, 88 insertions(+), 8 deletions(-) diff --git a/qemu/block-raw-posix.c b/qemu/block-raw-posix.c index 52ad357..1e46e03 100644 --- a/qemu/block-raw-posix.c +++ b/qemu/block-raw-posix.c @@ -663,6 +663,24 @@ static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs, return &acb->common; } +static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque) +{ + RawAIOCB *acb; + + if (fd_open(bs) < 0) + return NULL; + + acb = raw_aio_setup(bs, 0, NULL, 0, cb, opaque); + if (!acb) + return NULL; + if (qemu_paio_flush(&acb->aiocb) < 0) { + qemu_aio_release(acb); + return NULL; + } + return &acb->common; +} + static void raw_aio_cancel(BlockDriverAIOCB *blockacb) { int ret; @@ -696,7 +714,6 @@ static int posix_aio_init(void) } #endif /* CONFIG_AIO */ - static void raw_close(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; @@ -830,6 +847,7 @@ BlockDriver bdrv_raw = { #ifdef CONFIG_AIO .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, + .bdrv_aio_flush = raw_aio_flush, .bdrv_aio_cancel = raw_aio_cancel, .aiocb_size = sizeof(RawAIOCB), #endif @@ -1224,6 +1242,7 @@ BlockDriver bdrv_host_device = { #ifdef CONFIG_AIO .bdrv_aio_read = raw_aio_read, .bdrv_aio_write = raw_aio_write, + .bdrv_aio_flush = raw_aio_flush, .bdrv_aio_cancel = raw_aio_cancel, .aiocb_size = sizeof(RawAIOCB), #endif diff --git a/qemu/block.c b/qemu/block.c index 5967748..4f8b295 100644 --- a/qemu/block.c +++ b/qemu/block.c @@ -54,6 +54,8 @@ static BlockDriverAIOCB *bdrv_aio_read_em(BlockDriverState *bs, static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque); +static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque); static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb); static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); @@ -144,6 +146,10 @@ static void bdrv_register(BlockDriver *bdrv) bdrv->bdrv_read = bdrv_read_em; bdrv->bdrv_write = bdrv_write_em; } + + if (!bdrv->bdrv_aio_flush) + bdrv->bdrv_aio_flush = bdrv_aio_flush_em; + bdrv->next = first_drv; first_drv = bdrv; } @@ -1451,6 +1457,21 @@ BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, return ret; } +BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque) +{ + BlockDriver *drv = bs->drv; + + if (!drv) + return NULL; + + /* + * Note that unlike bdrv_flush the driver is reponsible for flushing a + * backing image if it exists. + */ + return drv->bdrv_aio_flush(bs, cb, opaque); +} + void bdrv_aio_cancel(BlockDriverAIOCB *acb) { BlockDriver *drv = acb->bs->drv; @@ -1501,6 +1522,22 @@ static BlockDriverAIOCB *bdrv_aio_write_em(BlockDriverState *bs, return &acb->common; } +static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque) +{ + BlockDriverAIOCBSync *acb; + + acb = qemu_aio_get(bs, cb, opaque); + acb->ret = 0; + + if (!acb->bh) + acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb); + + bdrv_flush(bs); + qemu_bh_schedule(acb->bh); + return &acb->common; +} + static void bdrv_aio_cancel_em(BlockDriverAIOCB *blockacb) { BlockDriverAIOCBSync *acb = (BlockDriverAIOCBSync *)blockacb; diff --git a/qemu/block.h b/qemu/block.h index 662082a..cab9cba 100644 --- a/qemu/block.h +++ b/qemu/block.h @@ -95,6 +95,8 @@ BlockDriverAIOCB *bdrv_aio_read(BlockDriverState *bs, int64_t sector_num, BlockDriverAIOCB *bdrv_aio_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque); +BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque); void bdrv_aio_cancel(BlockDriverAIOCB *acb); int qemu_key_check(BlockDriverState *bs, const char *name); diff --git a/qemu/block_int.h b/qemu/block_int.h index 1f77cf0..5334904 100644 --- a/qemu/block_int.h +++ b/qemu/block_int.h @@ -54,6 +54,8 @@ struct BlockDriver { BlockDriverAIOCB *(*bdrv_aio_write)(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque); + BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque); void (*bdrv_aio_cancel)(BlockDriverAIOCB *acb); int aiocb_size; diff --git a/qemu/posix-aio-compat.c b/qemu/posix-aio-compat.c index 394e807..6a718c0 100644 --- a/qemu/posix-aio-compat.c +++ b/qemu/posix-aio-compat.c @@ -15,6 +15,7 @@ #include <unistd.h> #include <errno.h> #include <sys/time.h> +#include <stdlib.h> #include "osdep.h" #include "posix-aio-compat.h" @@ -27,6 +28,10 @@ static int cur_threads = 0; static int idle_threads = 0; static TAILQ_HEAD(, qemu_paiocb) request_list; +#define QEMU_AIO_READ 0x0001 +#define QEMU_AIO_WRITE 0x0002 +#define QEMU_AIO_FLUSH 0x0008 + static void *aio_thread(void *unused) { sigset_t set; @@ -67,16 +72,25 @@ static void *aio_thread(void *unused) while (offset < aiocb->aio_nbytes) { ssize_t len; - if (aiocb->is_write) + switch (aiocb->aio_type) { + case QEMU_AIO_FLUSH: + len = fdatasync(aiocb->aio_fildes); + break; + case QEMU_AIO_WRITE: len = pwrite(aiocb->aio_fildes, (const char *)aiocb->aio_buf + offset, aiocb->aio_nbytes - offset, aiocb->aio_offset + offset); - else + break; + case QEMU_AIO_READ: len = pread(aiocb->aio_fildes, (char *)aiocb->aio_buf + offset, aiocb->aio_nbytes - offset, aiocb->aio_offset + offset); + break; + default: + abort(); + } if (len == -1 && errno == EINTR) continue; @@ -129,9 +143,9 @@ int qemu_paio_init(struct qemu_paioinit *aioinit) return 0; } -static int qemu_paio_submit(struct qemu_paiocb *aiocb, int is_write) +static int qemu_paio_submit(struct qemu_paiocb *aiocb, int aio_type) { - aiocb->is_write = is_write; + aiocb->aio_type = aio_type; aiocb->ret = -EINPROGRESS; aiocb->active = 0; pthread_mutex_lock(&lock); @@ -146,12 +160,17 @@ static int qemu_paio_submit(struct qemu_paiocb *aiocb, int is_write) int qemu_paio_read(struct qemu_paiocb *aiocb) { - return qemu_paio_submit(aiocb, 0); + return qemu_paio_submit(aiocb, QEMU_AIO_READ); } int qemu_paio_write(struct qemu_paiocb *aiocb) { - return qemu_paio_submit(aiocb, 1); + return qemu_paio_submit(aiocb, QEMU_AIO_WRITE); +} + +int qemu_paio_flush(struct qemu_paiocb *aiocb) +{ + return qemu_paio_submit(aiocb, QEMU_AIO_FLUSH); } ssize_t qemu_paio_return(struct qemu_paiocb *aiocb) diff --git a/qemu/posix-aio-compat.h b/qemu/posix-aio-compat.h index 5dddd71..56acaa0 100644 --- a/qemu/posix-aio-compat.h +++ b/qemu/posix-aio-compat.h @@ -34,7 +34,7 @@ struct qemu_paiocb /* private */ TAILQ_ENTRY(qemu_paiocb) node; - int is_write; + int aio_type; ssize_t ret; int active; }; @@ -49,6 +49,7 @@ struct qemu_paioinit int qemu_paio_init(struct qemu_paioinit *aioinit); int qemu_paio_read(struct qemu_paiocb *aiocb); int qemu_paio_write(struct qemu_paiocb *aiocb); +int qemu_paio_flush(struct qemu_paiocb *aiocb); int qemu_paio_error(struct qemu_paiocb *aiocb); ssize_t qemu_paio_return(struct qemu_paiocb *aiocb); int qemu_paio_cancel(int fd, struct qemu_paiocb *aiocb); -- 1.6.3.rc4.29.g8146