Use the holder-aware AioContext APIs to track each proxy's reference
to the shared IOThread, using the owning PCI device's canonical QOM
path as the holder identity. Because the IOChannel has no QOM parent
and therefore cannot provide a canonical path.

Signed-off-by: Zhang Chen <[email protected]>
---
 hw/vfio-user/pci.c   |  2 +-
 hw/vfio-user/proxy.c | 20 ++++++++++++++++++--
 hw/vfio-user/proxy.h |  4 +++-
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/hw/vfio-user/pci.c b/hw/vfio-user/pci.c
index e7573d4a9f..126dfdc897 100644
--- a/hw/vfio-user/pci.c
+++ b/hw/vfio-user/pci.c
@@ -273,7 +273,7 @@ static void vfio_user_pci_realize(PCIDevice *pdev, Error 
**errp)
     memset(&addr, 0, sizeof(addr));
     addr.type = SOCKET_ADDRESS_TYPE_UNIX;
     addr.u.q_unix.path = (char *)sock_name;
-    proxy = vfio_user_connect_dev(&addr, errp);
+    proxy = vfio_user_connect_dev(&addr, OBJECT(pdev), errp);
     if (!proxy) {
         return;
     }
diff --git a/hw/vfio-user/proxy.c b/hw/vfio-user/proxy.c
index 197aee07bf..e48873c0fb 100644
--- a/hw/vfio-user/proxy.c
+++ b/hw/vfio-user/proxy.c
@@ -892,7 +892,8 @@ vfio_user_disable_posted_writes(VFIOUserProxy *proxy)
 static QLIST_HEAD(, VFIOUserProxy) vfio_user_sockets =
     QLIST_HEAD_INITIALIZER(vfio_user_sockets);
 
-VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp)
+VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Object *owner,
+                                   Error **errp)
 {
     VFIOUserProxy *proxy;
     QIOChannelSocket *sioc;
@@ -917,6 +918,13 @@ 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;
+    /* The device may be unparented before disconnect releases the holder. */
+    proxy->qom_path = object_get_canonical_path(owner);
+    assert(proxy->qom_path);
+    const IOThreadHolder io_holder = {
+        .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+        .u.qom_object.qom_path = proxy->qom_path,
+    };
 
     /* init defaults */
     proxy->max_xfer_size = VFIO_USER_DEF_MAX_XFER;
@@ -936,7 +944,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 +976,10 @@ void vfio_user_set_handler(VFIODevice *vbasedev,
 void vfio_user_disconnect(VFIOUserProxy *proxy)
 {
     VFIOUserMsg *r1, *r2;
+    const IOThreadHolder io_holder = {
+        .type = IO_THREAD_HOLDER_KIND_QOM_OBJECT,
+        .u.qom_object.qom_path = proxy->qom_path,
+    };
 
     qemu_mutex_lock(&proxy->lock);
 
@@ -1021,12 +1034,15 @@ void vfio_user_disconnect(VFIOUserProxy *proxy)
     qemu_cond_destroy(&proxy->close_cv);
     qemu_mutex_destroy(&proxy->lock);
 
+    iothread_unref_and_put_aio_context(vfio_user_iothread, &io_holder);
+
     QLIST_REMOVE(proxy, next);
     if (QLIST_EMPTY(&vfio_user_sockets)) {
         iothread_destroy(vfio_user_iothread);
         vfio_user_iothread = NULL;
     }
 
+    g_free(proxy->qom_path);
     g_free(proxy->sockname);
     g_free(proxy);
 }
diff --git a/hw/vfio-user/proxy.h b/hw/vfio-user/proxy.h
index 7b97460cc5..dbdbcfabcb 100644
--- a/hw/vfio-user/proxy.h
+++ b/hw/vfio-user/proxy.h
@@ -70,6 +70,7 @@ typedef struct VFIOUserProxy {
     uint32_t wait_time;
     QemuCond close_cv;
     AioContext *ctx;
+    char *qom_path;
     QEMUBH *req_bh;
     bool async_ops;
 
@@ -102,7 +103,8 @@ typedef struct VFIOUserProxy {
 
 typedef struct VFIODevice VFIODevice;
 
-VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp);
+VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Object *owner,
+                                   Error **errp);
 void vfio_user_disconnect(VFIOUserProxy *proxy);
 void vfio_user_set_handler(VFIODevice *vbasedev,
                            void (*handler)(void *opaque, VFIOUserMsg *msg),
-- 
2.43.0


Reply via email to