aboutsummaryrefslogtreecommitdiff
path: root/blockdev.c
diff options
context:
space:
mode:
authorFiona Ebner <f.ebner@proxmox.com>2023-10-19 15:19:36 +0200
committerKevin Wolf <kwolf@redhat.com>2023-10-31 13:51:36 +0100
commit302823854b078f0525cf1babcc4fc9ff7b7d5f71 (patch)
tree12ffe2f508a27a27404bd8ae1aa1d0c9c23d215a /blockdev.c
parente462c6d27d0175a67cd373b3027ea5276d25dd4e (diff)
blockdev: mirror: avoid potential deadlock when using iothread
The bdrv_getlength() function is a generated co-wrapper and uses AIO_WAIT_WHILE() to wait for the spawned coroutine. AIO_WAIT_WHILE() expects the lock to be acquired exactly once. Fix a case where it may be acquired twice. This can happen when the source node is explicitly specified as the @replaces parameter or if the source node is a filter node. Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> Message-ID: <20231019131936.414246-4-f.ebner@proxmox.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'blockdev.c')
-rw-r--r--blockdev.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/blockdev.c b/blockdev.c
index a01c62596b..877e3a26d4 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2968,6 +2968,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
if (replaces) {
BlockDriverState *to_replace_bs;
+ AioContext *aio_context;
AioContext *replace_aio_context;
int64_t bs_size, replace_size;
@@ -2982,10 +2983,19 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
return;
}
+ aio_context = bdrv_get_aio_context(bs);
replace_aio_context = bdrv_get_aio_context(to_replace_bs);
- aio_context_acquire(replace_aio_context);
+ /*
+ * bdrv_getlength() is a co-wrapper and uses AIO_WAIT_WHILE. Be sure not
+ * to acquire the same AioContext twice.
+ */
+ if (replace_aio_context != aio_context) {
+ aio_context_acquire(replace_aio_context);
+ }
replace_size = bdrv_getlength(to_replace_bs);
- aio_context_release(replace_aio_context);
+ if (replace_aio_context != aio_context) {
+ aio_context_release(replace_aio_context);
+ }
if (replace_size < 0) {
error_setg_errno(errp, -replace_size,