[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-block] [PULL 30/76] block: avoid unnecessary bottom halves
From: |
Kevin Wolf |
Subject: |
[Qemu-block] [PULL 30/76] block: avoid unnecessary bottom halves |
Date: |
Tue, 28 Apr 2015 17:00:12 +0200 |
From: Paolo Bonzini <address@hidden>
bdrv_aio_* APIs can use coroutines to achieve asynchronicity. However,
the coroutine may terminate without having yielded back to the caller
(for example because of something that invokes a nested event loop,
or because the coroutine is doing nothing at all). In this case,
the bdrv_aio_* API must delay the completion to the next iteration
of the main loop, because bdrv_aio_* will never invoke the callback
before returning.
This can be done with a bottom half, and indeed bdrv_aio_* is always
using one for simplicity. It is possible to gain some performance
(~3%) by avoiding this in the common case. A new field in the
BlockAIOCBCoroutine struct is set to true until the first time the
corotine has yielded to its creator, and completion goes through a
new function bdrv_co_complete. If the flag is false, bdrv_co_complete
invokes the callback immediately. If it is true, the caller will
notice that the coroutine has completed and schedule the bottom
half itself.
Signed-off-by: Paolo Bonzini <address@hidden>
Reviewed-by: Stefan Hajnoczi <address@hidden>
Message-id: address@hidden
Signed-off-by: Stefan Hajnoczi <address@hidden>
Signed-off-by: Kevin Wolf <address@hidden>
---
block.c | 43 ++++++++++++++++++++++++++++++++++---------
1 file changed, 34 insertions(+), 9 deletions(-)
diff --git a/block.c b/block.c
index 70aed80..d13b2e7 100644
--- a/block.c
+++ b/block.c
@@ -4849,6 +4849,7 @@ typedef struct BlockAIOCBCoroutine {
BlockAIOCB common;
BlockRequest req;
bool is_write;
+ bool need_bh;
bool *done;
QEMUBH* bh;
} BlockAIOCBCoroutine;
@@ -4857,14 +4858,32 @@ static const AIOCBInfo bdrv_em_co_aiocb_info = {
.aiocb_size = sizeof(BlockAIOCBCoroutine),
};
+static void bdrv_co_complete(BlockAIOCBCoroutine *acb)
+{
+ if (!acb->need_bh) {
+ acb->common.cb(acb->common.opaque, acb->req.error);
+ qemu_aio_unref(acb);
+ }
+}
+
static void bdrv_co_em_bh(void *opaque)
{
BlockAIOCBCoroutine *acb = opaque;
- acb->common.cb(acb->common.opaque, acb->req.error);
-
+ assert(!acb->need_bh);
qemu_bh_delete(acb->bh);
- qemu_aio_unref(acb);
+ bdrv_co_complete(acb);
+}
+
+static void bdrv_co_maybe_schedule_bh(BlockAIOCBCoroutine *acb)
+{
+ acb->need_bh = false;
+ if (acb->req.error != -EINPROGRESS) {
+ BlockDriverState *bs = acb->common.bs;
+
+ acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
+ qemu_bh_schedule(acb->bh);
+ }
}
/* Invoke bdrv_co_do_readv/bdrv_co_do_writev */
@@ -4881,8 +4900,7 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque)
acb->req.nb_sectors, acb->req.qiov, acb->req.flags);
}
- acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
- qemu_bh_schedule(acb->bh);
+ bdrv_co_complete(acb);
}
static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
@@ -4898,6 +4916,8 @@ static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState
*bs,
BlockAIOCBCoroutine *acb;
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
+ acb->need_bh = true;
+ acb->req.error = -EINPROGRESS;
acb->req.sector = sector_num;
acb->req.nb_sectors = nb_sectors;
acb->req.qiov = qiov;
@@ -4907,6 +4927,7 @@ static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState
*bs,
co = qemu_coroutine_create(bdrv_co_do_rw);
qemu_coroutine_enter(co, acb);
+ bdrv_co_maybe_schedule_bh(acb);
return &acb->common;
}
@@ -4916,8 +4937,7 @@ static void coroutine_fn bdrv_aio_flush_co_entry(void
*opaque)
BlockDriverState *bs = acb->common.bs;
acb->req.error = bdrv_co_flush(bs);
- acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
- qemu_bh_schedule(acb->bh);
+ bdrv_co_complete(acb);
}
BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs,
@@ -4929,10 +4949,13 @@ BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs,
BlockAIOCBCoroutine *acb;
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
+ acb->need_bh = true;
+ acb->req.error = -EINPROGRESS;
co = qemu_coroutine_create(bdrv_aio_flush_co_entry);
qemu_coroutine_enter(co, acb);
+ bdrv_co_maybe_schedule_bh(acb);
return &acb->common;
}
@@ -4942,8 +4965,7 @@ static void coroutine_fn bdrv_aio_discard_co_entry(void
*opaque)
BlockDriverState *bs = acb->common.bs;
acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors);
- acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
- qemu_bh_schedule(acb->bh);
+ bdrv_co_complete(acb);
}
BlockAIOCB *bdrv_aio_discard(BlockDriverState *bs,
@@ -4956,11 +4978,14 @@ BlockAIOCB *bdrv_aio_discard(BlockDriverState *bs,
trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque);
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
+ acb->need_bh = true;
+ acb->req.error = -EINPROGRESS;
acb->req.sector = sector_num;
acb->req.nb_sectors = nb_sectors;
co = qemu_coroutine_create(bdrv_aio_discard_co_entry);
qemu_coroutine_enter(co, acb);
+ bdrv_co_maybe_schedule_bh(acb);
return &acb->common;
}
--
1.8.3.1
- [Qemu-block] [PULL 22/76] scripts: add 'qemu coroutine' command to qemu-gdb.py, (continued)
- [Qemu-block] [PULL 22/76] scripts: add 'qemu coroutine' command to qemu-gdb.py, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 25/76] MAINTAINERS: Add Fam Zheng as Null block driver maintainer, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 24/76] block/null: Support reopen, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 23/76] block/null: Latency simulation by adding new option "latency-ns", Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 26/76] blockjob: Allow nested pause, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 27/76] block: Pause block jobs in bdrv_drain_all, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 28/76] qemu-iotests: Test that "stop" doesn't drain block jobs, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 31/76] virtio_blk: comment fix, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 29/76] blockjob: Update function name in comments, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 32/76] m25p80: add missing blk_attach_dev_nofail, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 30/76] block: avoid unnecessary bottom halves,
Kevin Wolf <=
- [Qemu-block] [PULL 33/76] m25p80: fix s->blk usage before assignment, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 34/76] block: document block-stream in qmp-commands.hx, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 35/76] block: add bdrv_get_device_or_node_name(), Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 36/76] block: use bdrv_get_device_or_node_name() in error messages, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 37/76] block: add 'node-name' field to BLOCK_IMAGE_CORRUPTED, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 38/76] Revert "hmp: fix crash in 'info block -n -v'", Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 39/76] qmp: fill in the image field in BlockDeviceInfo, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 40/76] block/iscsi: do not forget to logout from target, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 41/76] block/iscsi: change all iscsilun properties from uint8_t to bool, Kevin Wolf, 2015/04/28
- [Qemu-block] [PULL 42/76] block/iscsi: rename iscsi_write_protected and let it return void, Kevin Wolf, 2015/04/28