From 0db52fa2553ba83454a347e0aca4896e1b0d9b41 Mon Sep 17 00:00:00 2001 From: Sergio Lopez Pascual Date: Thu, 11 Feb 2021 14:42:06 -0300 Subject: [PATCH 4/6] block: Avoid processing BDS twice in bdrv_set_aio_context_ignore() RH-Author: Sergio Lopez Pascual Message-id: <20210211144208.58930-4-slp@redhat.com> Patchwork-id: 101050 O-Subject: [RHEL-AV-8.4.0 qemu-kvm PATCH 3/5] block: Avoid processing BDS twice in bdrv_set_aio_context_ignore() Bugzilla: 1918966 1918968 RH-Acked-by: Max Reitz RH-Acked-by: Kevin Wolf RH-Acked-by: Eric Blake 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 Signed-off-by: Sergio Lopez Message-Id: <20210201125032.44713-2-slp@redhat.com> Signed-off-by: Kevin Wolf (cherry picked from commit 722d8e73d65cb54f39d360ecb2147ac58f43c399) Signed-off-by: Sergio Lopez Signed-off-by: Eduardo Lima (Etrunko) --- block.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/block.c b/block.c index f1cedac362..8bfa446f9c 100644 --- a/block.c +++ b/block.c @@ -6454,7 +6454,10 @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs, AioContext *new_context, GSList **ignore) { 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()); @@ -6469,16 +6472,33 @@ void bdrv_set_aio_context_ignore(BlockDriverState *bs, continue; } *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; } - assert(child->klass->set_aio_ctx); - *ignore = g_slist_prepend(*ignore, child); - child->klass->set_aio_ctx(child, new_context, ignore); + *ignore = g_slist_prepend(*ignore, parent); + parents_to_process = g_slist_prepend(parents_to_process, parent); + } + + 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); -- 2.27.0