* [PATCH V11 01/15] qapi/misc: Fix missed query-iothreads items
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-06 20:25 ` [PATCH V11 02/15] iothread: introduce holder tracking Zhang Chen
` (13 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen, qemu-stable
The example is incomplete: it misses members @poll-max-ns, @poll-grow,
@poll-shrink, @aio-max-batch. Messed up in commit 5fc00480ab1
(monitor: add poll-* properties into query-iothreads result) and
commit 1793ad0247c (iothread: add aio-max-batch parameter).
cc: qemu-stable@nongnu.org
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
qapi/misc.json | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/qapi/misc.json b/qapi/misc.json
index 22b7afed9f..c71a5fe657 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -123,11 +123,19 @@
# <- { "return": [
# {
# "id":"iothread0",
-# "thread-id":3134
+# "thread-id":3134,
+# "poll-max-ns":32768,
+# "poll-grow":0,
+# "poll-shrink":0,
+# "aio-max-batch":0
# },
# {
# "id":"iothread1",
-# "thread-id":3135
+# "thread-id":3135,
+# "poll-max-ns":32768,
+# "poll-grow":0,
+# "poll-shrink":0,
+# "aio-max-batch":0
# }
# ]
# }
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH V11 02/15] iothread: introduce holder tracking
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
2026-08-06 20:25 ` [PATCH V11 01/15] qapi/misc: Fix missed query-iothreads items Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-07 13:36 ` Markus Armbruster
2026-08-06 20:25 ` [PATCH V11 03/15] iothread: track users with holder name Zhang Chen
` (12 subsequent siblings)
14 siblings, 1 reply; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
IOThreads do not record the QOM objects and block exports that use
them, making runtime introspection and hotplug debugging difficult.
Add:
- holders: a list describing what is holding an iothread
- iothread_ref(): add a holder to the list
- iothread_unref(): remove a holder from the list
A holder can identify either a QOM object or a block export. A later
patch will expose this information through query-iothreads.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/system/iothread.h | 5 +++
iothread.c | 63 ++++++++++++++++++++++++++
qapi/misc.json | 94 ++++++++++++++++++++++++++++++++++-----
3 files changed, 150 insertions(+), 12 deletions(-)
diff --git a/include/system/iothread.h b/include/system/iothread.h
index a1ef7696cb..b8aeb32b0e 100644
--- a/include/system/iothread.h
+++ b/include/system/iothread.h
@@ -18,6 +18,7 @@
#include "qemu/thread.h"
#include "qom/object.h"
#include "system/event-loop-base.h"
+#include "qapi/qapi-types-misc.h"
#define TYPE_IOTHREAD "iothread"
@@ -50,6 +51,7 @@ struct IOThread {
bool stopping; /* has iothread_stop() been called? */
bool running; /* should iothread_run() continue? */
int thread_id;
+ IOThreadHolderList *holders;
/* AioContext poll parameters */
int64_t poll_max_ns;
@@ -82,4 +84,7 @@ void iothread_destroy(IOThread *iothread);
*/
bool qemu_in_iothread(void);
+void iothread_ref(IOThread *iothread, const IOThreadHolder *holder);
+void iothread_unref(IOThread *iothread, const IOThreadHolder *holder);
+
#endif /* IOTHREAD_H */
diff --git a/iothread.c b/iothread.c
index 3558535b40..2a4c92e08b 100644
--- a/iothread.c
+++ b/iothread.c
@@ -21,10 +21,71 @@
#include "system/iothread.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-misc.h"
+#include "qapi/clone-visitor.h"
+#include "qapi/qapi-visit-misc.h"
#include "qemu/error-report.h"
#include "qemu/rcu.h"
#include "qemu/main-loop.h"
+/* Add a deep copy of @holder to @iothread's list of holders. */
+void iothread_ref(IOThread *iothread, const IOThreadHolder *holder)
+{
+ assert(holder);
+
+ QAPI_LIST_PREPEND(iothread->holders, QAPI_CLONE(IOThreadHolder, holder));
+}
+
+static int iothread_holder_compare(const IOThreadHolder *holder_a,
+ const IOThreadHolder *holder_b)
+{
+ const char *name_a, *name_b;
+
+ if (holder_a->type != holder_b->type) {
+ return holder_b->type - holder_a->type;
+ }
+
+ switch (holder_a->type) {
+ case IO_THREAD_HOLDER_KIND_QOM_OBJECT:
+ name_a = holder_a->u.qom_object.qom_path;
+ name_b = holder_b->u.qom_object.qom_path;
+ break;
+ case IO_THREAD_HOLDER_KIND_BLOCK_EXPORT:
+ name_a = holder_a->u.block_export.export_id;
+ name_b = holder_b->u.block_export.export_id;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return strcmp(name_a, name_b);
+}
+
+/*
+ * Remove @holder from @iothread's list of holders.
+ *
+ * It is a programming error if @holder is not present.
+ */
+void iothread_unref(IOThread *iothread, const IOThreadHolder *holder)
+{
+ IOThreadHolderList **prev = &iothread->holders;
+ IOThreadHolderList *curr;
+
+ assert(holder);
+
+ while (*prev) {
+ curr = *prev;
+ if (iothread_holder_compare(curr->value, holder) == 0) {
+ *prev = curr->next;
+ curr->next = NULL;
+ qapi_free_IOThreadHolderList(curr);
+ return;
+ }
+ prev = &curr->next;
+ }
+
+ g_assert_not_reached();
+}
+
static void *iothread_run(void *opaque)
{
IOThread *iothread = opaque;
@@ -129,6 +190,7 @@ static void iothread_instance_finalize(Object *obj)
iothread->main_loop = NULL;
}
qemu_sem_destroy(&iothread->init_done_sem);
+ qapi_free_IOThreadHolderList(iothread->holders);
}
static void iothread_init_gcontext(IOThread *iothread, const char *thread_name)
@@ -373,6 +435,7 @@ static int query_one_iothread(Object *object, void *opaque)
info = g_new0(IOThreadInfo, 1);
info->id = iothread_get_id(iothread);
info->thread_id = iothread->thread_id;
+ info->holders = QAPI_CLONE(IOThreadHolderList, iothread->holders);
info->poll_max_ns = iothread->poll_max_ns;
info->poll_grow = iothread->poll_grow;
info->poll_shrink = iothread->poll_shrink;
diff --git a/qapi/misc.json b/qapi/misc.json
index c71a5fe657..eb3b89293d 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -67,6 +67,55 @@
##
{ 'command': 'query-name', 'returns': 'NameInfo', 'allow-preconfig': true }
+##
+# @IOThreadHolderBlockExport:
+#
+# @export-id: The unique block export identifier.
+#
+# Since: 11.2
+#
+##
+{ 'struct': 'IOThreadHolderBlockExport',
+ 'data': { 'export-id': 'str' } }
+
+##
+# @IOThreadHolderQomObject:
+#
+# @qom-path: Path to the object in the QOM tree.
+#
+# Since: 11.2
+#
+##
+{ 'struct': 'IOThreadHolderQomObject',
+ 'data': { 'qom-path': 'str' } }
+
+##
+# @IOThreadHolderKind:
+#
+# @block-export: A block export.
+# @qom-object: A QOM object.
+#
+# Since: 11.2
+##
+{ 'enum': 'IOThreadHolderKind',
+ 'data': [ 'block-export', 'qom-object' ] }
+
+##
+# @IOThreadHolder:
+#
+# The block export or QOM object holding the iothread.
+#
+# @type: the kind of iothread holder.
+#
+# Since: 11.2
+##
+{ 'union': 'IOThreadHolder',
+ 'base': { 'type': 'IOThreadHolderKind' },
+ 'discriminator': 'type',
+ 'data': {
+ 'block-export': 'IOThreadHolderBlockExport',
+ 'qom-object': 'IOThreadHolderQomObject' } }
+
##
# @IOThreadInfo:
#
@@ -76,6 +125,10 @@
#
# @thread-id: ID of the underlying host thread
#
+# @holders: the QOM objects or block exports currently holding this
+# iothread. When a holder is detached or destroyed, it is removed
+# from this list. (Since 11.2)
+#
# @poll-max-ns: maximum polling time in ns, 0 means polling is
# disabled (since 2.9)
#
@@ -98,6 +151,7 @@
{ 'struct': 'IOThreadInfo',
'data': {'id': 'str',
'thread-id': 'int',
+ 'holders': ['IOThreadHolder'],
'poll-max-ns': 'int',
'poll-grow': 'int',
'poll-shrink': 'int',
@@ -122,20 +176,36 @@
# -> { "execute": "query-iothreads" }
# <- { "return": [
# {
-# "id":"iothread0",
-# "thread-id":3134,
-# "poll-max-ns":32768,
-# "poll-grow":0,
-# "poll-shrink":0,
-# "aio-max-batch":0
+# "id": "iothread0",
+# "thread-id": 3134,
+# "holders": [
+# {
+# "qom-path": "/machine/peripheral/blk1/virtio-backend",
+# "type": "qom-object"
+# },
+# {
+# "qom-path": "/machine/peripheral/blk2/virtio-backend",
+# "type": "qom-object"
+# }
+# ],
+# "poll-max-ns": 32768,
+# "poll-grow": 0,
+# "poll-shrink": 0,
+# "aio-max-batch": 0
# },
# {
-# "id":"iothread1",
-# "thread-id":3135,
-# "poll-max-ns":32768,
-# "poll-grow":0,
-# "poll-shrink":0,
-# "aio-max-batch":0
+# "id": "iothread1",
+# "thread-id": 3135,
+# "holders": [
+# {
+# "export-id": "export0",
+# "type": "block-export"
+# }
+# ],
+# "poll-max-ns": 32768,
+# "poll-grow": 0,
+# "poll-shrink": 0,
+# "aio-max-batch": 0
# }
# ]
# }
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH V11 02/15] iothread: introduce holder tracking
2026-08-06 20:25 ` [PATCH V11 02/15] iothread: introduce holder tracking Zhang Chen
@ 2026-08-07 13:36 ` Markus Armbruster
0 siblings, 0 replies; 22+ messages in thread
From: Markus Armbruster @ 2026-08-07 13:36 UTC (permalink / raw)
To: Zhang Chen
Cc: qemu-devel, Eric Blake, Michael S . Tsirkin, Stefan Hajnoczi,
Paolo Bonzini, 'Daniel P . Berrangé', Jason Wang
Zhang Chen <zhangckid@gmail.com> writes:
> IOThreads do not record the QOM objects and block exports that use
> them, making runtime introspection and hotplug debugging difficult.
>
> Add:
>
> - holders: a list describing what is holding an iothread
> - iothread_ref(): add a holder to the list
> - iothread_unref(): remove a holder from the list
>
> A holder can identify either a QOM object or a block export. A later
> patch will expose this information through query-iothreads.
>
> Signed-off-by: Zhang Chen <zhangckid@gmail.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V11 03/15] iothread: track users with holder name
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
2026-08-06 20:25 ` [PATCH V11 01/15] qapi/misc: Fix missed query-iothreads items Zhang Chen
2026-08-06 20:25 ` [PATCH V11 02/15] iothread: introduce holder tracking Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-07 13:41 ` Markus Armbruster
2026-08-06 20:25 ` [PATCH V11 04/15] iothread: introduce iothread_unsafe_get_aio_context() Zhang Chen
` (11 subsequent siblings)
14 siblings, 1 reply; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Introduce iothread_ref_and_get_aio_context() with a holder argument
and its counterpart iothread_put_aio_context().
Previously, users of an IOThread AioContext did not explicitly record
their identity, making it difficult to debug which devices or
subsystems were pinning an IOThread.
Registering a holder takes an IOThread object reference so that the
IOThread and its AioContext stay alive until the matching put
operation. Document the ownership and BQL requirements.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
include/system/iothread.h | 21 +++++++++++++++++++++
iothread.c | 23 ++++++++++++++++++++++-
2 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/include/system/iothread.h b/include/system/iothread.h
index b8aeb32b0e..b6664e7a38 100644
--- a/include/system/iothread.h
+++ b/include/system/iothread.h
@@ -67,6 +67,27 @@ DECLARE_INSTANCE_CHECKER(IOThread, IOTHREAD,
char *iothread_get_id(IOThread *iothread);
IOThread *iothread_by_id(const char *id);
AioContext *iothread_get_aio_context(IOThread *iothread);
+
+/*
+ * Register @holder and return @iothread's AioContext. The holder is copied,
+ * and a reference is taken on @iothread so that both the IOThread and its
+ * AioContext remain alive.
+ *
+ * The caller must eventually call iothread_put_aio_context() with an
+ * equivalent holder. This function is not thread-safe and must be called
+ * under the Big QEMU Lock (BQL).
+ */
+AioContext *iothread_ref_and_get_aio_context(IOThread *iothread,
+ const IOThreadHolder *holder);
+
+/*
+ * Unregister @holder and release the corresponding reference on @iothread.
+ * Calling this function without a matching
+ * iothread_ref_and_get_aio_context() call is a programming error.
+ *
+ * This function is not thread-safe and must be called under the BQL.
+ */
+void iothread_put_aio_context(IOThread *iothread, const IOThreadHolder *holder);
GMainContext *iothread_get_g_main_context(IOThread *iothread);
/*
diff --git a/iothread.c b/iothread.c
index 2a4c92e08b..0cc8344ee6 100644
--- a/iothread.c
+++ b/iothread.c
@@ -33,6 +33,11 @@ void iothread_ref(IOThread *iothread, const IOThreadHolder *holder)
assert(holder);
QAPI_LIST_PREPEND(iothread->holders, QAPI_CLONE(IOThreadHolder, holder));
+ /*
+ * This guarantees that the IOThread and its AioContext remain alive
+ * as long as there is a holder.
+ */
+ object_ref(OBJECT(iothread));
}
static int iothread_holder_compare(const IOThreadHolder *holder_a,
@@ -78,6 +83,7 @@ void iothread_unref(IOThread *iothread, const IOThreadHolder *holder)
*prev = curr->next;
curr->next = NULL;
qapi_free_IOThreadHolderList(curr);
+ object_unref(OBJECT(iothread));
return;
}
prev = &curr->next;
@@ -199,7 +205,7 @@ static void iothread_init_gcontext(IOThread *iothread, const char *thread_name)
g_autofree char *name = g_strdup_printf("%s aio-context", thread_name);
iothread->worker_context = g_main_context_new();
- source = aio_get_g_source(iothread_get_aio_context(iothread));
+ source = aio_get_g_source(iothread->ctx);
g_source_set_name(source, name);
g_source_attach(source, iothread->worker_context);
g_source_unref(source);
@@ -421,6 +427,21 @@ AioContext *iothread_get_aio_context(IOThread *iothread)
return iothread->ctx;
}
+AioContext *iothread_ref_and_get_aio_context(IOThread *iothread,
+ const IOThreadHolder *holder)
+{
+ /* Add IOThreadHolder to the list */
+ iothread_ref(iothread, holder);
+
+ return iothread->ctx;
+}
+
+void iothread_put_aio_context(IOThread *iothread, const IOThreadHolder *holder)
+{
+ /* Delete IOThreadHolder from the list */
+ iothread_unref(iothread, holder);
+}
+
static int query_one_iothread(Object *object, void *opaque)
{
IOThreadInfoList ***tail = opaque;
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH V11 03/15] iothread: track users with holder name
2026-08-06 20:25 ` [PATCH V11 03/15] iothread: track users with holder name Zhang Chen
@ 2026-08-07 13:41 ` Markus Armbruster
2026-08-11 8:51 ` Zhang Chen
0 siblings, 1 reply; 22+ messages in thread
From: Markus Armbruster @ 2026-08-07 13:41 UTC (permalink / raw)
To: Zhang Chen
Cc: qemu-devel, Eric Blake, Michael S . Tsirkin, Stefan Hajnoczi,
Paolo Bonzini, 'Daniel P . Berrangé', Jason Wang
Zhang Chen <zhangckid@gmail.com> writes:
> Introduce iothread_ref_and_get_aio_context() with a holder argument
> and its counterpart iothread_put_aio_context().
>
> Previously, users of an IOThread AioContext did not explicitly record
> their identity, making it difficult to debug which devices or
> subsystems were pinning an IOThread.
>
> Registering a holder takes an IOThread object reference so that the
> IOThread and its AioContext stay alive until the matching put
> operation. Document the ownership and BQL requirements.
>
> Signed-off-by: Zhang Chen <zhangckid@gmail.com>
> ---
> include/system/iothread.h | 21 +++++++++++++++++++++
> iothread.c | 23 ++++++++++++++++++++++-
> 2 files changed, 43 insertions(+), 1 deletion(-)
>
> diff --git a/include/system/iothread.h b/include/system/iothread.h
> index b8aeb32b0e..b6664e7a38 100644
> --- a/include/system/iothread.h
> +++ b/include/system/iothread.h
> @@ -67,6 +67,27 @@ DECLARE_INSTANCE_CHECKER(IOThread, IOTHREAD,
> char *iothread_get_id(IOThread *iothread);
> IOThread *iothread_by_id(const char *id);
> AioContext *iothread_get_aio_context(IOThread *iothread);
> +
> +/*
> + * Register @holder and return @iothread's AioContext. The holder is copied,
> + * and a reference is taken on @iothread so that both the IOThread and its
> + * AioContext remain alive.
> + *
> + * The caller must eventually call iothread_put_aio_context() with an
> + * equivalent holder. This function is not thread-safe and must be called
> + * under the Big QEMU Lock (BQL).
> + */
> +AioContext *iothread_ref_and_get_aio_context(IOThread *iothread,
> + const IOThreadHolder *holder);
> +
> +/*
> + * Unregister @holder and release the corresponding reference on @iothread.
> + * Calling this function without a matching
> + * iothread_ref_and_get_aio_context() call is a programming error.
> + *
> + * This function is not thread-safe and must be called under the BQL.
> + */
> +void iothread_put_aio_context(IOThread *iothread, const IOThreadHolder *holder);
> GMainContext *iothread_get_g_main_context(IOThread *iothread);
>
> /*
> diff --git a/iothread.c b/iothread.c
> index 2a4c92e08b..0cc8344ee6 100644
> --- a/iothread.c
> +++ b/iothread.c
> @@ -33,6 +33,11 @@ void iothread_ref(IOThread *iothread, const IOThreadHolder *holder)
> assert(holder);
>
> QAPI_LIST_PREPEND(iothread->holders, QAPI_CLONE(IOThreadHolder, holder));
> + /*
> + * This guarantees that the IOThread and its AioContext remain alive
> + * as long as there is a holder.
> + */
> + object_ref(OBJECT(iothread));
> }
>
> static int iothread_holder_compare(const IOThreadHolder *holder_a,
> @@ -78,6 +83,7 @@ void iothread_unref(IOThread *iothread, const IOThreadHolder *holder)
> *prev = curr->next;
> curr->next = NULL;
> qapi_free_IOThreadHolderList(curr);
> + object_unref(OBJECT(iothread));
> return;
> }
> prev = &curr->next;
> @@ -199,7 +205,7 @@ static void iothread_init_gcontext(IOThread *iothread, const char *thread_name)
> g_autofree char *name = g_strdup_printf("%s aio-context", thread_name);
>
> iothread->worker_context = g_main_context_new();
> - source = aio_get_g_source(iothread_get_aio_context(iothread));
> + source = aio_get_g_source(iothread->ctx);
> g_source_set_name(source, name);
> g_source_attach(source, iothread->worker_context);
> g_source_unref(source);
> @@ -421,6 +427,21 @@ AioContext *iothread_get_aio_context(IOThread *iothread)
> return iothread->ctx;
> }
>
> +AioContext *iothread_ref_and_get_aio_context(IOThread *iothread,
> + const IOThreadHolder *holder)
> +{
> + /* Add IOThreadHolder to the list */
> + iothread_ref(iothread, holder);
> +
> + return iothread->ctx;
> +}
> +
> +void iothread_put_aio_context(IOThread *iothread, const IOThreadHolder *holder)
Should we name this "unref" rather than "put"? Perhaps Stefan has an
opinion.
> +{
> + /* Delete IOThreadHolder from the list */
> + iothread_unref(iothread, holder);
> +}
> +
> static int query_one_iothread(Object *object, void *opaque)
> {
> IOThreadInfoList ***tail = opaque;
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH V11 03/15] iothread: track users with holder name
2026-08-07 13:41 ` Markus Armbruster
@ 2026-08-11 8:51 ` Zhang Chen
0 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-11 8:51 UTC (permalink / raw)
To: Markus Armbruster
Cc: qemu-devel, Eric Blake, Michael S . Tsirkin, Stefan Hajnoczi,
Paolo Bonzini, Daniel P . Berrangé, Jason Wang
On Fri, Aug 7, 2026 at 9:41 PM Markus Armbruster <armbru@redhat.com> wrote:
>
> Zhang Chen <zhangckid@gmail.com> writes:
>
> > Introduce iothread_ref_and_get_aio_context() with a holder argument
> > and its counterpart iothread_put_aio_context().
> >
> > Previously, users of an IOThread AioContext did not explicitly record
> > their identity, making it difficult to debug which devices or
> > subsystems were pinning an IOThread.
> >
> > Registering a holder takes an IOThread object reference so that the
> > IOThread and its AioContext stay alive until the matching put
> > operation. Document the ownership and BQL requirements.
> >
> > Signed-off-by: Zhang Chen <zhangckid@gmail.com>
> > ---
> > include/system/iothread.h | 21 +++++++++++++++++++++
> > iothread.c | 23 ++++++++++++++++++++++-
> > 2 files changed, 43 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/system/iothread.h b/include/system/iothread.h
> > index b8aeb32b0e..b6664e7a38 100644
> > --- a/include/system/iothread.h
> > +++ b/include/system/iothread.h
> > @@ -67,6 +67,27 @@ DECLARE_INSTANCE_CHECKER(IOThread, IOTHREAD,
> > char *iothread_get_id(IOThread *iothread);
> > IOThread *iothread_by_id(const char *id);
> > AioContext *iothread_get_aio_context(IOThread *iothread);
> > +
> > +/*
> > + * Register @holder and return @iothread's AioContext. The holder is copied,
> > + * and a reference is taken on @iothread so that both the IOThread and its
> > + * AioContext remain alive.
> > + *
> > + * The caller must eventually call iothread_put_aio_context() with an
> > + * equivalent holder. This function is not thread-safe and must be called
> > + * under the Big QEMU Lock (BQL).
> > + */
> > +AioContext *iothread_ref_and_get_aio_context(IOThread *iothread,
> > + const IOThreadHolder *holder);
> > +
> > +/*
> > + * Unregister @holder and release the corresponding reference on @iothread.
> > + * Calling this function without a matching
> > + * iothread_ref_and_get_aio_context() call is a programming error.
> > + *
> > + * This function is not thread-safe and must be called under the BQL.
> > + */
> > +void iothread_put_aio_context(IOThread *iothread, const IOThreadHolder *holder);
> > GMainContext *iothread_get_g_main_context(IOThread *iothread);
> >
> > /*
> > diff --git a/iothread.c b/iothread.c
> > index 2a4c92e08b..0cc8344ee6 100644
> > --- a/iothread.c
> > +++ b/iothread.c
> > @@ -33,6 +33,11 @@ void iothread_ref(IOThread *iothread, const IOThreadHolder *holder)
> > assert(holder);
> >
> > QAPI_LIST_PREPEND(iothread->holders, QAPI_CLONE(IOThreadHolder, holder));
> > + /*
> > + * This guarantees that the IOThread and its AioContext remain alive
> > + * as long as there is a holder.
> > + */
> > + object_ref(OBJECT(iothread));
> > }
> >
> > static int iothread_holder_compare(const IOThreadHolder *holder_a,
> > @@ -78,6 +83,7 @@ void iothread_unref(IOThread *iothread, const IOThreadHolder *holder)
> > *prev = curr->next;
> > curr->next = NULL;
> > qapi_free_IOThreadHolderList(curr);
> > + object_unref(OBJECT(iothread));
> > return;
> > }
> > prev = &curr->next;
> > @@ -199,7 +205,7 @@ static void iothread_init_gcontext(IOThread *iothread, const char *thread_name)
> > g_autofree char *name = g_strdup_printf("%s aio-context", thread_name);
> >
> > iothread->worker_context = g_main_context_new();
> > - source = aio_get_g_source(iothread_get_aio_context(iothread));
> > + source = aio_get_g_source(iothread->ctx);
> > g_source_set_name(source, name);
> > g_source_attach(source, iothread->worker_context);
> > g_source_unref(source);
> > @@ -421,6 +427,21 @@ AioContext *iothread_get_aio_context(IOThread *iothread)
> > return iothread->ctx;
> > }
> >
> > +AioContext *iothread_ref_and_get_aio_context(IOThread *iothread,
> > + const IOThreadHolder *holder)
> > +{
> > + /* Add IOThreadHolder to the list */
> > + iothread_ref(iothread, holder);
> > +
> > + return iothread->ctx;
> > +}
> > +
> > +void iothread_put_aio_context(IOThread *iothread, const IOThreadHolder *holder)
>
> Should we name this "unref" rather than "put"? Perhaps Stefan has an
> opinion.
It's OK for me. The original code was designed to match the
"iothread_get_aio_context",
If Stefan has no objection, I will change the name to
"iothread_unref_aio_context".
Thanks
Chen
>
> > +{
> > + /* Delete IOThreadHolder from the list */
> > + iothread_unref(iothread, holder);
> > +}
> > +
> > static int query_one_iothread(Object *object, void *opaque)
> > {
> > IOThreadInfoList ***tail = opaque;
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V11 04/15] iothread: introduce iothread_unsafe_get_aio_context()
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (2 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 03/15] iothread: track users with holder name Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-06 20:25 ` [PATCH V11 05/15] block/export: track IOThread references Zhang Chen
` (10 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Add an explicitly unsafe accessor for legacy callers that cannot
provide a matching holder lifecycle, and convert blockdev.c to use it.
Keep iothread_get_aio_context() temporarily so that later caller
conversions remain independently buildable. It will be removed after
all production callers have migrated.
New code should use iothread_ref_and_get_aio_context().
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
blockdev.c | 2 +-
include/system/iothread.h | 10 ++++++++++
iothread.c | 5 +++++
3 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/blockdev.c b/blockdev.c
index 6e86c6262f..baeab3a3e1 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3683,7 +3683,7 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
goto out;
}
- new_context = iothread_get_aio_context(obj);
+ new_context = iothread_unsafe_get_aio_context(obj);
} else {
new_context = qemu_get_aio_context();
}
diff --git a/include/system/iothread.h b/include/system/iothread.h
index b6664e7a38..cf1b6e0cdc 100644
--- a/include/system/iothread.h
+++ b/include/system/iothread.h
@@ -68,6 +68,16 @@ char *iothread_get_id(IOThread *iothread);
IOThread *iothread_by_id(const char *id);
AioContext *iothread_get_aio_context(IOThread *iothread);
+/*
+ * Return @iothread's AioContext without registering a holder or taking a
+ * reference on @iothread. The caller must ensure that the IOThread remains
+ * alive for as long as the returned AioContext is used.
+ *
+ * This API exists for legacy callers without a clear ref/unref lifecycle. Do
+ * not use it in new code; use iothread_ref_and_get_aio_context() instead.
+ */
+AioContext *iothread_unsafe_get_aio_context(IOThread *iothread);
+
/*
* Register @holder and return @iothread's AioContext. The holder is copied,
* and a reference is taken on @iothread so that both the IOThread and its
diff --git a/iothread.c b/iothread.c
index 0cc8344ee6..43f42c65c8 100644
--- a/iothread.c
+++ b/iothread.c
@@ -442,6 +442,11 @@ void iothread_put_aio_context(IOThread *iothread, const IOThreadHolder *holder)
iothread_unref(iothread, holder);
}
+AioContext *iothread_unsafe_get_aio_context(IOThread *iothread)
+{
+ return iothread->ctx;
+}
+
static int query_one_iothread(Object *object, void *opaque)
{
IOThreadInfoList ***tail = opaque;
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH V11 05/15] block/export: track IOThread references
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (3 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 04/15] iothread: introduce iothread_unsafe_get_aio_context() Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-06 20:25 ` [PATCH V11 06/15] monitor: track IOThread users with QOM paths Zhang Chen
` (9 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Track the IOThreads used by a block export and identify the holder
with the unique BlockExportOptions id.
Acquire holder-aware references during export creation and release
them on error or export deletion. Support both single- and
multi-iothread exports.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
block/export/export.c | 79 +++++++++++++++++++++++++++++++++++++-----
include/block/export.h | 6 ++++
2 files changed, 76 insertions(+), 9 deletions(-)
diff --git a/block/export/export.c b/block/export/export.c
index b733f269f3..96d719418e 100644
--- a/block/export/export.c
+++ b/block/export/export.c
@@ -15,7 +15,6 @@
#include "block/block.h"
#include "system/block-backend.h"
-#include "system/iothread.h"
#include "block/export.h"
#include "block/fuse.h"
#include "block/nbd.h"
@@ -85,6 +84,8 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
AioContext *ctx;
AioContext **multithread_ctxs = NULL;
size_t multithread_count = 0;
+ g_autofree IOThread **local_iothreads = NULL;
+ const char *holder_id = NULL;
uint64_t perm;
int ret;
@@ -139,7 +140,16 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
goto fail;
}
- new_ctx = iothread_get_aio_context(iothread);
+ holder_id = export->id;
+ const IOThreadHolder holder = {
+ .type = IO_THREAD_HOLDER_KIND_BLOCK_EXPORT,
+ .u.block_export.export_id = (char *)holder_id,
+ };
+
+ new_ctx = iothread_ref_and_get_aio_context(iothread, &holder);
+ multithread_count = 1;
+ local_iothreads = g_new0(IOThread *, 1);
+ local_iothreads[0] = iothread;
/* Ignore errors with fixed-iothread=false */
set_context_errp = fixed_iothread ? errp : NULL;
@@ -163,8 +173,15 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
return NULL;
}
+ local_iothreads = g_new0(IOThread *, multithread_count);
multithread_ctxs = g_new(AioContext *, multithread_count);
i = 0;
+ holder_id = export->id;
+ const IOThreadHolder holder = {
+ .type = IO_THREAD_HOLDER_KIND_BLOCK_EXPORT,
+ .u.block_export.export_id = (char *)holder_id,
+ };
+
for (strList *e = iothread_list; e; e = e->next) {
IOThread *iothread = iothread_by_id(e->value);
@@ -172,7 +189,9 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
error_setg(errp, "iothread \"%s\" not found", e->value);
goto fail;
}
- multithread_ctxs[i++] = iothread_get_aio_context(iothread);
+ local_iothreads[i] = iothread;
+ multithread_ctxs[i++] = iothread_ref_and_get_aio_context(iothread,
+ &holder);
}
assert(i == multithread_count);
}
@@ -225,12 +244,15 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
assert(drv->instance_size >= sizeof(BlockExport));
exp = g_malloc0(drv->instance_size);
*exp = (BlockExport) {
- .drv = drv,
- .refcount = 1,
- .user_owned = true,
- .id = g_strdup(export->id),
- .ctx = ctx,
- .blk = blk,
+ .drv = drv,
+ .refcount = 1,
+ .user_owned = true,
+ .id = g_strdup(export->id),
+ .ctx = ctx,
+ .blk = blk,
+ .iothreads = g_steal_pointer(&local_iothreads),
+ .iothread_count = multithread_count,
+ .iothread_holder_id = g_strdup(holder_id),
};
ret = drv->create(exp, export, multithread_ctxs, multithread_count, errp);
@@ -250,8 +272,32 @@ fail:
blk_unref(blk);
}
if (exp) {
+ if (exp->iothreads) {
+ const IOThreadHolder holder = {
+ .type = IO_THREAD_HOLDER_KIND_BLOCK_EXPORT,
+ .u.block_export.export_id = exp->iothread_holder_id,
+ };
+ for (size_t j = 0; j < exp->iothread_count; j++) {
+ if (exp->iothreads[j]) {
+ iothread_put_aio_context(exp->iothreads[j], &holder);
+ }
+ }
+ g_free(exp->iothreads);
+ }
+ g_free(exp->iothread_holder_id);
g_free(exp->id);
g_free(exp);
+ } else if (local_iothreads) {
+ const IOThreadHolder holder = {
+ .type = IO_THREAD_HOLDER_KIND_BLOCK_EXPORT,
+ .u.block_export.export_id = (char *)holder_id,
+ };
+
+ for (size_t j = 0; j < multithread_count; j++) {
+ if (local_iothreads[j]) {
+ iothread_put_aio_context(local_iothreads[j], &holder);
+ }
+ }
}
g_free(multithread_ctxs);
return NULL;
@@ -269,10 +315,25 @@ static void blk_exp_delete_bh(void *opaque)
BlockExport *exp = opaque;
assert(exp->refcount == 0);
+
QLIST_REMOVE(exp, next);
exp->drv->delete(exp);
blk_set_dev_ops(exp->blk, NULL, NULL);
blk_unref(exp->blk);
+
+ if (exp->iothreads) {
+ const IOThreadHolder holder = {
+ .type = IO_THREAD_HOLDER_KIND_BLOCK_EXPORT,
+ .u.block_export.export_id = exp->iothread_holder_id,
+ };
+
+ for (size_t i = 0; i < exp->iothread_count; i++) {
+ iothread_put_aio_context(exp->iothreads[i], &holder);
+ }
+ g_free(exp->iothreads);
+ }
+
+ g_free(exp->iothread_holder_id);
qapi_event_send_block_export_deleted(exp->id);
g_free(exp->id);
g_free(exp);
diff --git a/include/block/export.h b/include/block/export.h
index ca45da928c..a093dea0b6 100644
--- a/include/block/export.h
+++ b/include/block/export.h
@@ -16,6 +16,7 @@
#include "qapi/qapi-types-block-export.h"
#include "qemu/queue.h"
+#include "system/iothread.h"
typedef struct BlockExport BlockExport;
@@ -89,6 +90,11 @@ struct BlockExport {
/* List entry for block_exports */
QLIST_ENTRY(BlockExport) next;
+
+ /* The IOThreads utilized by this specific block export */
+ IOThread **iothreads;
+ size_t iothread_count;
+ char *iothread_holder_id;
};
BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp);
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH V11 06/15] monitor: track IOThread users with QOM paths
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (4 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 05/15] block/export: track IOThread references Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-07 14:03 ` Markus Armbruster
2026-08-06 20:25 ` [PATCH V11 07/15] virtio-vq-mapping: track iothread-vq-mapping references using device path Zhang Chen
` (8 subsequent siblings)
14 siblings, 1 reply; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Acquire the shared monitor IOThread AioContext once, using the monitor
QOM path as the holder, and reuse the stored context for later
operations.
Release the holder during global cleanup and dynamic QMP monitor
deletion to provide an explicit acquire/release lifecycle.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
monitor/monitor-internal.h | 3 +++
monitor/monitor.c | 26 +++++++++++++++++++++-----
monitor/qmp.c | 16 ++++++++++++++--
3 files changed, 38 insertions(+), 7 deletions(-)
diff --git a/monitor/monitor-internal.h b/monitor/monitor-internal.h
index 23829f32f9..caecceec93 100644
--- a/monitor/monitor-internal.h
+++ b/monitor/monitor-internal.h
@@ -153,6 +153,9 @@ struct Monitor {
guint out_watch;
int mux_out;
int reset_seen;
+
+ /* iothread context */
+ AioContext *ctx;
};
struct MonitorHMPClass {
diff --git a/monitor/monitor.c b/monitor/monitor.c
index ed195fd97b..840a579247 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -573,7 +573,7 @@ void monitor_suspend(Monitor *mon)
* Kick I/O thread to make sure this takes effect. It'll be
* evaluated again in prepare() of the watch object.
*/
- aio_notify(iothread_get_aio_context(mon_iothread));
+ aio_notify(mon->ctx);
}
trace_monitor_suspend(mon, 1);
@@ -668,6 +668,17 @@ void monitor_cleanup(void)
qemu_mutex_unlock(&monitor_lock);
monitor_flush(mon);
qemu_mutex_lock(&monitor_lock);
+
+ if (monitor_requires_iothread(mon)) {
+ g_autofree char *path = object_get_canonical_path(OBJECT(mon));
+ const IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = path,
+ };
+
+ iothread_put_aio_context(mon_iothread, &io_holder);
+ mon->ctx = NULL;
+ }
object_unparent(OBJECT(mon));
}
qemu_mutex_unlock(&monitor_lock);
@@ -713,7 +724,6 @@ char *monitor_compat_id(void)
static void monitor_complete(UserCreatable *uc, Error **errp)
{
Monitor *mon = MONITOR(uc);
- AioContext *ctx;
if (mon->chardev_id) {
Chardev *chr = qemu_chr_find(mon->chardev_id);
@@ -732,11 +742,17 @@ static void monitor_complete(UserCreatable *uc, Error **errp)
mon_iothread = iothread_create("mon_iothread", &error_abort);
}
- ctx = iothread_get_aio_context(mon_iothread);
+ g_autofree char *path = object_get_canonical_path(OBJECT(mon));
+ const IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = path,
+ };
+
+ mon->ctx = iothread_ref_and_get_aio_context(mon_iothread, &io_holder);
} else {
- ctx = qemu_get_aio_context();
+ mon->ctx = qemu_get_aio_context();
}
- mon->accept_input_bh = aio_bh_new(ctx, monitor_accept_input, mon);
+ mon->accept_input_bh = aio_bh_new(mon->ctx, monitor_accept_input, mon);
}
int monitor_new(MonitorOptions *opts, bool allow_hmp, Error **errp)
diff --git a/monitor/qmp.c b/monitor/qmp.c
index 338d37cb7e..51a724d545 100644
--- a/monitor/qmp.c
+++ b/monitor/qmp.c
@@ -733,7 +733,8 @@ static void monitor_qmp_complete(UserCreatable *uc, Error **errp)
* thread. Schedule a bottom half.
*/
mon->setup_pending = true;
- aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread),
+
+ aio_bh_schedule_oneshot(MONITOR(mon)->ctx,
monitor_qmp_setup_handlers_bh, mon);
/* The bottom half will add @mon to @mon_list */
} else {
@@ -788,7 +789,7 @@ static bool monitor_qmp_prepare_delete(UserCreatable *uc, Error **errp)
/* Synchronize with in-flight iothread callbacks. */
if (monitor_requires_iothread(mon)) {
- aio_wait_bh_oneshot(iothread_get_aio_context(mon_iothread),
+ aio_wait_bh_oneshot(MONITOR(mon)->ctx,
monitor_qmp_iothread_quiesce, NULL);
}
@@ -796,6 +797,17 @@ static bool monitor_qmp_prepare_delete(UserCreatable *uc, Error **errp)
monitor_qmp_drain_queue(qmp);
monitor_fdsets_cleanup();
+ if (monitor_requires_iothread(mon)) {
+ g_autofree char *path = object_get_canonical_path(OBJECT(mon));
+ const IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = path,
+ };
+
+ iothread_put_aio_context(mon_iothread, &io_holder);
+ mon->ctx = NULL;
+ }
+
return true;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH V11 06/15] monitor: track IOThread users with QOM paths
2026-08-06 20:25 ` [PATCH V11 06/15] monitor: track IOThread users with QOM paths Zhang Chen
@ 2026-08-07 14:03 ` Markus Armbruster
0 siblings, 0 replies; 22+ messages in thread
From: Markus Armbruster @ 2026-08-07 14:03 UTC (permalink / raw)
To: Zhang Chen
Cc: qemu-devel, Eric Blake, Michael S . Tsirkin, Stefan Hajnoczi,
Paolo Bonzini, 'Daniel P . Berrangé', Jason Wang
Zhang Chen <zhangckid@gmail.com> writes:
> Acquire the shared monitor IOThread AioContext once, using the monitor
> QOM path as the holder, and reuse the stored context for later
> operations.
This describes what the patch does, but not why it is useful.
> Release the holder during global cleanup and dynamic QMP monitor
> deletion to provide an explicit acquire/release lifecycle.
This at least provides a clue: "to provide ..."
> Signed-off-by: Zhang Chen <zhangckid@gmail.com>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V11 07/15] virtio-vq-mapping: track iothread-vq-mapping references using device path
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (5 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 06/15] monitor: track IOThread users with QOM paths Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-06 20:25 ` [PATCH V11 08/15] virtio: track IOThread references for thread pinning Zhang Chen
` (7 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Replace raw object_ref/unref calls with iothread_get/put_aio_context
in iothread-vq-mapping. This allows tracking IOThread users via the
device's canonical QOM path, improving lifecycle traceability for
virtio-blk and virtio-scsi devices.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
hw/block/virtio-blk.c | 8 +++++++-
hw/scsi/virtio-scsi-dataplane.c | 9 +++++++--
hw/virtio/iothread-vq-mapping.c | 20 +++++++++++++++-----
include/hw/virtio/iothread-vq-mapping.h | 6 +++++-
4 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 6b92066aff..4b2cf3d52f 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -1493,9 +1493,12 @@ static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
s->vq_aio_context = g_new(AioContext *, conf->num_queues);
if (conf->iothread_vq_mapping_list) {
+ g_autofree char *path = object_get_canonical_path(OBJECT(vdev));
+
if (!iothread_vq_mapping_apply(conf->iothread_vq_mapping_list,
s->vq_aio_context,
conf->num_queues,
+ path,
errp)) {
g_free(s->vq_aio_context);
s->vq_aio_context = NULL;
@@ -1527,7 +1530,10 @@ static void virtio_blk_vq_aio_context_cleanup(VirtIOBlock *s)
assert(!s->ioeventfd_started);
if (conf->iothread_vq_mapping_list) {
- iothread_vq_mapping_cleanup(conf->iothread_vq_mapping_list);
+ g_autofree char *path = object_get_canonical_path(
+ OBJECT(VIRTIO_DEVICE(s)));
+
+ iothread_vq_mapping_cleanup(conf->iothread_vq_mapping_list, path);
}
if (conf->iothread) {
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 95f13fb7c2..26ecefd547 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -65,9 +65,11 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
s->vq_aio_context[1] = qemu_get_aio_context();
if (vs->conf.iothread_vq_mapping_list) {
+ g_autofree char *path = object_get_canonical_path(OBJECT(vdev));
+
if (!iothread_vq_mapping_apply(vs->conf.iothread_vq_mapping_list,
&s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED],
- vs->conf.num_queues, errp)) {
+ vs->conf.num_queues, path, errp)) {
g_free(s->vq_aio_context);
s->vq_aio_context = NULL;
return;
@@ -94,7 +96,10 @@ void virtio_scsi_dataplane_cleanup(VirtIOSCSI *s)
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
if (vs->conf.iothread_vq_mapping_list) {
- iothread_vq_mapping_cleanup(vs->conf.iothread_vq_mapping_list);
+ g_autofree char *path = object_get_canonical_path(
+ OBJECT(VIRTIO_DEVICE(s)));
+
+ iothread_vq_mapping_cleanup(vs->conf.iothread_vq_mapping_list, path);
}
if (vs->conf.iothread) {
diff --git a/hw/virtio/iothread-vq-mapping.c b/hw/virtio/iothread-vq-mapping.c
index 55ce62986c..2cb48dd387 100644
--- a/hw/virtio/iothread-vq-mapping.c
+++ b/hw/virtio/iothread-vq-mapping.c
@@ -77,6 +77,7 @@ bool iothread_vq_mapping_apply(
IOThreadVirtQueueMappingList *list,
AioContext **vq_aio_context,
uint16_t num_queues,
+ const char *holder,
Error **errp)
{
IOThreadVirtQueueMappingList *node;
@@ -93,10 +94,13 @@ bool iothread_vq_mapping_apply(
for (node = list; node; node = node->next) {
IOThread *iothread = iothread_by_id(node->value->iothread);
- AioContext *ctx = iothread_get_aio_context(iothread);
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)holder,
+ };
- /* Released in virtio_blk_vq_aio_context_cleanup() */
- object_ref(OBJECT(iothread));
+ AioContext *ctx = iothread_ref_and_get_aio_context(iothread,
+ &io_holder);
if (node->value->vqs) {
uint16List *vq;
@@ -120,13 +124,19 @@ bool iothread_vq_mapping_apply(
return true;
}
-void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list)
+void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list,
+ const char *holder)
{
IOThreadVirtQueueMappingList *node;
for (node = list; node; node = node->next) {
IOThread *iothread = iothread_by_id(node->value->iothread);
- object_unref(OBJECT(iothread));
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)holder,
+ };
+
+ iothread_put_aio_context(iothread, &io_holder);
}
}
diff --git a/include/hw/virtio/iothread-vq-mapping.h b/include/hw/virtio/iothread-vq-mapping.h
index 57335c3703..0d39caddf3 100644
--- a/include/hw/virtio/iothread-vq-mapping.h
+++ b/include/hw/virtio/iothread-vq-mapping.h
@@ -17,6 +17,7 @@
* @list: The mapping of virtqueues to IOThreads.
* @vq_aio_context: The array of AioContext pointers to fill in.
* @num_queues: The length of @vq_aio_context.
+ * @holder: The QOM paths for attached device.
* @errp: If an error occurs, a pointer to the area to store the error.
*
* Fill in the AioContext for each virtqueue in the @vq_aio_context array given
@@ -31,15 +32,18 @@ bool iothread_vq_mapping_apply(
IOThreadVirtQueueMappingList *list,
AioContext **vq_aio_context,
uint16_t num_queues,
+ const char *holder,
Error **errp);
/**
* iothread_vq_mapping_cleanup:
* @list: The mapping of virtqueues to IOThreads.
+ * @holder: The QOM paths for attached device.
*
* Release IOThread object references that were acquired by
* iothread_vq_mapping_apply().
*/
-void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list);
+void iothread_vq_mapping_cleanup(IOThreadVirtQueueMappingList *list,
+ const char *holder);
#endif /* HW_VIRTIO_IOTHREAD_VQ_MAPPING_H */
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH V11 08/15] virtio: track IOThread references for thread pinning
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (6 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 07/15] virtio-vq-mapping: track iothread-vq-mapping references using device path Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-06 20:25 ` [PATCH V11 09/15] net/colo: track IOThread references using path-based holder Zhang Chen
` (6 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Use the virtio device canonical QOM path as the holder when virtio-blk
and virtio-scsi acquire an IOThread AioContext.
Replace the raw object references with the holder-aware
acquire/release helpers so the users are visible through IOThread
introspection.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
hw/block/virtio-blk.c | 23 +++++++++++++----------
hw/scsi/virtio-scsi-dataplane.c | 23 +++++++++++++----------
2 files changed, 26 insertions(+), 20 deletions(-)
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 4b2cf3d52f..c92c0d39e9 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -1469,6 +1469,7 @@ static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
VirtIOBlkConf *conf = &s->conf;
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+ g_autofree char *path = object_get_canonical_path(OBJECT(vdev));
if (conf->iothread && conf->iothread_vq_mapping_list) {
error_setg(errp,
@@ -1493,8 +1494,6 @@ static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
s->vq_aio_context = g_new(AioContext *, conf->num_queues);
if (conf->iothread_vq_mapping_list) {
- g_autofree char *path = object_get_canonical_path(OBJECT(vdev));
-
if (!iothread_vq_mapping_apply(conf->iothread_vq_mapping_list,
s->vq_aio_context,
conf->num_queues,
@@ -1505,13 +1504,15 @@ static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
return false;
}
} else if (conf->iothread) {
- AioContext *ctx = iothread_get_aio_context(conf->iothread);
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
+ AioContext *ctx = iothread_ref_and_get_aio_context(conf->iothread,
+ &io_holder);
for (unsigned i = 0; i < conf->num_queues; i++) {
s->vq_aio_context[i] = ctx;
}
-
- /* Released in virtio_blk_vq_aio_context_cleanup() */
- object_ref(OBJECT(conf->iothread));
} else {
AioContext *ctx = qemu_get_aio_context();
for (unsigned i = 0; i < conf->num_queues; i++) {
@@ -1526,18 +1527,20 @@ static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
static void virtio_blk_vq_aio_context_cleanup(VirtIOBlock *s)
{
VirtIOBlkConf *conf = &s->conf;
+ g_autofree char *path = object_get_canonical_path(OBJECT(VIRTIO_DEVICE(s)));
assert(!s->ioeventfd_started);
if (conf->iothread_vq_mapping_list) {
- g_autofree char *path = object_get_canonical_path(
- OBJECT(VIRTIO_DEVICE(s)));
-
iothread_vq_mapping_cleanup(conf->iothread_vq_mapping_list, path);
}
if (conf->iothread) {
- object_unref(OBJECT(conf->iothread));
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
+ iothread_put_aio_context(conf->iothread, &io_holder);
}
g_free(s->vq_aio_context);
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 26ecefd547..c71f33b41e 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -28,6 +28,7 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
VirtIODevice *vdev = VIRTIO_DEVICE(s);
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+ g_autofree char *path = object_get_canonical_path(OBJECT(vdev));
if (vs->conf.iothread && vs->conf.iothread_vq_mapping_list) {
error_setg(errp,
@@ -65,8 +66,6 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
s->vq_aio_context[1] = qemu_get_aio_context();
if (vs->conf.iothread_vq_mapping_list) {
- g_autofree char *path = object_get_canonical_path(OBJECT(vdev));
-
if (!iothread_vq_mapping_apply(vs->conf.iothread_vq_mapping_list,
&s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED],
vs->conf.num_queues, path, errp)) {
@@ -75,13 +74,15 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
return;
}
} else if (vs->conf.iothread) {
- AioContext *ctx = iothread_get_aio_context(vs->conf.iothread);
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
+ AioContext *ctx = iothread_ref_and_get_aio_context(vs->conf.iothread,
+ &io_holder);
for (uint16_t i = 0; i < vs->conf.num_queues; i++) {
s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i] = ctx;
}
-
- /* Released in virtio_scsi_dataplane_cleanup() */
- object_ref(OBJECT(vs->conf.iothread));
} else {
AioContext *ctx = qemu_get_aio_context();
for (unsigned i = 0; i < vs->conf.num_queues; i++) {
@@ -94,16 +95,18 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
void virtio_scsi_dataplane_cleanup(VirtIOSCSI *s)
{
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
+ g_autofree char *path = object_get_canonical_path(OBJECT(VIRTIO_DEVICE(s)));
if (vs->conf.iothread_vq_mapping_list) {
- g_autofree char *path = object_get_canonical_path(
- OBJECT(VIRTIO_DEVICE(s)));
-
iothread_vq_mapping_cleanup(vs->conf.iothread_vq_mapping_list, path);
}
if (vs->conf.iothread) {
- object_unref(OBJECT(vs->conf.iothread));
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
+ iothread_put_aio_context(vs->conf.iothread, &io_holder);
}
g_free(s->vq_aio_context);
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH V11 09/15] net/colo: track IOThread references using path-based holder
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (7 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 08/15] virtio: track IOThread references for thread pinning Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-06 20:25 ` [PATCH V11 10/15] virtio-balloon: Update tracking iothread users with holder Zhang Chen
` (5 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Convert colo-compare to use the iothread_ref_and_get_aio_context() and
iothread_put_aio_context() APIs. This ensures that IOThread references
are tracked using the COLO object's canonical QOM path as the holder
ID.
This refactoring improves IOThread lifecycle traceability and aligns
the code with modern QEMU iothread reference management patterns.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
net/colo-compare.c | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/net/colo-compare.c b/net/colo-compare.c
index 5986fb1e88..a7bbb1056d 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -130,6 +130,7 @@ struct CompareState {
GHashTable *connection_track_table;
IOThread *iothread;
+ AioContext *iothread_ctx;
GMainContext *worker_context;
QEMUTimer *packet_check_timer;
@@ -922,9 +923,7 @@ void colo_notify_compares_event(void *opaque, int event, Error **errp)
static void colo_compare_timer_init(CompareState *s)
{
- AioContext *ctx = iothread_get_aio_context(s->iothread);
-
- s->packet_check_timer = aio_timer_new(ctx, QEMU_CLOCK_HOST,
+ s->packet_check_timer = aio_timer_new(s->iothread_ctx, QEMU_CLOCK_HOST,
SCALE_MS, check_old_packet_regular,
s);
timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_HOST) +
@@ -964,8 +963,15 @@ static void colo_compare_handle_event(void *opaque)
static void colo_compare_iothread(CompareState *s)
{
- AioContext *ctx = iothread_get_aio_context(s->iothread);
- object_ref(OBJECT(s->iothread));
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
+
+ AioContext *ctx = iothread_ref_and_get_aio_context(s->iothread, &io_holder);
+
+ s->iothread_ctx = ctx;
s->worker_context = iothread_get_g_main_context(s->iothread);
qemu_chr_fe_set_handlers(&s->chr_pri_in, compare_chr_can_read,
@@ -1404,6 +1410,7 @@ static void colo_compare_finalize(Object *obj)
{
CompareState *s = COLO_COMPARE(obj);
CompareState *tmp;
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
qemu_mutex_lock(&colo_compare_mutex);
QTAILQ_FOREACH(tmp, &net_compares, next) {
@@ -1430,18 +1437,20 @@ static void colo_compare_finalize(Object *obj)
g_clear_pointer(&s->event_bh, qemu_bh_delete);
if (s->iothread) {
- AioContext *ctx = iothread_get_aio_context(s->iothread);
-
- AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
+ AIO_WAIT_WHILE(s->iothread_ctx, !s->out_sendco.done);
if (s->notify_dev) {
- AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
+ AIO_WAIT_WHILE(s->iothread_ctx, !s->notify_sendco.done);
}
/* Release all unhandled packets after compare thread exited */
g_queue_foreach(&s->conn_list, colo_flush_packets, s);
AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
- object_unref(OBJECT(s->iothread));
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
+ iothread_put_aio_context(s->iothread, &io_holder);
}
g_queue_clear(&s->conn_list);
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH V11 10/15] virtio-balloon: Update tracking iothread users with holder
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (8 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 09/15] net/colo: track IOThread references using path-based holder Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-06 20:25 ` [PATCH V11 11/15] vfio-user/proxy: Update tracking iothread users with holder name Zhang Chen
` (4 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Replace raw object_ref/unref calls with iothread_get/put_aio_context.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
hw/virtio/virtio-balloon.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 4c5f486ba2..e9d023b4ec 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -892,14 +892,20 @@ static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats);
if (virtio_has_feature(s->host_features, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
+
s->free_page_vq = virtio_add_queue(vdev, VIRTQUEUE_MAX_SIZE,
virtio_balloon_handle_free_page_vq);
precopy_add_notifier(&s->free_page_hint_notify);
- object_ref(OBJECT(s->iothread));
- s->free_page_bh = aio_bh_new_guarded(iothread_get_aio_context(s->iothread),
- virtio_ballloon_get_free_page_hints, s,
- &dev->mem_reentrancy_guard);
+ s->free_page_bh = aio_bh_new_guarded(
+ iothread_ref_and_get_aio_context(s->iothread, &io_holder),
+ virtio_ballloon_get_free_page_hints, s,
+ &dev->mem_reentrancy_guard);
}
if (virtio_has_feature(s->host_features, VIRTIO_BALLOON_F_REPORTING)) {
@@ -919,9 +925,15 @@ static void virtio_balloon_device_unrealize(DeviceState *dev)
qemu_unregister_resettable(OBJECT(dev));
if (s->free_page_bh) {
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
+
qemu_bh_delete(s->free_page_bh);
- object_unref(OBJECT(s->iothread));
virtio_balloon_free_page_stop(s);
+ iothread_put_aio_context(s->iothread, &io_holder);
precopy_remove_notifier(&s->free_page_hint_notify);
}
balloon_stats_destroy_timer(s);
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH V11 11/15] vfio-user/proxy: Update tracking iothread users with holder name
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (9 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 10/15] virtio-balloon: Update tracking iothread users with holder Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-06 20:25 ` [PATCH V11 12/15] xen-block: " Zhang Chen
` (3 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Add object_ref/unref calls with iothread_get/put_aio_context.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
hw/vfio-user/proxy.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/hw/vfio-user/proxy.c b/hw/vfio-user/proxy.c
index 197aee07bf..5ef1547357 100644
--- a/hw/vfio-user/proxy.c
+++ b/hw/vfio-user/proxy.c
@@ -898,6 +898,7 @@ VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp)
QIOChannelSocket *sioc;
QIOChannel *ioc;
char *sockname;
+ g_autofree char *path = NULL;
if (addr->type != SOCKET_ADDRESS_TYPE_UNIX) {
error_setg(errp, "vfio_user_connect - bad address family");
@@ -917,6 +918,11 @@ VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp)
proxy = g_malloc0(sizeof(VFIOUserProxy));
proxy->sockname = g_strdup_printf("unix:%s", sockname);
proxy->ioc = ioc;
+ path = object_get_canonical_path(OBJECT(proxy->ioc));
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
/* init defaults */
proxy->max_xfer_size = VFIO_USER_DEF_MAX_XFER;
@@ -936,7 +942,8 @@ VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp)
vfio_user_iothread = iothread_create("vfio-user", errp);
}
- proxy->ctx = iothread_get_aio_context(vfio_user_iothread);
+ proxy->ctx = iothread_ref_and_get_aio_context(vfio_user_iothread,
+ &io_holder);
proxy->req_bh = qemu_bh_new(vfio_user_request, proxy);
QTAILQ_INIT(&proxy->outgoing);
@@ -967,6 +974,11 @@ void vfio_user_set_handler(VFIODevice *vbasedev,
void vfio_user_disconnect(VFIOUserProxy *proxy)
{
VFIOUserMsg *r1, *r2;
+ g_autofree char *path = object_get_canonical_path(OBJECT(proxy->ioc));
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
qemu_mutex_lock(&proxy->lock);
@@ -1021,6 +1033,8 @@ void vfio_user_disconnect(VFIOUserProxy *proxy)
qemu_cond_destroy(&proxy->close_cv);
qemu_mutex_destroy(&proxy->lock);
+ iothread_put_aio_context(vfio_user_iothread, &io_holder);
+
QLIST_REMOVE(proxy, next);
if (QLIST_EMPTY(&vfio_user_sockets)) {
iothread_destroy(vfio_user_iothread);
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH V11 12/15] xen-block: Update tracking iothread users with holder name
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (10 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 11/15] vfio-user/proxy: Update tracking iothread users with holder name Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-06 20:25 ` [PATCH V11 13/15] monitor/hmp: display IOThread holders Zhang Chen
` (2 subsequent siblings)
14 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Replace raw object_ref/unref calls with iothread_get/put_aio_context.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
hw/block/dataplane/xen-block.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c
index 48c2e315f3..b5bf8d359f 100644
--- a/hw/block/dataplane/xen-block.c
+++ b/hw/block/dataplane/xen-block.c
@@ -621,9 +621,15 @@ XenBlockDataPlane *xen_block_dataplane_create(XenDevice *xendev,
QLIST_INIT(&dataplane->freelist);
if (iothread) {
+ g_autofree char *path = object_get_canonical_path(OBJECT(xendev));
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
+
dataplane->iothread = iothread;
- object_ref(OBJECT(dataplane->iothread));
- dataplane->ctx = iothread_get_aio_context(dataplane->iothread);
+ dataplane->ctx = iothread_ref_and_get_aio_context(dataplane->iothread,
+ &io_holder);
} else {
dataplane->ctx = qemu_get_aio_context();
}
@@ -652,7 +658,14 @@ void xen_block_dataplane_destroy(XenBlockDataPlane *dataplane)
qemu_bh_delete(dataplane->bh);
if (dataplane->iothread) {
- object_unref(OBJECT(dataplane->iothread));
+ g_autofree char *path = object_get_canonical_path(
+ OBJECT(dataplane->xendev));
+ IOThreadHolder io_holder = {
+ .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+ .u.qom_object.qom_path = (char *)path,
+ };
+
+ iothread_put_aio_context(dataplane->iothread, &io_holder);
}
g_free(dataplane);
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH V11 13/15] monitor/hmp: display IOThread holders
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (11 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 12/15] xen-block: " Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-07 13:44 ` Markus Armbruster
2026-08-06 20:25 ` [PATCH V11 14/15] iothread: remove legacy iothread_get_aio_context() Zhang Chen
2026-08-06 20:25 ` [PATCH V11 15/15] tests/unit/iothread: update AioContext ref/put helpers Zhang Chen
14 siblings, 1 reply; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Display holder information in info iothreads to aid manual debugging.
Omit the holders line when an IOThread has no holders.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
monitor/hmp-cmds.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index e9fb8d827a..de37f83a72 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -240,11 +240,33 @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
IOThreadInfoList *info;
IOThreadInfo *value;
+ IOThreadHolderList *h;
for (info = info_list; info; info = info->next) {
value = info->value;
monitor_printf(mon, "%s:\n", value->id);
monitor_printf(mon, " thread_id=%" PRId64 "\n", value->thread_id);
+ if (value->holders) {
+ monitor_printf(mon, " holders=");
+ for (h = value->holders; h; h = h->next) {
+ IOThreadHolder *holder = h->value;
+
+ switch (holder->type) {
+ case IO_THREAD_HOLDER_KIND_BLOCK_EXPORT:
+ monitor_printf(mon, "[block-export: %s]",
+ holder->u.block_export.export_id);
+ break;
+ case IO_THREAD_HOLDER_KIND_QOM_OBJECT:
+ monitor_printf(mon, "[qom-path: %s]",
+ holder->u.qom_object.qom_path);
+ break;
+ default:
+ monitor_printf(mon, "[unknown]");
+ break;
+ }
+ }
+ monitor_printf(mon, "\n");
+ }
monitor_printf(mon, " poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
monitor_printf(mon, " poll-grow=%" PRId64 "\n", value->poll_grow);
monitor_printf(mon, " poll-shrink=%" PRId64 "\n", value->poll_shrink);
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH V11 13/15] monitor/hmp: display IOThread holders
2026-08-06 20:25 ` [PATCH V11 13/15] monitor/hmp: display IOThread holders Zhang Chen
@ 2026-08-07 13:44 ` Markus Armbruster
2026-08-11 8:44 ` Zhang Chen
0 siblings, 1 reply; 22+ messages in thread
From: Markus Armbruster @ 2026-08-07 13:44 UTC (permalink / raw)
To: Zhang Chen
Cc: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Zhang Chen <zhangckid@gmail.com> writes:
> Display holder information in info iothreads to aid manual debugging.
> Omit the holders line when an IOThread has no holders.
>
> Signed-off-by: Zhang Chen <zhangckid@gmail.com>
> ---
> monitor/hmp-cmds.c | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
> index e9fb8d827a..de37f83a72 100644
> --- a/monitor/hmp-cmds.c
> +++ b/monitor/hmp-cmds.c
> @@ -240,11 +240,33 @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
> IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
> IOThreadInfoList *info;
> IOThreadInfo *value;
> + IOThreadHolderList *h;
>
> for (info = info_list; info; info = info->next) {
> value = info->value;
> monitor_printf(mon, "%s:\n", value->id);
> monitor_printf(mon, " thread_id=%" PRId64 "\n", value->thread_id);
> + if (value->holders) {
> + monitor_printf(mon, " holders=");
> + for (h = value->holders; h; h = h->next) {
> + IOThreadHolder *holder = h->value;
> +
> + switch (holder->type) {
> + case IO_THREAD_HOLDER_KIND_BLOCK_EXPORT:
> + monitor_printf(mon, "[block-export: %s]",
> + holder->u.block_export.export_id);
> + break;
> + case IO_THREAD_HOLDER_KIND_QOM_OBJECT:
> + monitor_printf(mon, "[qom-path: %s]",
> + holder->u.qom_object.qom_path);
> + break;
> + default:
> + monitor_printf(mon, "[unknown]");
> + break;
> + }
> + }
> + monitor_printf(mon, "\n");
> + }
This prints nothing when we have no holders.
If you delete the if (value->holders) guard, it prints a line
holders=
Matter of taste. Anyone got a preference?
> monitor_printf(mon, " poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
> monitor_printf(mon, " poll-grow=%" PRId64 "\n", value->poll_grow);
> monitor_printf(mon, " poll-shrink=%" PRId64 "\n", value->poll_shrink);
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH V11 13/15] monitor/hmp: display IOThread holders
2026-08-07 13:44 ` Markus Armbruster
@ 2026-08-11 8:44 ` Zhang Chen
0 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-11 8:44 UTC (permalink / raw)
To: Markus Armbruster
Cc: qemu-devel, Eric Blake, Michael S . Tsirkin, Stefan Hajnoczi,
Paolo Bonzini, Daniel P . Berrangé, Jason Wang
On Fri, Aug 7, 2026 at 9:44 PM Markus Armbruster <armbru@redhat.com> wrote:
>
> Zhang Chen <zhangckid@gmail.com> writes:
>
> > Display holder information in info iothreads to aid manual debugging.
> > Omit the holders line when an IOThread has no holders.
> >
> > Signed-off-by: Zhang Chen <zhangckid@gmail.com>
> > ---
> > monitor/hmp-cmds.c | 22 ++++++++++++++++++++++
> > 1 file changed, 22 insertions(+)
> >
> > diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
> > index e9fb8d827a..de37f83a72 100644
> > --- a/monitor/hmp-cmds.c
> > +++ b/monitor/hmp-cmds.c
> > @@ -240,11 +240,33 @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
> > IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
> > IOThreadInfoList *info;
> > IOThreadInfo *value;
> > + IOThreadHolderList *h;
> >
> > for (info = info_list; info; info = info->next) {
> > value = info->value;
> > monitor_printf(mon, "%s:\n", value->id);
> > monitor_printf(mon, " thread_id=%" PRId64 "\n", value->thread_id);
> > + if (value->holders) {
> > + monitor_printf(mon, " holders=");
> > + for (h = value->holders; h; h = h->next) {
> > + IOThreadHolder *holder = h->value;
> > +
> > + switch (holder->type) {
> > + case IO_THREAD_HOLDER_KIND_BLOCK_EXPORT:
> > + monitor_printf(mon, "[block-export: %s]",
> > + holder->u.block_export.export_id);
> > + break;
> > + case IO_THREAD_HOLDER_KIND_QOM_OBJECT:
> > + monitor_printf(mon, "[qom-path: %s]",
> > + holder->u.qom_object.qom_path);
> > + break;
> > + default:
> > + monitor_printf(mon, "[unknown]");
> > + break;
> > + }
> > + }
> > + monitor_printf(mon, "\n");
> > + }
>
> This prints nothing when we have no holders.
>
> If you delete the if (value->holders) guard, it prints a line
>
> holders=
>
> Matter of taste. Anyone got a preference?
OK, I will update it as the comments.
Thanks
Chen
>
> > monitor_printf(mon, " poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
> > monitor_printf(mon, " poll-grow=%" PRId64 "\n", value->poll_grow);
> > monitor_printf(mon, " poll-shrink=%" PRId64 "\n", value->poll_shrink);
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH V11 14/15] iothread: remove legacy iothread_get_aio_context()
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (12 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 13/15] monitor/hmp: display IOThread holders Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
2026-08-06 20:25 ` [PATCH V11 15/15] tests/unit/iothread: update AioContext ref/put helpers Zhang Chen
14 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
All production callers have migrated to either the holder-tracking
iothread_ref_and_get_aio_context() API or the explicitly unsafe legacy
accessor. Remove the now-unused ambiguous getter.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
include/system/iothread.h | 1 -
iothread.c | 5 -----
2 files changed, 6 deletions(-)
diff --git a/include/system/iothread.h b/include/system/iothread.h
index cf1b6e0cdc..2e28fd3ad0 100644
--- a/include/system/iothread.h
+++ b/include/system/iothread.h
@@ -66,7 +66,6 @@ DECLARE_INSTANCE_CHECKER(IOThread, IOTHREAD,
char *iothread_get_id(IOThread *iothread);
IOThread *iothread_by_id(const char *id);
-AioContext *iothread_get_aio_context(IOThread *iothread);
/*
* Return @iothread's AioContext without registering a holder or taking a
diff --git a/iothread.c b/iothread.c
index 43f42c65c8..06c5926b6e 100644
--- a/iothread.c
+++ b/iothread.c
@@ -422,11 +422,6 @@ char *iothread_get_id(IOThread *iothread)
return g_strdup(object_get_canonical_path_component(OBJECT(iothread)));
}
-AioContext *iothread_get_aio_context(IOThread *iothread)
-{
- return iothread->ctx;
-}
-
AioContext *iothread_ref_and_get_aio_context(IOThread *iothread,
const IOThreadHolder *holder)
{
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH V11 15/15] tests/unit/iothread: update AioContext ref/put helpers
2026-08-06 20:25 [PATCH V11 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
` (13 preceding siblings ...)
2026-08-06 20:25 ` [PATCH V11 14/15] iothread: remove legacy iothread_get_aio_context() Zhang Chen
@ 2026-08-06 20:25 ` Zhang Chen
14 siblings, 0 replies; 22+ messages in thread
From: Zhang Chen @ 2026-08-06 20:25 UTC (permalink / raw)
To: qemu-devel, Eric Blake, Markus Armbruster, Michael S . Tsirkin,
Stefan Hajnoczi, Paolo Bonzini,
'Daniel P . Berrangé', Jason Wang
Cc: Zhang Chen
Update the unit-test IOThread stubs and callers to use
iothread_ref_and_get_aio_context() together with the matching
iothread_put_aio_context().
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
tests/unit/iothread.c | 17 +++++++++++------
tests/unit/iothread.h | 6 +++++-
tests/unit/test-aio-multithread.c | 5 ++++-
tests/unit/test-bdrv-drain.c | 18 +++++++++++++-----
tests/unit/test-block-iothread.c | 21 ++++++++++++++-------
5 files changed, 47 insertions(+), 20 deletions(-)
diff --git a/tests/unit/iothread.c b/tests/unit/iothread.c
index a363bf8f70..af3e264e02 100644
--- a/tests/unit/iothread.c
+++ b/tests/unit/iothread.c
@@ -30,12 +30,22 @@ struct IOThread {
bool stopping;
};
+AioContext *iothread_ref_and_get_aio_context(IOThread *iothread,
+ IOThreadHolder *holder)
+{
+ return iothread->ctx;
+}
+
+void iothread_put_aio_context(IOThread *iothread, IOThreadHolder *holder)
+{
+}
+
static void iothread_init_gcontext(IOThread *iothread)
{
GSource *source;
iothread->worker_context = g_main_context_new();
- source = aio_get_g_source(iothread_get_aio_context(iothread));
+ source = aio_get_g_source(iothread->ctx);
g_source_attach(source, iothread->worker_context);
g_source_unref(source);
iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
@@ -113,8 +123,3 @@ IOThread *iothread_new(void)
qemu_mutex_unlock(&iothread->init_done_lock);
return iothread;
}
-
-AioContext *iothread_get_aio_context(IOThread *iothread)
-{
- return iothread->ctx;
-}
diff --git a/tests/unit/iothread.h b/tests/unit/iothread.h
index eb4d0c77f8..49e97b43d4 100644
--- a/tests/unit/iothread.h
+++ b/tests/unit/iothread.h
@@ -17,9 +17,13 @@
#include "qemu/thread.h"
typedef struct IOThread IOThread;
+typedef struct IOThreadHolder IOThreadHolder;
+
+AioContext *iothread_ref_and_get_aio_context(IOThread *iothread,
+ IOThreadHolder *holder);
+void iothread_put_aio_context(IOThread *iothread, IOThreadHolder *holder);
IOThread *iothread_new(void);
void iothread_join(IOThread *iothread);
-AioContext *iothread_get_aio_context(IOThread *iothread);
#endif
diff --git a/tests/unit/test-aio-multithread.c b/tests/unit/test-aio-multithread.c
index 9179cdc6a3..a63e54fe62 100644
--- a/tests/unit/test-aio-multithread.c
+++ b/tests/unit/test-aio-multithread.c
@@ -69,7 +69,7 @@ static void create_aio_contexts(void)
for (i = 0; i < NUM_CONTEXTS; i++) {
threads[i] = iothread_new();
- ctx[i] = iothread_get_aio_context(threads[i]);
+ ctx[i] = iothread_ref_and_get_aio_context(threads[i], NULL);
}
qemu_event_init(&done_event, false);
@@ -87,6 +87,9 @@ static void join_aio_contexts(void)
for (i = 0; i < NUM_CONTEXTS; i++) {
aio_context_ref(ctx[i]);
}
+ for (i = 0; i < NUM_CONTEXTS; i++) {
+ iothread_put_aio_context(threads[i], NULL);
+ }
for (i = 0; i < NUM_CONTEXTS; i++) {
iothread_join(threads[i]);
}
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
index 43b0ba8648..b9b153f95d 100644
--- a/tests/unit/test-bdrv-drain.c
+++ b/tests/unit/test-bdrv-drain.c
@@ -537,8 +537,8 @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
IOThread *a = iothread_new();
IOThread *b = iothread_new();
- AioContext *ctx_a = iothread_get_aio_context(a);
- AioContext *ctx_b = iothread_get_aio_context(b);
+ AioContext *ctx_a = iothread_ref_and_get_aio_context(a, NULL);
+ AioContext *ctx_b = iothread_ref_and_get_aio_context(b, NULL);
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0);
@@ -612,6 +612,8 @@ static void test_iothread_common(enum drain_type drain_type, int drain_thread)
bdrv_unref(bs);
blk_unref(blk);
+ iothread_put_aio_context(a, NULL);
+ iothread_put_aio_context(b, NULL);
out:
iothread_join(a);
@@ -762,7 +764,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
AioContext *ctx;
iothread = iothread_new();
- ctx = iothread_get_aio_context(iothread);
+ ctx = iothread_ref_and_get_aio_context(iothread, NULL);
blk_set_aio_context(blk_src, ctx, &error_abort);
}
@@ -892,6 +894,10 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
bdrv_unref(src_overlay);
bdrv_unref(target);
+ if (use_iothread) {
+ iothread_put_aio_context(iothread, NULL);
+ }
+
if (iothread) {
iothread_join(iothread);
}
@@ -1398,8 +1404,8 @@ static void test_set_aio_context(void)
BlockDriverState *bs;
IOThread *a = iothread_new();
IOThread *b = iothread_new();
- AioContext *ctx_a = iothread_get_aio_context(a);
- AioContext *ctx_b = iothread_get_aio_context(b);
+ AioContext *ctx_a = iothread_ref_and_get_aio_context(a, NULL);
+ AioContext *ctx_b = iothread_ref_and_get_aio_context(b, NULL);
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
&error_abort);
@@ -1410,6 +1416,8 @@ static void test_set_aio_context(void)
bdrv_try_change_aio_context(bs, qemu_get_aio_context(), NULL, &error_abort);
bdrv_unref(bs);
+ iothread_put_aio_context(a, NULL);
+ iothread_put_aio_context(b, NULL);
iothread_join(a);
iothread_join(b);
}
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
index 5273ff235a..391b28b73a 100644
--- a/tests/unit/test-block-iothread.c
+++ b/tests/unit/test-block-iothread.c
@@ -466,7 +466,7 @@ static void test_sync_op(const void *opaque)
{
const SyncOpTest *t = opaque;
IOThread *iothread = iothread_new();
- AioContext *ctx = iothread_get_aio_context(iothread);
+ AioContext *ctx = iothread_ref_and_get_aio_context(iothread, NULL);
BlockBackend *blk;
BlockDriverState *bs;
BdrvChild *c;
@@ -493,6 +493,7 @@ static void test_sync_op(const void *opaque)
bdrv_unref(bs);
blk_unref(blk);
+ iothread_put_aio_context(iothread, NULL);
}
typedef struct TestBlockJob {
@@ -549,7 +550,7 @@ BlockJobDriver test_job_driver = {
static void test_attach_blockjob(void)
{
IOThread *iothread = iothread_new();
- AioContext *ctx = iothread_get_aio_context(iothread);
+ AioContext *ctx = iothread_ref_and_get_aio_context(iothread, NULL);
BlockBackend *blk;
BlockDriverState *bs;
TestBlockJob *tjob;
@@ -595,6 +596,7 @@ static void test_attach_blockjob(void)
bdrv_unref(bs);
blk_unref(blk);
+ iothread_put_aio_context(iothread, NULL);
}
/*
@@ -612,7 +614,7 @@ static void test_attach_blockjob(void)
static void test_propagate_basic(void)
{
IOThread *iothread = iothread_new();
- AioContext *ctx = iothread_get_aio_context(iothread);
+ AioContext *ctx = iothread_ref_and_get_aio_context(iothread, NULL);
AioContext *main_ctx;
BlockBackend *blk;
BlockDriverState *bs_a, *bs_b, *bs_verify;
@@ -658,6 +660,7 @@ static void test_propagate_basic(void)
bdrv_unref(bs_b);
bdrv_unref(bs_a);
blk_unref(blk);
+ iothread_put_aio_context(iothread, NULL);
}
/*
@@ -676,7 +679,7 @@ static void test_propagate_basic(void)
static void test_propagate_diamond(void)
{
IOThread *iothread = iothread_new();
- AioContext *ctx = iothread_get_aio_context(iothread);
+ AioContext *ctx = iothread_ref_and_get_aio_context(iothread, NULL);
AioContext *main_ctx;
BlockBackend *blk;
BlockDriverState *bs_a, *bs_b, *bs_c, *bs_verify;
@@ -736,12 +739,13 @@ static void test_propagate_diamond(void)
bdrv_unref(bs_c);
bdrv_unref(bs_b);
bdrv_unref(bs_a);
+ iothread_put_aio_context(iothread, NULL);
}
static void test_propagate_mirror(void)
{
IOThread *iothread = iothread_new();
- AioContext *ctx = iothread_get_aio_context(iothread);
+ AioContext *ctx = iothread_ref_and_get_aio_context(iothread, NULL);
AioContext *main_ctx = qemu_get_aio_context();
BlockDriverState *src, *target, *filter;
BlockBackend *blk;
@@ -807,12 +811,13 @@ static void test_propagate_mirror(void)
blk_unref(blk);
bdrv_unref(src);
bdrv_unref(target);
+ iothread_put_aio_context(iothread, NULL);
}
static void test_attach_second_node(void)
{
IOThread *iothread = iothread_new();
- AioContext *ctx = iothread_get_aio_context(iothread);
+ AioContext *ctx = iothread_ref_and_get_aio_context(iothread, NULL);
AioContext *main_ctx = qemu_get_aio_context();
BlockBackend *blk;
BlockDriverState *bs, *filter;
@@ -840,12 +845,13 @@ static void test_attach_second_node(void)
bdrv_unref(filter);
bdrv_unref(bs);
blk_unref(blk);
+ iothread_put_aio_context(iothread, NULL);
}
static void test_attach_preserve_blk_ctx(void)
{
IOThread *iothread = iothread_new();
- AioContext *ctx = iothread_get_aio_context(iothread);
+ AioContext *ctx = iothread_ref_and_get_aio_context(iothread, NULL);
BlockBackend *blk;
BlockDriverState *bs;
@@ -871,6 +877,7 @@ static void test_attach_preserve_blk_ctx(void)
blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
bdrv_unref(bs);
blk_unref(blk);
+ iothread_put_aio_context(iothread, NULL);
}
int main(int argc, char **argv)
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread