summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block.c57
-rw-r--r--include/block/block.h11
-rw-r--r--include/block/block_int.h36
3 files changed, 102 insertions, 2 deletions
diff --git a/block.c b/block.c
index 87da79fbe8..1fd38159e2 100644
--- a/block.c
+++ b/block.c
@@ -363,6 +363,7 @@ BlockDriverState *bdrv_new(const char *device_name, Error **errp)
qemu_co_queue_init(&bs->throttled_reqs[0]);
qemu_co_queue_init(&bs->throttled_reqs[1]);
bs->refcnt = 1;
+ bs->aio_context = qemu_get_aio_context();
return bs;
}
@@ -5661,8 +5662,60 @@ out:
AioContext *bdrv_get_aio_context(BlockDriverState *bs)
{
- /* Currently BlockDriverState always uses the main loop AioContext */
- return qemu_get_aio_context();
+ return bs->aio_context;
+}
+
+void bdrv_detach_aio_context(BlockDriverState *bs)
+{
+ if (!bs->drv) {
+ return;
+ }
+
+ if (bs->drv->bdrv_detach_aio_context) {
+ bs->drv->bdrv_detach_aio_context(bs);
+ }
+ if (bs->file) {
+ bdrv_detach_aio_context(bs->file);
+ }
+ if (bs->backing_hd) {
+ bdrv_detach_aio_context(bs->backing_hd);
+ }
+
+ bs->aio_context = NULL;
+}
+
+void bdrv_attach_aio_context(BlockDriverState *bs,
+ AioContext *new_context)
+{
+ if (!bs->drv) {
+ return;
+ }
+
+ bs->aio_context = new_context;
+
+ if (bs->backing_hd) {
+ bdrv_attach_aio_context(bs->backing_hd, new_context);
+ }
+ if (bs->file) {
+ bdrv_attach_aio_context(bs->file, new_context);
+ }
+ if (bs->drv->bdrv_attach_aio_context) {
+ bs->drv->bdrv_attach_aio_context(bs, new_context);
+ }
+}
+
+void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
+{
+ bdrv_drain_all(); /* ensure there are no in-flight requests */
+
+ bdrv_detach_aio_context(bs);
+
+ /* This function executes in the old AioContext so acquire the new one in
+ * case it runs in a different thread.
+ */
+ aio_context_acquire(new_context);
+ bdrv_attach_aio_context(bs, new_context);
+ aio_context_release(new_context);
}
void bdrv_add_before_write_notifier(BlockDriverState *bs,
diff --git a/include/block/block.h b/include/block/block.h
index faee3aa246..292754f9fe 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -574,4 +574,15 @@ int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag);
int bdrv_debug_resume(BlockDriverState *bs, const char *tag);
bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag);
+/**
+ * bdrv_set_aio_context:
+ *
+ * Changes the #AioContext used for fd handlers, timers, and BHs by this
+ * BlockDriverState and all its children.
+ *
+ * This function must be called from the old #AioContext or with a lock held so
+ * the old #AioContext is not executing.
+ */
+void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
+
#endif
diff --git a/include/block/block_int.h b/include/block/block_int.h
index f2e753f632..93ec86f3f7 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -247,6 +247,19 @@ struct BlockDriver {
*/
int (*bdrv_has_zero_init)(BlockDriverState *bs);
+ /* Remove fd handlers, timers, and other event loop callbacks so the event
+ * loop is no longer in use. Called with no in-flight requests and in
+ * depth-first traversal order with parents before child nodes.
+ */
+ void (*bdrv_detach_aio_context)(BlockDriverState *bs);
+
+ /* Add fd handlers, timers, and other event loop callbacks so I/O requests
+ * can be processed again. Called with no in-flight requests and in
+ * depth-first traversal order with child nodes before parent nodes.
+ */
+ void (*bdrv_attach_aio_context)(BlockDriverState *bs,
+ AioContext *new_context);
+
QLIST_ENTRY(BlockDriver) list;
};
@@ -297,6 +310,8 @@ struct BlockDriverState {
const BlockDevOps *dev_ops;
void *dev_opaque;
+ AioContext *aio_context; /* event loop used for fd handlers, timers, etc */
+
char filename[1024];
char backing_file[1024]; /* if non zero, the image is a diff of
this file image */
@@ -396,6 +411,27 @@ void bdrv_add_before_write_notifier(BlockDriverState *bs,
*/
AioContext *bdrv_get_aio_context(BlockDriverState *bs);
+/**
+ * bdrv_detach_aio_context:
+ *
+ * May be called from .bdrv_detach_aio_context() to detach children from the
+ * current #AioContext. This is only needed by block drivers that manage their
+ * own children. Both ->file and ->backing_hd are automatically handled and
+ * block drivers should not call this function on them explicitly.
+ */
+void bdrv_detach_aio_context(BlockDriverState *bs);
+
+/**
+ * bdrv_attach_aio_context:
+ *
+ * May be called from .bdrv_attach_aio_context() to attach children to the new
+ * #AioContext. This is only needed by block drivers that manage their own
+ * children. Both ->file and ->backing_hd are automatically handled and block
+ * drivers should not call this function on them explicitly.
+ */
+void bdrv_attach_aio_context(BlockDriverState *bs,
+ AioContext *new_context);
+
#ifdef _WIN32
int is_windows_drive(const char *filename);
#endif