block: Don't poll in parent drain callbacks
bdrv_do_drained_begin() is only safe if we have a single BDRV_POLL_WHILE() after quiescing all affected nodes. We cannot allow that parent callbacks introduce a nested polling loop that could cause graph changes while we're traversing the graph. Split off bdrv_do_drained_begin_quiesce(), which only quiesces a single node without waiting for its requests to complete. These requests will be waited for in the BDRV_POLL_WHILE() call down the call chain. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
ebd3183761
commit
dcf94a23b1
2
block.c
2
block.c
@ -818,7 +818,7 @@ static char *bdrv_child_get_parent_desc(BdrvChild *c)
|
|||||||
static void bdrv_child_cb_drained_begin(BdrvChild *child)
|
static void bdrv_child_cb_drained_begin(BdrvChild *child)
|
||||||
{
|
{
|
||||||
BlockDriverState *bs = child->opaque;
|
BlockDriverState *bs = child->opaque;
|
||||||
bdrv_drained_begin(bs);
|
bdrv_do_drained_begin_quiesce(bs, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bdrv_child_cb_drained_poll(BdrvChild *child)
|
static bool bdrv_child_cb_drained_poll(BdrvChild *child)
|
||||||
|
24
block/io.c
24
block/io.c
@ -286,15 +286,10 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
|
|||||||
assert(data.done);
|
assert(data.done);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
|
void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
|
||||||
BdrvChild *parent, bool poll)
|
BdrvChild *parent)
|
||||||
{
|
{
|
||||||
BdrvChild *child, *next;
|
assert(!qemu_in_coroutine());
|
||||||
|
|
||||||
if (qemu_in_coroutine()) {
|
|
||||||
bdrv_co_yield_to_drain(bs, true, recursive, parent, poll);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop things in parent-to-child order */
|
/* Stop things in parent-to-child order */
|
||||||
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
|
if (atomic_fetch_inc(&bs->quiesce_counter) == 0) {
|
||||||
@ -303,6 +298,19 @@ void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
|
|||||||
|
|
||||||
bdrv_parent_drained_begin(bs, parent);
|
bdrv_parent_drained_begin(bs, parent);
|
||||||
bdrv_drain_invoke(bs, true);
|
bdrv_drain_invoke(bs, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive,
|
||||||
|
BdrvChild *parent, bool poll)
|
||||||
|
{
|
||||||
|
BdrvChild *child, *next;
|
||||||
|
|
||||||
|
if (qemu_in_coroutine()) {
|
||||||
|
bdrv_co_yield_to_drain(bs, true, recursive, parent, poll);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdrv_do_drained_begin_quiesce(bs, parent);
|
||||||
|
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
bs->recursive_quiesce_counter++;
|
bs->recursive_quiesce_counter++;
|
||||||
|
@ -590,6 +590,15 @@ bool bdrv_drain_poll(BlockDriverState *bs, bool recursive,
|
|||||||
*/
|
*/
|
||||||
void bdrv_drained_begin(BlockDriverState *bs);
|
void bdrv_drained_begin(BlockDriverState *bs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdrv_do_drained_begin_quiesce:
|
||||||
|
*
|
||||||
|
* Quiesces a BDS like bdrv_drained_begin(), but does not wait for already
|
||||||
|
* running requests to complete.
|
||||||
|
*/
|
||||||
|
void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
|
||||||
|
BdrvChild *parent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like bdrv_drained_begin, but recursively begins a quiesced section for
|
* Like bdrv_drained_begin, but recursively begins a quiesced section for
|
||||||
* exclusive access to all child nodes as well.
|
* exclusive access to all child nodes as well.
|
||||||
|
Loading…
Reference in New Issue
Block a user