block: Avoid processing BDS twice in bdrv_set_aio_context_ignore()
Some graphs may contain an indirect reference to the first BDS in the chain that can be reached while walking it bottom->up from one its children. Doubling-processing of a BDS is especially problematic for the aio_notifiers, as they might attempt to work on both the old and the new AIO contexts. To avoid this problem, add every child and parent to the ignore list before actually processing them. Suggested-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Sergio Lopez <slp@redhat.com> Message-Id: <20210201125032.44713-2-slp@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
d7beddcc02
commit
722d8e73d6
34
block.c
34
block.c
@ -6439,7 +6439,10 @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs,
|
|||||||
AioContext *new_context, GSList **ignore)
|
AioContext *new_context, GSList **ignore)
|
||||||
{
|
{
|
||||||
AioContext *old_context = bdrv_get_aio_context(bs);
|
AioContext *old_context = bdrv_get_aio_context(bs);
|
||||||
BdrvChild *child;
|
GSList *children_to_process = NULL;
|
||||||
|
GSList *parents_to_process = NULL;
|
||||||
|
GSList *entry;
|
||||||
|
BdrvChild *child, *parent;
|
||||||
|
|
||||||
g_assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
g_assert(qemu_get_current_aio_context() == qemu_get_aio_context());
|
||||||
|
|
||||||
@ -6454,17 +6457,34 @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
*ignore = g_slist_prepend(*ignore, child);
|
*ignore = g_slist_prepend(*ignore, child);
|
||||||
bdrv_set_aio_context_ignore(child->bs, new_context, ignore);
|
children_to_process = g_slist_prepend(children_to_process, child);
|
||||||
}
|
}
|
||||||
QLIST_FOREACH(child, &bs->parents, next_parent) {
|
|
||||||
if (g_slist_find(*ignore, child)) {
|
QLIST_FOREACH(parent, &bs->parents, next_parent) {
|
||||||
|
if (g_slist_find(*ignore, parent)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
assert(child->klass->set_aio_ctx);
|
*ignore = g_slist_prepend(*ignore, parent);
|
||||||
*ignore = g_slist_prepend(*ignore, child);
|
parents_to_process = g_slist_prepend(parents_to_process, parent);
|
||||||
child->klass->set_aio_ctx(child, new_context, ignore);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (entry = children_to_process;
|
||||||
|
entry != NULL;
|
||||||
|
entry = g_slist_next(entry)) {
|
||||||
|
child = entry->data;
|
||||||
|
bdrv_set_aio_context_ignore(child->bs, new_context, ignore);
|
||||||
|
}
|
||||||
|
g_slist_free(children_to_process);
|
||||||
|
|
||||||
|
for (entry = parents_to_process;
|
||||||
|
entry != NULL;
|
||||||
|
entry = g_slist_next(entry)) {
|
||||||
|
parent = entry->data;
|
||||||
|
assert(parent->klass->set_aio_ctx);
|
||||||
|
parent->klass->set_aio_ctx(parent, new_context, ignore);
|
||||||
|
}
|
||||||
|
g_slist_free(parents_to_process);
|
||||||
|
|
||||||
bdrv_detach_aio_context(bs);
|
bdrv_detach_aio_context(bs);
|
||||||
|
|
||||||
/* Acquire the new context, if necessary */
|
/* Acquire the new context, if necessary */
|
||||||
|
Loading…
Reference in New Issue
Block a user