diff --git a/block.c b/block.c index 8d9b9017d3..430edf79bb 100644 --- a/block.c +++ b/block.c @@ -6326,6 +6326,33 @@ void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx) bdrv_dec_in_flight(bs); } +void coroutine_fn bdrv_co_lock(BlockDriverState *bs) +{ + AioContext *ctx = bdrv_get_aio_context(bs); + + /* In the main thread, bs->aio_context won't change concurrently */ + assert(qemu_get_current_aio_context() == qemu_get_aio_context()); + + /* + * We're in coroutine context, so we already hold the lock of the main + * loop AioContext. Don't lock it twice to avoid deadlocks. + */ + assert(qemu_in_coroutine()); + if (ctx != qemu_get_aio_context()) { + aio_context_acquire(ctx); + } +} + +void coroutine_fn bdrv_co_unlock(BlockDriverState *bs) +{ + AioContext *ctx = bdrv_get_aio_context(bs); + + assert(qemu_in_coroutine()); + if (ctx != qemu_get_aio_context()) { + aio_context_release(ctx); + } +} + void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co) { aio_co_enter(bdrv_get_aio_context(bs), co); diff --git a/include/block/block.h b/include/block/block.h index 1027c58a41..d16c401cb4 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -657,6 +657,20 @@ AioContext *coroutine_fn bdrv_co_enter(BlockDriverState *bs); */ void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx); +/** + * Locks the AioContext of @bs if it's not the current AioContext. This avoids + * double locking which could lead to deadlocks: This is a coroutine_fn, so we + * know we already own the lock of the current AioContext. + * + * May only be called in the main thread. + */ +void coroutine_fn bdrv_co_lock(BlockDriverState *bs); + +/** + * Unlocks the AioContext of @bs if it's not the current AioContext. + */ +void coroutine_fn bdrv_co_unlock(BlockDriverState *bs); + /** * Transfer control to @co in the aio context of @bs */