aboutsummaryrefslogtreecommitdiff
path: root/block.c
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2023-06-05 10:57:05 +0200
committerKevin Wolf <kwolf@redhat.com>2023-06-28 08:46:12 +0200
commitc066e808e11a5c181b625537b6c78e0de27a4801 (patch)
treeb1c4e1339d7f719bee86a86eed90fc9ee082b062 /block.c
parent8394c35ee14861e2dd2afb20b03036b86388e375 (diff)
block: Fix AioContext locking in bdrv_attach_child_common()
The function can move the child node to a different AioContext. In this case, it also must take the AioContext lock for the new context before calling functions that require the caller to hold the AioContext for the child node. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Message-ID: <20230605085711.21261-6-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'block.c')
-rw-r--r--block.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/block.c b/block.c
index 213a09643d..2c8a3ffe19 100644
--- a/block.c
+++ b/block.c
@@ -2989,6 +2989,10 @@ static TransactionActionDrv bdrv_attach_child_common_drv = {
* Function doesn't update permissions, caller is responsible for this.
*
* Returns new created child.
+ *
+ * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
+ * @child_bs can move to a different AioContext in this function. Callers must
+ * make sure that their AioContext locking is still correct after this.
*/
static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
const char *child_name,
@@ -2999,7 +3003,7 @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
Transaction *tran, Error **errp)
{
BdrvChild *new_child;
- AioContext *parent_ctx;
+ AioContext *parent_ctx, *new_child_ctx;
AioContext *child_ctx = bdrv_get_aio_context(child_bs);
assert(child_class->get_parent_desc);
@@ -3050,6 +3054,12 @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
}
}
+ new_child_ctx = bdrv_get_aio_context(child_bs);
+ if (new_child_ctx != child_ctx) {
+ aio_context_release(child_ctx);
+ aio_context_acquire(new_child_ctx);
+ }
+
bdrv_ref(child_bs);
/*
* Let every new BdrvChild start with a drained parent. Inserting the child
@@ -3079,11 +3089,20 @@ static BdrvChild *bdrv_attach_child_common(BlockDriverState *child_bs,
};
tran_add(tran, &bdrv_attach_child_common_drv, s);
+ if (new_child_ctx != child_ctx) {
+ aio_context_release(new_child_ctx);
+ aio_context_acquire(child_ctx);
+ }
+
return new_child;
}
/*
* Function doesn't update permissions, caller is responsible for this.
+ *
+ * The caller must hold the AioContext lock for @child_bs. Both @parent_bs and
+ * @child_bs can move to a different AioContext in this function. Callers must
+ * make sure that their AioContext locking is still correct after this.
*/
static BdrvChild *bdrv_attach_child_noperm(BlockDriverState *parent_bs,
BlockDriverState *child_bs,