[PATCH V5 06/13] virtio: use iothread_get/put_aio_context for thread pinning

Zhang Chen posted 13 patches 1 month, 1 week ago
Maintainers: Kevin Wolf <kwolf@redhat.com>, Hanna Reitz <hreitz@redhat.com>, Stefan Hajnoczi <stefanha@redhat.com>, Stefano Stabellini <sstabellini@kernel.org>, Anthony PERARD <anthony@xenproject.org>, "Edgar E. Iglesias" <edgar.iglesias@gmail.com>, "Michael S. Tsirkin" <mst@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, Fam Zheng <fam@euphon.net>, John Levon <john.levon@nutanix.com>, Thanos Makatos <thanos.makatos@nutanix.com>, "Cédric Le Goater" <clg@redhat.com>, David Hildenbrand <david@kernel.org>, "Dr. David Alan Gilbert" <dave@treblig.org>, Markus Armbruster <armbru@redhat.com>, Zhang Chen <zhangckid@gmail.com>, Li Zhijian <lizhijian@fujitsu.com>, Jason Wang <jasowang@redhat.com>, Eric Blake <eblake@redhat.com>
There is a newer version of this series
[PATCH V5 06/13] virtio: use iothread_get/put_aio_context for thread pinning
Posted by Zhang Chen 1 month, 1 week ago
Refactor virtio-blk and virtio-scsi to use the new iothread_get/put
APIs for AioContext management. This ensures IOThread references
are tracked via the device's canonical QOM path.

Summary of changes:
- Lift 'path' scope to cover both vq_mapping and single iothread cases.
- Replace raw object_ref/unref with iothread_get/put_aio_context.
- Ensure consistent memory cleanup of the QOM path string.

Signed-off-by: Zhang Chen <zhangckid@gmail.com>
---
 hw/block/virtio-blk.c           | 17 ++++++-----------
 hw/scsi/virtio-scsi-dataplane.c | 18 +++++++-----------
 2 files changed, 13 insertions(+), 22 deletions(-)

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index b6f74df68f..94a70c6212 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -1429,6 +1429,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);
+    char *path = object_get_canonical_path(OBJECT(vdev));
 
     if (conf->iothread && conf->iothread_vq_mapping_list) {
         error_setg(errp,
@@ -1453,8 +1454,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) {
-        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,
@@ -1465,15 +1464,11 @@ static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
             s->vq_aio_context = NULL;
             return false;
         }
-        g_free(path);
     } else if (conf->iothread) {
-        AioContext *ctx = iothread_get_aio_context(conf->iothread);
+        AioContext *ctx = iothread_get_aio_context(conf->iothread, path);
         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++) {
@@ -1481,6 +1476,7 @@ static bool virtio_blk_vq_aio_context_init(VirtIOBlock *s, Error **errp)
         }
     }
 
+    g_free(path);
     return true;
 }
 
@@ -1488,20 +1484,19 @@ 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;
+    char *path = object_get_canonical_path(OBJECT(VIRTIO_DEVICE(s)));
 
     assert(!s->ioeventfd_started);
 
     if (conf->iothread_vq_mapping_list) {
-        char *path = object_get_canonical_path(OBJECT(VIRTIO_DEVICE(s)));
-
         iothread_vq_mapping_cleanup(conf->iothread_vq_mapping_list, path);
-        g_free(path);
     }
 
     if (conf->iothread) {
-        object_unref(OBJECT(conf->iothread));
+        iothread_put_aio_context(conf->iothread, path);
     }
 
+    g_free(path);
     g_free(s->vq_aio_context);
     s->vq_aio_context = NULL;
 }
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index ed5304c6a9..29615ec63e 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);
+    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) {
-        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,39 +74,36 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
             s->vq_aio_context = NULL;
             return;
         }
-        g_free(path);
     } else if (vs->conf.iothread) {
-        AioContext *ctx = iothread_get_aio_context(vs->conf.iothread);
+        AioContext *ctx = iothread_get_aio_context(vs->conf.iothread, path);
         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++) {
             s->vq_aio_context[VIRTIO_SCSI_VQ_NUM_FIXED + i] = ctx;
         }
     }
