From: Zhang Chen <zhangckid@gmail.com>
To: qemu-devel <qemu-devel@nongnu.org>,
"Dr . David Alan Gilbert" <dave@treblig.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>,
"Kevin Wolf" <kwolf@redhat.com>,
"Jason Wang" <jasowang@redhat.com>, "Fam Zheng" <fam@euphon.net>,
"Daniel P . Berrangé" <berrange@redhat.com>
Cc: Zhang Chen <zhangckid@gmail.com>
Subject: [PATCH V10 02/15] iothread: introduce iothread_ref/unref to track attached devices
Date: Thu, 16 Jul 2026 22:40:27 +0800 [thread overview]
Message-ID: <20260716144043.76414-3-zhangckid@gmail.com> (raw)
In-Reply-To: <20260716144043.76414-1-zhangckid@gmail.com>
Currently, IOThreads do not maintain a record of which devices are
associated with them. This makes it difficult to monitor the
workload distribution of IOThreads, especially in complex
hotplug scenarios involving multiple virtio-blk or virtio-scsi devices.
This patch introduces a reference counting and tracking mechanism
within the IOThread object:
- iothread_ref(): Prepends the device's IOThreadHolder to a list.
- iothread_unref(): Searches for the IOThreadHolder using a
string comparison (strcmp), releases the associated memory
upon a successful match.
- holders: A IOThreadHolderList storing the IOThreadHolder
of attached devices for runtime introspection.
A later commit will add QMP commands to let management applications
query the attachment status of IOThreads.
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/system/iothread.h | 11 ++++++
iothread.c | 70 +++++++++++++++++++++++++++++++++++++++
qapi/misc.json | 59 +++++++++++++++++++++++++++++++++
3 files changed, 140 insertions(+)
diff --git a/include/system/iothread.h b/include/system/iothread.h
index a1ef7696cb..ef0b2f9648 100644
--- a/include/system/iothread.h
+++ b/include/system/iothread.h
@@ -38,6 +38,9 @@
#define IOTHREAD_POLL_WEIGHT_DEFAULT 0ULL
#endif
+typedef struct IOThreadHolder IOThreadHolder;
+typedef struct IOThreadHolderList IOThreadHolderList;
+
struct IOThread {
EventLoopBase parent_obj;
@@ -50,6 +53,11 @@ struct IOThread {
bool stopping; /* has iothread_stop() been called? */
bool running; /* should iothread_run() continue? */
int thread_id;
+ /*
+ * The list elements are of type IOThreadHolder, which can
+ * represent either a QOM path or a block export name.
+ */
+ IOThreadHolderList *holders;
/* AioContext poll parameters */
int64_t poll_max_ns;
@@ -82,4 +90,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..38f273c0e9 100644
--- a/iothread.c
+++ b/iothread.c
@@ -21,10 +21,78 @@
#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"
+/*
+ * iothread_ref:
+ * @iothread: the iothread to track
+ * @holder: the IOThreadHolder object initialized by the caller
+ *
+ * Add the @holder to the iothread's tracking list.
+ */
+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_name;
+ name_b = holder_b->u.block_export.export_name;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return strcmp(name_a, name_b);
+}
+
+/*
+ * This function removes the @holder from the @iothread's tracking list.
+ * The @holder must match the one used previously in iothread_ref().
+ * It is a programming error to call this with a @holder that is not
+ * currently associated with the @iothread.
+ */
+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 +197,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 +442,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..096e418b7a 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -67,6 +67,56 @@
##
{ 'command': 'query-name', 'returns': 'NameInfo', 'allow-preconfig': true }
+
+##
+# @IOThreadHolderBlockExport:
+#
+# @export-name: Name of the block export.
+#
+# Since: 11.1
+#
+##
+{ 'struct': 'IOThreadHolderBlockExport',
+ 'data': { 'export-name': 'str' } }
+
+##
+# @IOThreadHolderQomObject:
+#
+# @qom-path: Path to the object in the QOM tree.
+#
+# Since: 11.1
+#
+##
+{ 'struct': 'IOThreadHolderQomObject',
+ 'data': { 'qom-path': 'str' } }
+
+##
+# @IOThreadHolderKind:
+#
+# @block-export: A block export.
+# @qom-object: A QOM Object.
+#
+# Since: 11.1
+##
+{ 'enum': 'IOThreadHolderKind',
+ 'data': [ 'block-export', 'qom-object' ] }
+
+##
+# @IOThreadHolder:
+#
+# The block export or QOM object holding the I/O thread.
+#
+# @type: the kind of I/O thread holder.
+#
+# Since: 11.1
+##
+{ 'union': 'IOThreadHolder',
+ 'base': { 'type': 'IOThreadHolderKind' },
+ 'discriminator': 'type',
+ 'data': {
+ 'block-export': 'IOThreadHolderBlockExport',
+ 'qom-object': 'IOThreadHolderQomObject' } }
+
##
# @IOThreadInfo:
#
@@ -76,6 +126,11 @@
#
# @thread-id: ID of the underlying host thread
#
+# @holders: the QOM objects or block nodes currently
+# associated with this iothread. When an associated component is
+# detached or destroyed, it is removed from this list.
+# (Since 11.1)
+#
# @poll-max-ns: maximum polling time in ns, 0 means polling is
# disabled (since 2.9)
#
@@ -98,6 +153,7 @@
{ 'struct': 'IOThreadInfo',
'data': {'id': 'str',
'thread-id': 'int',
+ 'holders': ['IOThreadHolder'],
'poll-max-ns': 'int',
'poll-grow': 'int',
'poll-shrink': 'int',
@@ -124,6 +180,8 @@
# {
# "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,
@@ -132,6 +190,7 @@
# {
# "id":"iothread1",
# "thread-id":3135,
+# "holders":[{"export-name": "fmt_qcow2", "type": "block-export"}],
# "poll-max-ns":32768,
# "poll-grow":0,
# "poll-shrink":0,
--
2.49.0
next prev parent reply other threads:[~2026-07-16 14:43 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-16 14:40 [PATCH V10 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
2026-07-16 14:40 ` [PATCH V10 01/15] qapi/misc: Fix missed query-iothreads items Zhang Chen
2026-07-16 14:40 ` Zhang Chen [this message]
2026-07-16 14:40 ` [PATCH V10 03/15] iothread: tracking iothread users with holder name Zhang Chen
2026-07-16 14:40 ` [PATCH V10 04/15] iothread: introduce iothread_unsafe_get_aio_context() Zhang Chen
2026-07-16 14:40 ` [PATCH V10 05/15] block/export: track IOThread reference in BlockExport Zhang Chen
2026-07-16 14:40 ` [PATCH V10 06/15] monitor: Update tracking iothread users with holder Zhang Chen
2026-07-16 15:11 ` Daniel P. Berrangé
2026-07-16 16:18 ` Zhang Chen
2026-07-16 14:40 ` [PATCH V10 07/15] virtio-vq-mapping: track iothread-vq-mapping references using device path Zhang Chen
2026-07-16 14:40 ` [PATCH V10 08/15] virtio: use iothread_get/put_aio_context for thread pinning Zhang Chen
2026-07-16 14:40 ` [PATCH V10 09/15] net/colo: track IOThread references using path-based holder Zhang Chen
2026-07-16 14:40 ` [PATCH V10 10/15] virtio-balloon: Update tracking iothread users with holder Zhang Chen
2026-07-16 14:40 ` [PATCH V10 11/15] vfio-user/proxy: Update tracking iothread users with holder name Zhang Chen
2026-07-16 14:40 ` [PATCH V10 12/15] xen-block: " Zhang Chen
2026-07-16 14:40 ` [PATCH V10 13/15] monitor/hmp: Add holders support for hmp_info_iothreads Zhang Chen
2026-07-16 14:40 ` [PATCH V10 14/15] iothread: simplify API by merging iothread_get_aio_context variants Zhang Chen
2026-07-16 14:40 ` [PATCH V10 15/15] tests/unit/iothread: Update the iothread_get_aio_context 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=20260716144043.76414-3-zhangckid@gmail.com \
--to=zhangckid@gmail.com \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=dave@treblig.org \
--cc=eblake@redhat.com \
--cc=fam@euphon.net \
--cc=jasowang@redhat.com \
--cc=kwolf@redhat.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.