From: Zhang Chen <zhangckid@gmail.com>
To: qemu-devel <qemu-devel@nongnu.org>,
"Eric Blake" <eblake@redhat.com>,
"Markus Armbruster" <armbru@redhat.com>,
"'Michael S . Tsirkin'" <mst@redhat.com>,
"Stefan Hajnoczi" <stefanha@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"'Daniel P . Berrangé'" <berrange@redhat.com>,
"Jason Wang" <jasowangio@gmail.com>
Cc: Zhang Chen <zhangckid@gmail.com>
Subject: [PATCH V16 01/13] iothread: introduce holder tracking
Date: Fri, 11 Sep 2026 18:06:57 +0800 [thread overview]
Message-ID: <20260911100709.726366-2-zhangckid@gmail.com> (raw)
In-Reply-To: <20260911100709.726366-1-zhangckid@gmail.com>
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.
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Zhang Chen <zhangckid@gmail.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..66dfde626e 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_a->type - holder_b->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 baa50cc844..bb49969b4b 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.43.0
next prev parent reply other threads:[~2026-09-11 10:08 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-11 10:06 [PATCH V16 00/13] iothread: Support tracking and querying IOThread holder Zhang Chen
2026-09-11 10:06 ` Zhang Chen [this message]
2026-09-11 10:06 ` [PATCH V16 02/13] iothread: add holder-aware AioContext accessors Zhang Chen
2026-09-11 10:06 ` [PATCH V16 03/13] block/export: track IOThread references Zhang Chen
2026-09-11 10:07 ` [PATCH V16 04/13] monitor: track IOThread users with QOM paths Zhang Chen
2026-09-11 10:07 ` [PATCH V16 05/13] virtio-vq-mapping: track iothread-vq-mapping references using device path Zhang Chen
2026-09-11 10:07 ` [PATCH V16 06/13] virtio: track IOThread references for thread pinning Zhang Chen
2026-09-11 10:07 ` [PATCH V16 07/13] net/colo: track IOThread references using path-based holder Zhang Chen
2026-09-11 10:07 ` [PATCH V16 08/13] virtio-balloon: Update tracking iothread users with holder Zhang Chen
2026-09-11 10:07 ` [PATCH V16 09/13] vfio-user/proxy: Update tracking iothread users with holder name Zhang Chen
2026-09-11 10:07 ` [PATCH V16 10/13] xen-block: " Zhang Chen
2026-09-11 10:07 ` [PATCH V16 11/13] monitor/hmp: display IOThread holders Zhang Chen
2026-09-11 10:07 ` [PATCH V16 12/13] iothread: make legacy AioContext getter explicitly unsafe Zhang Chen
2026-09-11 10:07 ` [PATCH V16 13/13] tests/unit/iothread: update AioContext ref/put helpers Zhang Chen
2026-09-11 10:52 ` [PATCH V16 00/13] iothread: Support tracking and querying IOThread holder Markus Armbruster
2026-09-11 12:53 ` Zhang Chen
2026-09-11 13:36 ` Markus Armbruster
2026-09-11 14:26 ` Zhang Chen
2026-09-15 7:33 ` Markus Armbruster
2026-09-15 9:47 ` Zhang Chen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260911100709.726366-2-zhangckid@gmail.com \
--to=zhangckid@gmail.com \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=eblake@redhat.com \
--cc=jasowangio@gmail.com \
--cc=mst@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox