block: Defer .bdrv_drain_begin callback to polling phase
We cannot allow aio_poll() in bdrv_drain_invoke(begin=true) until we're done with propagating the drain through the graph and are doing the single final BDRV_POLL_WHILE(). Just schedule the coroutine with the callback and increase bs->in_flight to make sure that the polling phase will wait for it. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
231281ab42
commit
0109e7e6f8
28
block/io.c
28
block/io.c
@ -182,22 +182,40 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
|
||||
|
||||
/* Set data->done before reading bs->wakeup. */
|
||||
atomic_mb_set(&data->done, true);
|
||||
bdrv_wakeup(bs);
|
||||
bdrv_dec_in_flight(bs);
|
||||
|
||||
if (data->begin) {
|
||||
g_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
|
||||
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin)
|
||||
{
|
||||
BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin};
|
||||
BdrvCoDrainData *data;
|
||||
|
||||
if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) ||
|
||||
(!begin && !bs->drv->bdrv_co_drain_end)) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data);
|
||||
bdrv_coroutine_enter(bs, data.co);
|
||||
BDRV_POLL_WHILE(bs, !data.done);
|
||||
data = g_new(BdrvCoDrainData, 1);
|
||||
*data = (BdrvCoDrainData) {
|
||||
.bs = bs,
|
||||
.done = false,
|
||||
.begin = begin
|
||||
};
|
||||
|
||||
/* Make sure the driver callback completes during the polling phase for
|
||||
* drain_begin. */
|
||||
bdrv_inc_in_flight(bs);
|
||||
data->co = qemu_coroutine_create(bdrv_drain_invoke_entry, data);
|
||||
aio_co_schedule(bdrv_get_aio_context(bs), data->co);
|
||||
|
||||
if (!begin) {
|
||||
BDRV_POLL_WHILE(bs, !data->done);
|
||||
g_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */
|
||||
|
Loading…
x
Reference in New Issue
Block a user