aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2020-10-05 17:58:53 +0200
committerMarkus Armbruster <armbru@redhat.com>2020-10-09 07:08:20 +0200
commite336fd4c4b2fa04e5d6c7f8ee524bfd2d9e9e8f1 (patch)
tree5e067cd1cc99e744e2eea9eac4cdb58904e564aa
parent26b0b698c00bd9176f86c539aeb680481fa19473 (diff)
block: Add bdrv_co_enter()/leave()
Add a pair of functions to temporarily move the current coroutine to the AioContext of a given BlockDriverState. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Message-Id: <20201005155855.256490-13-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
-rw-r--r--block.c23
-rw-r--r--include/block/block.h17
2 files changed, 40 insertions, 0 deletions
diff --git a/block.c b/block.c
index 52b2e2709f..8d9b9017d3 100644
--- a/block.c
+++ b/block.c
@@ -6303,6 +6303,29 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs)
return bs ? bs->aio_context : qemu_get_aio_context();
}
+AioContext *coroutine_fn bdrv_co_enter(BlockDriverState *bs)
+{
+ Coroutine *self = qemu_coroutine_self();
+ AioContext *old_ctx = qemu_coroutine_get_aio_context(self);
+ AioContext *new_ctx;
+
+ /*
+ * Increase bs->in_flight to ensure that this operation is completed before
+ * moving the node to a different AioContext. Read new_ctx only afterwards.
+ */
+ bdrv_inc_in_flight(bs);
+
+ new_ctx = bdrv_get_aio_context(bs);
+ aio_co_reschedule_self(new_ctx);
+ return old_ctx;
+}
+
+void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx)
+{
+ aio_co_reschedule_self(old_ctx);
+ bdrv_dec_in_flight(bs);
+}
+
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 ce2ac39299..1027c58a41 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -641,6 +641,23 @@ bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag);
AioContext *bdrv_get_aio_context(BlockDriverState *bs);
/**
+ * Move the current coroutine to the AioContext of @bs and return the old
+ * AioContext of the coroutine. Increase bs->in_flight so that draining @bs
+ * will wait for the operation to proceed until the corresponding
+ * bdrv_co_leave().
+ *
+ * Consequently, you can't call drain inside a bdrv_co_enter/leave() section as
+ * this will deadlock.
+ */
+AioContext *coroutine_fn bdrv_co_enter(BlockDriverState *bs);
+
+/**
+ * Ends a section started by bdrv_co_enter(). Move the current coroutine back
+ * to old_ctx and decrease bs->in_flight again.
+ */
+void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx);
+
+/**
* Transfer control to @co in the aio context of @bs
*/
void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co);