mirror of https://github.com/xemu-project/xemu.git
block: Revert .bdrv_drained_begin/end to non-coroutine_fn
Polling during bdrv_drained_end() can be problematic (and in the future, we may get cases for bdrv_drained_begin() where polling is forbidden, and we don't care about already in-flight requests, but just want to prevent new requests from arriving). The .bdrv_drained_begin/end callbacks running in a coroutine is the only reason why we have to do this polling, so make them non-coroutine callbacks again. None of the callers actually yield any more. This means that bdrv_drained_end() effectively doesn't poll any more, even if AIO_WAIT_WHILE() loops are still there (their condition is false from the beginning). This is generally not a problem, but in test-bdrv-drain, some additional explicit aio_poll() calls need to be added because the test case wants to verify the final state after BHs have executed. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> Reviewed-by: Hanna Reitz <hreitz@redhat.com> Message-Id: <20221118174110.55183-4-kwolf@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
7bce1c2998
commit
5e8ac21717
4
block.c
4
block.c
|
@ -1713,8 +1713,8 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
|
||||||
assert(is_power_of_2(bs->bl.request_alignment));
|
assert(is_power_of_2(bs->bl.request_alignment));
|
||||||
|
|
||||||
for (i = 0; i < bs->quiesce_counter; i++) {
|
for (i = 0; i < bs->quiesce_counter; i++) {
|
||||||
if (drv->bdrv_co_drain_begin) {
|
if (drv->bdrv_drain_begin) {
|
||||||
drv->bdrv_co_drain_begin(bs);
|
drv->bdrv_drain_begin(bs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
49
block/io.c
49
block/io.c
|
@ -252,55 +252,20 @@ typedef struct {
|
||||||
int *drained_end_counter;
|
int *drained_end_counter;
|
||||||
} BdrvCoDrainData;
|
} BdrvCoDrainData;
|
||||||
|
|
||||||
static void coroutine_fn bdrv_drain_invoke_entry(void *opaque)
|
/* Recursively call BlockDriver.bdrv_drain_begin/end callbacks */
|
||||||
{
|
|
||||||
BdrvCoDrainData *data = opaque;
|
|
||||||
BlockDriverState *bs = data->bs;
|
|
||||||
|
|
||||||
if (data->begin) {
|
|
||||||
bs->drv->bdrv_co_drain_begin(bs);
|
|
||||||
} else {
|
|
||||||
bs->drv->bdrv_co_drain_end(bs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set data->done and decrement drained_end_counter before bdrv_wakeup() */
|
|
||||||
qatomic_mb_set(&data->done, true);
|
|
||||||
if (!data->begin) {
|
|
||||||
qatomic_dec(data->drained_end_counter);
|
|
||||||
}
|
|
||||||
bdrv_dec_in_flight(bs);
|
|
||||||
|
|
||||||
g_free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */
|
|
||||||
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin,
|
static void bdrv_drain_invoke(BlockDriverState *bs, bool begin,
|
||||||
int *drained_end_counter)
|
int *drained_end_counter)
|
||||||
{
|
{
|
||||||
BdrvCoDrainData *data;
|
if (!bs->drv || (begin && !bs->drv->bdrv_drain_begin) ||
|
||||||
|
(!begin && !bs->drv->bdrv_drain_end)) {
|
||||||
if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) ||
|
|
||||||
(!begin && !bs->drv->bdrv_co_drain_end)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = g_new(BdrvCoDrainData, 1);
|
if (begin) {
|
||||||
*data = (BdrvCoDrainData) {
|
bs->drv->bdrv_drain_begin(bs);
|
||||||
.bs = bs,
|
} else {
|
||||||
.done = false,
|
bs->drv->bdrv_drain_end(bs);
|
||||||
.begin = begin,
|
|
||||||
.drained_end_counter = drained_end_counter,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!begin) {
|
|
||||||
qatomic_inc(drained_end_counter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */
|
/* Returns true if BDRV_POLL_WHILE() should go into a blocking aio_poll() */
|
||||||
|
|
|
@ -262,7 +262,7 @@ static bool coroutine_fn qed_plug_allocating_write_reqs(BDRVQEDState *s)
|
||||||
assert(!s->allocating_write_reqs_plugged);
|
assert(!s->allocating_write_reqs_plugged);
|
||||||
if (s->allocating_acb != NULL) {
|
if (s->allocating_acb != NULL) {
|
||||||
/* Another allocating write came concurrently. This cannot happen
|
/* Another allocating write came concurrently. This cannot happen
|
||||||
* from bdrv_qed_co_drain_begin, but it can happen when the timer runs.
|
* from bdrv_qed_drain_begin, but it can happen when the timer runs.
|
||||||
*/
|
*/
|
||||||
qemu_co_mutex_unlock(&s->table_lock);
|
qemu_co_mutex_unlock(&s->table_lock);
|
||||||
return false;
|
return false;
|
||||||
|
@ -365,7 +365,7 @@ static void bdrv_qed_attach_aio_context(BlockDriverState *bs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coroutine_fn bdrv_qed_co_drain_begin(BlockDriverState *bs)
|
static void bdrv_qed_drain_begin(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVQEDState *s = bs->opaque;
|
BDRVQEDState *s = bs->opaque;
|
||||||
|
|
||||||
|
@ -1661,7 +1661,7 @@ static BlockDriver bdrv_qed = {
|
||||||
.bdrv_co_check = bdrv_qed_co_check,
|
.bdrv_co_check = bdrv_qed_co_check,
|
||||||
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
|
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
|
||||||
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
|
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
|
||||||
.bdrv_co_drain_begin = bdrv_qed_co_drain_begin,
|
.bdrv_drain_begin = bdrv_qed_drain_begin,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bdrv_qed_init(void)
|
static void bdrv_qed_init(void)
|
||||||
|
|
|
@ -214,7 +214,7 @@ static void throttle_reopen_abort(BDRVReopenState *reopen_state)
|
||||||
reopen_state->opaque = NULL;
|
reopen_state->opaque = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coroutine_fn throttle_co_drain_begin(BlockDriverState *bs)
|
static void throttle_drain_begin(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
ThrottleGroupMember *tgm = bs->opaque;
|
ThrottleGroupMember *tgm = bs->opaque;
|
||||||
if (qatomic_fetch_inc(&tgm->io_limits_disabled) == 0) {
|
if (qatomic_fetch_inc(&tgm->io_limits_disabled) == 0) {
|
||||||
|
@ -222,7 +222,7 @@ static void coroutine_fn throttle_co_drain_begin(BlockDriverState *bs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs)
|
static void throttle_drain_end(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
ThrottleGroupMember *tgm = bs->opaque;
|
ThrottleGroupMember *tgm = bs->opaque;
|
||||||
assert(tgm->io_limits_disabled);
|
assert(tgm->io_limits_disabled);
|
||||||
|
@ -261,8 +261,8 @@ static BlockDriver bdrv_throttle = {
|
||||||
.bdrv_reopen_commit = throttle_reopen_commit,
|
.bdrv_reopen_commit = throttle_reopen_commit,
|
||||||
.bdrv_reopen_abort = throttle_reopen_abort,
|
.bdrv_reopen_abort = throttle_reopen_abort,
|
||||||
|
|
||||||
.bdrv_co_drain_begin = throttle_co_drain_begin,
|
.bdrv_drain_begin = throttle_drain_begin,
|
||||||
.bdrv_co_drain_end = throttle_co_drain_end,
|
.bdrv_drain_end = throttle_drain_end,
|
||||||
|
|
||||||
.is_filter = true,
|
.is_filter = true,
|
||||||
.strong_runtime_opts = throttle_strong_runtime_opts,
|
.strong_runtime_opts = throttle_strong_runtime_opts,
|
||||||
|
|
|
@ -735,17 +735,19 @@ struct BlockDriver {
|
||||||
void (*bdrv_io_unplug)(BlockDriverState *bs);
|
void (*bdrv_io_unplug)(BlockDriverState *bs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bdrv_co_drain_begin is called if implemented in the beginning of a
|
* bdrv_drain_begin is called if implemented in the beginning of a
|
||||||
* drain operation to drain and stop any internal sources of requests in
|
* drain operation to drain and stop any internal sources of requests in
|
||||||
* the driver.
|
* the driver.
|
||||||
* bdrv_co_drain_end is called if implemented at the end of the drain.
|
* bdrv_drain_end is called if implemented at the end of the drain.
|
||||||
*
|
*
|
||||||
* They should be used by the driver to e.g. manage scheduled I/O
|
* They should be used by the driver to e.g. manage scheduled I/O
|
||||||
* requests, or toggle an internal state. After the end of the drain new
|
* requests, or toggle an internal state. After the end of the drain new
|
||||||
* requests will continue normally.
|
* requests will continue normally.
|
||||||
|
*
|
||||||
|
* Implementations of both functions must not call aio_poll().
|
||||||
*/
|
*/
|
||||||
void coroutine_fn (*bdrv_co_drain_begin)(BlockDriverState *bs);
|
void (*bdrv_drain_begin)(BlockDriverState *bs);
|
||||||
void coroutine_fn (*bdrv_co_drain_end)(BlockDriverState *bs);
|
void (*bdrv_drain_end)(BlockDriverState *bs);
|
||||||
|
|
||||||
bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs);
|
bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs);
|
||||||
bool coroutine_fn (*bdrv_co_can_store_new_dirty_bitmap)(
|
bool coroutine_fn (*bdrv_co_can_store_new_dirty_bitmap)(
|
||||||
|
|
|
@ -46,7 +46,7 @@ static void coroutine_fn sleep_in_drain_begin(void *opaque)
|
||||||
bdrv_dec_in_flight(bs);
|
bdrv_dec_in_flight(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
|
static void bdrv_test_drain_begin(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVTestState *s = bs->opaque;
|
BDRVTestState *s = bs->opaque;
|
||||||
s->drain_count++;
|
s->drain_count++;
|
||||||
|
@ -57,7 +57,7 @@ static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs)
|
static void bdrv_test_drain_end(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVTestState *s = bs->opaque;
|
BDRVTestState *s = bs->opaque;
|
||||||
s->drain_count--;
|
s->drain_count--;
|
||||||
|
@ -111,8 +111,8 @@ static BlockDriver bdrv_test = {
|
||||||
.bdrv_close = bdrv_test_close,
|
.bdrv_close = bdrv_test_close,
|
||||||
.bdrv_co_preadv = bdrv_test_co_preadv,
|
.bdrv_co_preadv = bdrv_test_co_preadv,
|
||||||
|
|
||||||
.bdrv_co_drain_begin = bdrv_test_co_drain_begin,
|
.bdrv_drain_begin = bdrv_test_drain_begin,
|
||||||
.bdrv_co_drain_end = bdrv_test_co_drain_end,
|
.bdrv_drain_end = bdrv_test_drain_end,
|
||||||
|
|
||||||
.bdrv_child_perm = bdrv_default_perms,
|
.bdrv_child_perm = bdrv_default_perms,
|
||||||
|
|
||||||
|
@ -1703,6 +1703,7 @@ static void test_blockjob_commit_by_drained_end(void)
|
||||||
bdrv_drained_begin(bs_child);
|
bdrv_drained_begin(bs_child);
|
||||||
g_assert(!job_has_completed);
|
g_assert(!job_has_completed);
|
||||||
bdrv_drained_end(bs_child);
|
bdrv_drained_end(bs_child);
|
||||||
|
aio_poll(qemu_get_aio_context(), false);
|
||||||
g_assert(job_has_completed);
|
g_assert(job_has_completed);
|
||||||
|
|
||||||
bdrv_unref(bs_parents[0]);
|
bdrv_unref(bs_parents[0]);
|
||||||
|
@ -1858,6 +1859,7 @@ static void test_drop_intermediate_poll(void)
|
||||||
|
|
||||||
g_assert(!job_has_completed);
|
g_assert(!job_has_completed);
|
||||||
ret = bdrv_drop_intermediate(chain[1], chain[0], NULL);
|
ret = bdrv_drop_intermediate(chain[1], chain[0], NULL);
|
||||||
|
aio_poll(qemu_get_aio_context(), false);
|
||||||
g_assert(ret == 0);
|
g_assert(ret == 0);
|
||||||
g_assert(job_has_completed);
|
g_assert(job_has_completed);
|
||||||
|
|
||||||
|
@ -1946,7 +1948,7 @@ static void coroutine_fn bdrv_replace_test_drain_co(void *opaque)
|
||||||
* .was_drained.
|
* .was_drained.
|
||||||
* Increment .drain_count.
|
* Increment .drain_count.
|
||||||
*/
|
*/
|
||||||
static void coroutine_fn bdrv_replace_test_co_drain_begin(BlockDriverState *bs)
|
static void bdrv_replace_test_drain_begin(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVReplaceTestState *s = bs->opaque;
|
BDRVReplaceTestState *s = bs->opaque;
|
||||||
|
|
||||||
|
@ -1977,7 +1979,7 @@ static void coroutine_fn bdrv_replace_test_read_entry(void *opaque)
|
||||||
* If .drain_count reaches 0 and the node has a backing file, issue a
|
* If .drain_count reaches 0 and the node has a backing file, issue a
|
||||||
* read request.
|
* read request.
|
||||||
*/
|
*/
|
||||||
static void coroutine_fn bdrv_replace_test_co_drain_end(BlockDriverState *bs)
|
static void bdrv_replace_test_drain_end(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVReplaceTestState *s = bs->opaque;
|
BDRVReplaceTestState *s = bs->opaque;
|
||||||
|
|
||||||
|
@ -2002,8 +2004,8 @@ static BlockDriver bdrv_replace_test = {
|
||||||
.bdrv_close = bdrv_replace_test_close,
|
.bdrv_close = bdrv_replace_test_close,
|
||||||
.bdrv_co_preadv = bdrv_replace_test_co_preadv,
|
.bdrv_co_preadv = bdrv_replace_test_co_preadv,
|
||||||
|
|
||||||
.bdrv_co_drain_begin = bdrv_replace_test_co_drain_begin,
|
.bdrv_drain_begin = bdrv_replace_test_drain_begin,
|
||||||
.bdrv_co_drain_end = bdrv_replace_test_co_drain_end,
|
.bdrv_drain_end = bdrv_replace_test_drain_end,
|
||||||
|
|
||||||
.bdrv_child_perm = bdrv_default_perms,
|
.bdrv_child_perm = bdrv_default_perms,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue