All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: Zhang Chen <zhangckid@gmail.com>
Cc: 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>
Subject: Re: [PATCH V8 02/15] iothread: introduce iothread_ref/unref to track attached devices
Date: Tue, 02 Jun 2026 13:29:19 +0200	[thread overview]
Message-ID: <87tsrl2nao.fsf@pond.sub.org> (raw)
In-Reply-To: <20260529213321.96271-3-zhangckid@gmail.com> (Zhang Chen's message of "Sat, 30 May 2026 05:33:08 +0800")

Zhang Chen <zhangckid@gmail.com> writes:

> 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 custom
>   string comparison (g_strcmp0), releases the associated memory
>   upon a successful match.
> - holders: A GList 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>
> ---
>  include/system/iothread.h |  5 +++
>  iothread.c                | 94 +++++++++++++++++++++++++++++++++++++++
>  qapi/misc.json            | 61 +++++++++++++++++++++++++
>  3 files changed, 160 insertions(+)
>
> diff --git a/include/system/iothread.h b/include/system/iothread.h
> index a1ef7696cb..b9207ad829 100644
> --- a/include/system/iothread.h
> +++ b/include/system/iothread.h
> @@ -50,6 +50,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 node name.

You forgot monitors.

Suggest "which can either be a QOM object, a block node, or a monitor."

> +     */
> +    GList *holders;
>  
>      /* AioContext poll parameters */
>      int64_t poll_max_ns;
> diff --git a/iothread.c b/iothread.c
> index 3558535b40..3301b8d495 100644
> --- a/iothread.c
> +++ b/iothread.c
> @@ -25,6 +25,92 @@
>  #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.
> + */
> +static void iothread_ref(IOThread *iothread, const IOThreadHolder *holder)

Yes, this is the interface I want :)

> +{
> +    assert(holder);
> +    IOThreadHolder *h = g_new0(IOThreadHolder, 1);
> +
> +    h->type = holder->type;
> +    switch (holder->type) {
> +    case IO_THREAD_HOLDER_KIND_QOM_OBJECT:
> +        h->u.qom_object.qom_path = g_strdup(holder->u.qom_object.qom_path);
> +        break;
> +    case IO_THREAD_HOLDER_KIND_BLOCK_NODE:
> +        h->u.block_node.node_name =
> +            g_strdup(holder->u.block_node.node_name);
> +        break;
> +    case IO_THREAD_HOLDER_KIND_MONITOR_NAME:
> +        h->u.monitor_name.monitor_name =
> +            g_strdup(holder->u.monitor_name.monitor_name);
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }

This makes @h a deep copy of @holder.  Try

    IOThreadHolder *h = QAPI_CLONE(IOThreadHolder, holder);

instead.

Instead of making a copy, the function could take ownership of @holder,
and require @holder's members to be dynamically allocated.  More
efficient, but complicates the callers somewhat.  Not worthwhile, I
guess.

> +
> +    iothread->holders = g_list_prepend(iothread->holders, h);
> +}
> +
> +static int iothread_holder_compare(gconstpointer a, gconstpointer b)
> +{
> +    const IOThreadHolder *holder_a = a;
> +    const IOThreadHolder *holder_b = b;
> +    const char *name_a, *name_b;
> +
> +    if (holder_a->type != holder_b->type) {
> +        return -1;

Please use

           return holder_b->type - holder_a->type;

Why?  By convention, an int-valued function fn() comparing A to B
returns less than 0 when A<B, 0 when A == B, and greater than 0 when
A>B.  Anything else needs a prominent comment.  Best to stick to the
convention whenever practical.

Since A < B iff B > A, we want fn(A, B) == -fn(B, A).

Your function does not satisfy that!  Harmless for now, because you only
ever pass it to g_list_find_custom(), which treats all non-zero values
the same.  But if anyone passes it to something like qsort() in the
future, they can look forward to some debugging "fun".

> +    }
> +
> +    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_NODE:
> +        name_a = holder_a->u.block_node.node_name;
> +        name_b = holder_b->u.block_node.node_name;
> +        break;
> +    case IO_THREAD_HOLDER_KIND_MONITOR_NAME:
> +        name_a = holder_a->u.monitor_name.monitor_name;
> +        name_b = holder_b->u.monitor_name.monitor_name;
> +        break;
> +    default:
> +       /*
> +        * This should not happen. If it does, name_a/b remains
> +        * NULL and g_strcmp0 will handle it safely.
> +        */
> +        name_a = NULL;
> +        name_b = NULL;

Replace this by

           g_assert_not_reached();

Then neither @name_a nor @name_b can be null, because a non-optional
QAPI str is never null.  Simply use strcmp().

> +    }
> +
> +    return g_strcmp0(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.
> + */
> +static void iothread_unref(IOThread *iothread, const IOThreadHolder *holder)
> +{
> +    assert(holder);
> +    GList *link = g_list_find_custom(iothread->holders, holder,
> +                                     (GCompareFunc)iothread_holder_compare);
> +
> +    assert(link);
> +
> +    IOThreadHolder *h = (IOThreadHolder *)link->data;
> +    qapi_free_IOThreadHolder(h);
> +    iothread->holders = g_list_delete_link(iothread->holders, link);

Removing @link from the list before freeing link->data would be more
obviously correct, wouldn't it?

> +}
> +
>  static void *iothread_run(void *opaque)
>  {
>      IOThread *iothread = opaque;
> @@ -356,6 +442,14 @@ char *iothread_get_id(IOThread *iothread)
>  
>  AioContext *iothread_get_aio_context(IOThread *iothread)
>  {
> +    /* Remove in next patch for build */
> +    IOThreadHolder holder = {
> +        .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
> +        .u.qom_object.qom_path = (char *)"tmp_path",
> +    };
> +    iothread_ref(iothread, &holder);
> +    iothread_unref(iothread, &holder);
> +

Is this really needed to make this patch work?

>      return iothread->ctx;
>  }
>  
> diff --git a/qapi/misc.json b/qapi/misc.json
> index c71a5fe657..d9f82f0922 100644
> --- a/qapi/misc.json
> +++ b/qapi/misc.json
> @@ -67,6 +67,67 @@
>  ##
>  { 'command': 'query-name', 'returns': 'NameInfo', 'allow-preconfig': true }
>  
> +
> +##
> +# @IOThreadHolderBlockNode:
> +#
> +# @node-name: A block node.

Let's use

   # @node-name: Name of the block node

to make it more similar to node-name descriptions elsewhere.

> +#
> +# Since: 11.1
> +#
> +##
> +{ 'struct': 'IOThreadHolderBlockNode',
> +  'data': { 'node-name': 'str' } }
> +
> +##
> +# @IOThreadHolderQomObject:
> +#
> +# @qom-path: A QOM Object.

Likewise, let's use

  # @qom-path: Path to the object in the QOM tree

> +#
> +# Since: 11.1
> +#
> +##
> +{ 'struct': 'IOThreadHolderQomObject',
> +  'data': { 'qom-path': 'str' } }
> +
> +##
> +# @IOThreadHolderMonitor:
> +#

Let's use

   # @monitor-name: Name of the HMP/QMP monitor

> +# @monitor-name: A HMP/QMP monitor.
> +#
> +# Since: 11.1
> +#
> +##
> +{ 'struct': 'IOThreadHolderMonitor',
> +  'data': { 'monitor-name': 'str' } }
> +
> +##
> +# @IOThreadHolderKind:
> +#
> +# @block-node: A block node.
> +# @qom-object: A QOM Object.
> +# @monitor-name: A HMP/QMP monitor.

Rename to @monitor for consistency with the other two.

Remark, not a request to change anything in your patch: kind monitor
will become obsolete when monitors become QOM objects.  Doing that
before we release this interface is desirable.

> +#
> +# Since: 11.1
> +##
> +{ 'enum': 'IOThreadHolderKind',
> +  'data': [ 'block-node', 'qom-object', 'monitor-name' ] }
> +
> +##
> +# @IOThreadHolder:
> +#

Let's add a short description:

   # The block node, QOM object, or monitor 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-node': 'IOThreadHolderBlockNode',
> +    'qom-object': 'IOThreadHolderQomObject',
> +    'monitor-name': 'IOThreadHolderMonitor' } }
> +
>  ##
>  # @IOThreadInfo:
>  #



  reply	other threads:[~2026-06-02 11:30 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-29 21:33 [PATCH V8 00/15] iothread: Support tracking and querying IOThread holders Zhang Chen
2026-05-29 21:33 ` [PATCH V8 01/15] qapi/misc: Fix missed query-iothreads items Zhang Chen
2026-05-29 21:33 ` [PATCH V8 02/15] iothread: introduce iothread_ref/unref to track attached devices Zhang Chen
2026-06-02 11:29   ` Markus Armbruster [this message]
2026-05-29 21:33 ` [PATCH V8 03/15] iothread: tracking iothread users with holder name Zhang Chen
2026-05-29 21:33 ` [PATCH V8 04/15] iothread: introduce iothread_unsafe_get_aio_context() Zhang Chen
2026-05-29 21:33 ` [PATCH V8 05/15] block/export: track IOThread reference in BlockExport Zhang Chen
2026-05-29 21:33 ` [PATCH V8 06/15] monitor: assign unique default ID to anonymous monitors Zhang Chen
2026-06-02 17:02   ` Markus Armbruster
2026-06-04  9:57     ` Zhang Chen
2026-05-29 21:33 ` [PATCH V8 07/15] monitor: Update tracking iothread users with holder Zhang Chen
2026-06-02 17:20   ` Markus Armbruster
2026-06-04 10:16     ` Zhang Chen
2026-05-29 21:33 ` [PATCH V8 08/15] virtio-vq-mapping: track iothread-vq-mapping references using device path Zhang Chen
2026-05-29 21:33 ` [PATCH V8 09/15] virtio: use iothread_get/put_aio_context for thread pinning Zhang Chen
2026-05-29 21:33 ` [PATCH V8 10/15] net/colo: track IOThread references using path-based holder Zhang Chen
2026-05-29 21:33 ` [PATCH V8 11/15] virtio-balloon: Update tracking iothread users with holder Zhang Chen
2026-05-29 21:33 ` [PATCH V8 12/15] vfio-user/proxy: Update tracking iothread users with holder name Zhang Chen
2026-05-29 21:33 ` [PATCH V8 13/15] xen-block: " Zhang Chen
2026-05-29 21:33 ` [PATCH V8 14/15] qapi: examine IOThread attachment status via query-iothreads Zhang Chen
2026-06-02 17:34   ` Markus Armbruster
2026-06-04 11:49     ` Zhang Chen
2026-05-29 21:33 ` [PATCH V8 15/15] iothread: simplify API by merging iothread_get_aio_context variants Zhang Chen
2026-06-02 17:41   ` Markus Armbruster
2026-06-04 11:53     ` 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=87tsrl2nao.fsf@pond.sub.org \
    --to=armbru@redhat.com \
    --cc=dave@treblig.org \
    --cc=eblake@redhat.com \
    --cc=mst@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    --cc=zhangckid@gmail.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.