block: plug whole tree at once, introduce bdrv_io_unplugged_begin/end

Extract the handling of io_plug "depth" from linux-aio.c and let the
main bdrv_drain loop do nothing but wait on I/O.

Like the two newly introduced functions, bdrv_io_plug and bdrv_io_unplug
now operate on all children.  The visit order is now symmetrical between
plug and unplug, making it possible for formats to implement plug/unplug.

Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Paolo Bonzini 2016-04-07 18:33:34 +02:00 committed by Kevin Wolf
parent ce0f141259
commit 6b98bd6495
6 changed files with 71 additions and 44 deletions

View file

@ -253,7 +253,6 @@ static void bdrv_drain_poll(BlockDriverState *bs)
while (busy) { while (busy) {
/* Keep iterating */ /* Keep iterating */
bdrv_flush_io_queue(bs);
busy = bdrv_requests_pending(bs); busy = bdrv_requests_pending(bs);
busy |= aio_poll(bdrv_get_aio_context(bs), busy); busy |= aio_poll(bdrv_get_aio_context(bs), busy);
} }
@ -307,20 +306,24 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs)
void coroutine_fn bdrv_co_drain(BlockDriverState *bs) void coroutine_fn bdrv_co_drain(BlockDriverState *bs)
{ {
bdrv_no_throttling_begin(bs); bdrv_no_throttling_begin(bs);
bdrv_io_unplugged_begin(bs);
bdrv_drain_recurse(bs); bdrv_drain_recurse(bs);
bdrv_co_yield_to_drain(bs); bdrv_co_yield_to_drain(bs);
bdrv_io_unplugged_end(bs);
bdrv_no_throttling_end(bs); bdrv_no_throttling_end(bs);
} }
void bdrv_drain(BlockDriverState *bs) void bdrv_drain(BlockDriverState *bs)
{ {
bdrv_no_throttling_begin(bs); bdrv_no_throttling_begin(bs);
bdrv_io_unplugged_begin(bs);
bdrv_drain_recurse(bs); bdrv_drain_recurse(bs);
if (qemu_in_coroutine()) { if (qemu_in_coroutine()) {
bdrv_co_yield_to_drain(bs); bdrv_co_yield_to_drain(bs);
} else { } else {
bdrv_drain_poll(bs); bdrv_drain_poll(bs);
} }
bdrv_io_unplugged_end(bs);
bdrv_no_throttling_end(bs); bdrv_no_throttling_end(bs);
} }
@ -345,6 +348,7 @@ void bdrv_drain_all(void)
block_job_pause(bs->job); block_job_pause(bs->job);
} }
bdrv_no_throttling_begin(bs); bdrv_no_throttling_begin(bs);
bdrv_io_unplugged_begin(bs);
bdrv_drain_recurse(bs); bdrv_drain_recurse(bs);
aio_context_release(aio_context); aio_context_release(aio_context);
@ -369,7 +373,6 @@ void bdrv_drain_all(void)
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
while ((bs = bdrv_next(bs))) { while ((bs = bdrv_next(bs))) {
if (aio_context == bdrv_get_aio_context(bs)) { if (aio_context == bdrv_get_aio_context(bs)) {
bdrv_flush_io_queue(bs);
if (bdrv_requests_pending(bs)) { if (bdrv_requests_pending(bs)) {
busy = true; busy = true;
aio_poll(aio_context, busy); aio_poll(aio_context, busy);
@ -386,6 +389,7 @@ void bdrv_drain_all(void)
AioContext *aio_context = bdrv_get_aio_context(bs); AioContext *aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
bdrv_io_unplugged_end(bs);
bdrv_no_throttling_end(bs); bdrv_no_throttling_end(bs);
if (bs->job) { if (bs->job) {
block_job_resume(bs->job); block_job_resume(bs->job);
@ -2756,31 +2760,67 @@ void bdrv_add_before_write_notifier(BlockDriverState *bs,
void bdrv_io_plug(BlockDriverState *bs) void bdrv_io_plug(BlockDriverState *bs)
{ {
BlockDriver *drv = bs->drv; BdrvChild *child;
if (drv && drv->bdrv_io_plug) {
drv->bdrv_io_plug(bs); QLIST_FOREACH(child, &bs->children, next) {
} else if (bs->file) { bdrv_io_plug(child->bs);
bdrv_io_plug(bs->file->bs); }
if (bs->io_plugged++ == 0 && bs->io_plug_disabled == 0) {
BlockDriver *drv = bs->drv;
if (drv && drv->bdrv_io_plug) {
drv->bdrv_io_plug(bs);
}
} }
} }
void bdrv_io_unplug(BlockDriverState *bs) void bdrv_io_unplug(BlockDriverState *bs)
{ {
BlockDriver *drv = bs->drv; BdrvChild *child;
if (drv && drv->bdrv_io_unplug) {
drv->bdrv_io_unplug(bs); assert(bs->io_plugged);
} else if (bs->file) { if (--bs->io_plugged == 0 && bs->io_plug_disabled == 0) {
bdrv_io_unplug(bs->file->bs); BlockDriver *drv = bs->drv;
if (drv && drv->bdrv_io_unplug) {
drv->bdrv_io_unplug(bs);
}
}
QLIST_FOREACH(child, &bs->children, next) {
bdrv_io_unplug(child->bs);
} }
} }
void bdrv_flush_io_queue(BlockDriverState *bs) void bdrv_io_unplugged_begin(BlockDriverState *bs)
{ {
BlockDriver *drv = bs->drv; BdrvChild *child;
if (drv && drv->bdrv_flush_io_queue) {
drv->bdrv_flush_io_queue(bs); if (bs->io_plug_disabled++ == 0 && bs->io_plugged > 0) {
} else if (bs->file) { BlockDriver *drv = bs->drv;
bdrv_flush_io_queue(bs->file->bs); if (drv && drv->bdrv_io_unplug) {
drv->bdrv_io_unplug(bs);
}
}
QLIST_FOREACH(child, &bs->children, next) {
bdrv_io_unplugged_begin(child->bs);
}
}
void bdrv_io_unplugged_end(BlockDriverState *bs)
{
BdrvChild *child;
assert(bs->io_plug_disabled);
QLIST_FOREACH(child, &bs->children, next) {
bdrv_io_unplugged_end(child->bs);
}
if (--bs->io_plug_disabled == 0 && bs->io_plugged > 0) {
BlockDriver *drv = bs->drv;
if (drv && drv->bdrv_io_plug) {
drv->bdrv_io_plug(bs);
}
} }
} }

View file

@ -220,19 +220,16 @@ void laio_io_plug(BlockDriverState *bs, void *aio_ctx)
{ {
struct qemu_laio_state *s = aio_ctx; struct qemu_laio_state *s = aio_ctx;
s->io_q.plugged++; assert(!s->io_q.plugged);
s->io_q.plugged = 1;
} }
void laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug) void laio_io_unplug(BlockDriverState *bs, void *aio_ctx)
{ {
struct qemu_laio_state *s = aio_ctx; struct qemu_laio_state *s = aio_ctx;
assert(s->io_q.plugged > 0 || !unplug); assert(s->io_q.plugged);
s->io_q.plugged = 0;
if (unplug && --s->io_q.plugged > 0) {
return;
}
if (!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) { if (!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
ioq_submit(s); ioq_submit(s);
} }

View file

@ -43,7 +43,7 @@ BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
void laio_detach_aio_context(void *s, AioContext *old_context); void laio_detach_aio_context(void *s, AioContext *old_context);
void laio_attach_aio_context(void *s, AioContext *new_context); void laio_attach_aio_context(void *s, AioContext *new_context);
void laio_io_plug(BlockDriverState *bs, void *aio_ctx); void laio_io_plug(BlockDriverState *bs, void *aio_ctx);
void laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug); void laio_io_unplug(BlockDriverState *bs, void *aio_ctx);
#endif #endif
#ifdef _WIN32 #ifdef _WIN32

View file

@ -1345,17 +1345,7 @@ static void raw_aio_unplug(BlockDriverState *bs)
#ifdef CONFIG_LINUX_AIO #ifdef CONFIG_LINUX_AIO
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
if (s->use_aio) { if (s->use_aio) {
laio_io_unplug(bs, s->aio_ctx, true); laio_io_unplug(bs, s->aio_ctx);
}
#endif
}
static void raw_aio_flush_io_queue(BlockDriverState *bs)
{
#ifdef CONFIG_LINUX_AIO
BDRVRawState *s = bs->opaque;
if (s->use_aio) {
laio_io_unplug(bs, s->aio_ctx, false);
} }
#endif #endif
} }
@ -1949,7 +1939,6 @@ BlockDriver bdrv_file = {
.bdrv_refresh_limits = raw_refresh_limits, .bdrv_refresh_limits = raw_refresh_limits,
.bdrv_io_plug = raw_aio_plug, .bdrv_io_plug = raw_aio_plug,
.bdrv_io_unplug = raw_aio_unplug, .bdrv_io_unplug = raw_aio_unplug,
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
.bdrv_truncate = raw_truncate, .bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
@ -2398,7 +2387,6 @@ static BlockDriver bdrv_host_device = {
.bdrv_refresh_limits = raw_refresh_limits, .bdrv_refresh_limits = raw_refresh_limits,
.bdrv_io_plug = raw_aio_plug, .bdrv_io_plug = raw_aio_plug,
.bdrv_io_unplug = raw_aio_unplug, .bdrv_io_unplug = raw_aio_unplug,
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
.bdrv_truncate = raw_truncate, .bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
@ -2528,7 +2516,6 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_refresh_limits = raw_refresh_limits, .bdrv_refresh_limits = raw_refresh_limits,
.bdrv_io_plug = raw_aio_plug, .bdrv_io_plug = raw_aio_plug,
.bdrv_io_unplug = raw_aio_unplug, .bdrv_io_unplug = raw_aio_unplug,
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
.bdrv_truncate = raw_truncate, .bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,
@ -2664,7 +2651,6 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_refresh_limits = raw_refresh_limits, .bdrv_refresh_limits = raw_refresh_limits,
.bdrv_io_plug = raw_aio_plug, .bdrv_io_plug = raw_aio_plug,
.bdrv_io_unplug = raw_aio_unplug, .bdrv_io_unplug = raw_aio_unplug,
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
.bdrv_truncate = raw_truncate, .bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength, .bdrv_getlength = raw_getlength,

View file

@ -520,7 +520,8 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
void bdrv_io_plug(BlockDriverState *bs); void bdrv_io_plug(BlockDriverState *bs);
void bdrv_io_unplug(BlockDriverState *bs); void bdrv_io_unplug(BlockDriverState *bs);
void bdrv_flush_io_queue(BlockDriverState *bs); void bdrv_io_unplugged_begin(BlockDriverState *bs);
void bdrv_io_unplugged_end(BlockDriverState *bs);
/** /**
* bdrv_drained_begin: * bdrv_drained_begin:

View file

@ -294,7 +294,6 @@ struct BlockDriver {
/* io queue for linux-aio */ /* io queue for linux-aio */
void (*bdrv_io_plug)(BlockDriverState *bs); void (*bdrv_io_plug)(BlockDriverState *bs);
void (*bdrv_io_unplug)(BlockDriverState *bs); void (*bdrv_io_unplug)(BlockDriverState *bs);
void (*bdrv_flush_io_queue)(BlockDriverState *bs);
/** /**
* Try to get @bs's logical and physical block size. * Try to get @bs's logical and physical block size.
@ -484,6 +483,10 @@ struct BlockDriverState {
uint64_t write_threshold_offset; uint64_t write_threshold_offset;
NotifierWithReturn write_threshold_notifier; NotifierWithReturn write_threshold_notifier;
/* counters for nested bdrv_io_plug and bdrv_io_unplugged_begin */
unsigned io_plugged;
unsigned io_plug_disabled;
int quiesce_counter; int quiesce_counter;
}; };