+    g_free(path);
 }
 
 /* Context: BQL held */
 void virtio_scsi_dataplane_cleanup(VirtIOSCSI *s)
 {
     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
+    char *path = object_get_canonical_path(OBJECT(VIRTIO_DEVICE(s)));
 
     if (vs->conf.iothread_vq_mapping_list) {
-        char *path = object_get_canonical_path(OBJECT(VIRTIO_DEVICE(s)));
-
         iothread_vq_mapping_cleanup(vs->conf.iothread_vq_mapping_list, path);
-        g_free(path);
+
     }
 
     if (vs->conf.iothread) {
-        object_unref(OBJECT(vs->conf.iothread));
+        iothread_put_aio_context(vs->conf.iothread, path);
     }
 
+    g_free(path);
     g_free(s->vq_aio_context);
     s->vq_aio_context = NULL;
 }
-- 
2.49.0
Re: [PATCH V5 06/13] virtio: use iothread_get/put_aio_context for thread pinning
Posted by Stefan Hajnoczi 1 month ago
On Thu, Mar 05, 2026 at 10:24:52PM +0800, Zhang Chen wrote:
> Refactor virtio-blk and virtio-scsi to use the new iothread_get/put
> APIs for AioContext management. This ensures IOThread references
> are tracked via the device's canonical QOM path.
> 
> Summary of changes:
> - Lift 'path' scope to cover both vq_mapping and single iothread cases.
> - Replace raw object_ref/unref with iothread_get/put_aio_context.
> - Ensure consistent memory cleanup of the QOM path string.
> 
> Signed-off-by: Zhang Chen <zhangckid@gmail.com>
> ---
>  hw/block/virtio-blk.c           | 17 ++++++-----------
>  hw/scsi/virtio-scsi-dataplane.c | 18 +++++++-----------
>  2 files changed, 13 insertions(+), 22 deletions(-)
> 
> diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> index b6f74df68f..94a70c6212 100644
> --- a/hw/block/virtio-blk.c
> +++ b/hw/block/virtio-blk.c
> @@ -1429,6 +1429,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);
> +    char *path = object_get_canonical_path(OBJECT(vdev));
>  
>      if (conf->iothread && conf->iothread_vq_mapping_list) {
>          error_setg(errp,

There is a memory leak when this returns false. Please use g_autofree
when declaring temporary string variables instead of calling g_free()
manually.
Re: [PATCH V5 06/13] virtio: use iothread_get/put_aio_context for thread pinning
Posted by Zhang Chen 1 month ago
On Mon, Mar 9, 2026 at 4:27 PM Stefan Hajnoczi <stefanha@redhat.com> wrote:
>
> On Thu, Mar 05, 2026 at 10:24:52PM +0800, Zhang Chen wrote:
> > Refactor virtio-blk and virtio-scsi to use the new iothread_get/put
> > APIs for AioContext management. This ensures IOThread references
> > are tracked via the device's canonical QOM path.
> >
> > Summary of changes:
> > - Lift 'path' scope to cover both vq_mapping and single iothread cases.
> > - Replace raw object_ref/unref with iothread_get/put_aio_context.
> > - Ensure consistent memory cleanup of the QOM path string.
> >
> > Signed-off-by: Zhang Chen <zhangckid@gmail.com>
> > ---
> >  hw/block/virtio-blk.c           | 17 ++++++-----------
> >  hw/scsi/virtio-scsi-dataplane.c | 18 +++++++-----------
> >  2 files changed, 13 insertions(+), 22 deletions(-)
> >
> > diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
> > index b6f74df68f..94a70c6212 100644
> > --- a/hw/block/virtio-blk.c
> > +++ b/hw/block/virtio-blk.c
> > @@ -1429,6 +1429,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);
> > +    char *path = object_get_canonical_path(OBJECT(vdev));
> >
> >      if (conf->iothread && conf->iothread_vq_mapping_list) {
> >          error_setg(errp,
>
> There is a memory leak when this returns false. Please use g_autofree
> when declaring temporary string variables instead of calling g_free()
> manually.

Sure.

Thanks
Chen