It's safer to expand in_flight request to start before enter to coroutine in synchronous wrappers and end after BDRV_POLL_WHILE loop. Note that qemu_coroutine_enter may only schedule the coroutine in some circumstances.
bdrv_make_zero update includes refactoring: move the whole loop into coroutine, which has additional benefit of not create/enter new coroutine on each iteration. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsement...@virtuozzo.com> --- block/io.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/block/io.c b/block/io.c index d2ac9ac7b5..220b5c04d7 100644 --- a/block/io.c +++ b/block/io.c @@ -2735,8 +2735,11 @@ bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, * BDRV_REQ_FUA). * * Returns < 0 on error, 0 on success. For error codes see bdrv_write(). + * + * To be called between exactly one pair of bdrv_inc/dec_in_flight() */ -int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) +static int coroutine_fn +bdrv_do_make_zero(BdrvChild *child, BdrvRequestFlags flags) { int ret; int64_t target_size, bytes, offset = 0; @@ -2752,7 +2755,8 @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) if (bytes <= 0) { return 0; } - ret = bdrv_block_status(bs, offset, bytes, &bytes, NULL, NULL); + ret = bdrv_co_block_status(bs, true, false, + offset, bytes, &bytes, NULL, NULL); if (ret < 0) { return ret; } @@ -2760,7 +2764,7 @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) offset += bytes; continue; } - ret = bdrv_pwrite_zeroes(child, offset, bytes, flags); + ret = bdrv_do_pwrite_zeroes(child, offset, bytes, flags); if (ret < 0) { return ret; } @@ -2768,6 +2772,49 @@ int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) } } +typedef struct BdrvDoMakeZeroData { + BdrvChild *child; + BdrvRequestFlags flags; + int ret; + bool done; +} BdrvDoMakeZeroData; + +static void coroutine_fn bdrv_make_zero_co_entry(void *opaque) +{ + BdrvDoMakeZeroData *data = opaque; + + data->ret = bdrv_do_make_zero(data->child, data->flags); + data->done = true; + aio_wait_kick(); +} + +int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags) +{ + int ret; + + bdrv_inc_in_flight(child->bs); + + if (qemu_in_coroutine()) { + /* Fast-path if already in coroutine context */ + ret = bdrv_do_make_zero(child, flags); + } else { + BdrvDoMakeZeroData data = { + .child = child, + .flags = flags, + .done = false, + }; + Coroutine *co = qemu_coroutine_create(bdrv_make_zero_co_entry, &data); + + bdrv_coroutine_enter(child->bs, co); + BDRV_POLL_WHILE(child->bs, !data.done); + ret = data.ret; + } + + bdrv_dec_in_flight(child->bs); + + return ret; +} + typedef struct BdrvVmstateCo { BlockDriverState *bs; QEMUIOVector *qiov; -- 2.21.0