xref: /qemu/hw/vfio-user/proxy.c (revision 438d863f1f40fbc2b57bf94cc6c998a6445c0932)
1*438d863fSJohn Levon /*
2*438d863fSJohn Levon  * vfio protocol over a UNIX socket.
3*438d863fSJohn Levon  *
4*438d863fSJohn Levon  * Copyright © 2018, 2021 Oracle and/or its affiliates.
5*438d863fSJohn Levon  *
6*438d863fSJohn Levon  * SPDX-License-Identifier: GPL-2.0-or-later
7*438d863fSJohn Levon  */
8*438d863fSJohn Levon 
9*438d863fSJohn Levon #include "qemu/osdep.h"
10*438d863fSJohn Levon #include <sys/ioctl.h>
11*438d863fSJohn Levon 
12*438d863fSJohn Levon #include "hw/vfio/vfio-device.h"
13*438d863fSJohn Levon #include "hw/vfio-user/proxy.h"
14*438d863fSJohn Levon #include "qapi/error.h"
15*438d863fSJohn Levon #include "qemu/error-report.h"
16*438d863fSJohn Levon #include "qemu/lockable.h"
17*438d863fSJohn Levon #include "system/iothread.h"
18*438d863fSJohn Levon 
19*438d863fSJohn Levon static IOThread *vfio_user_iothread;
20*438d863fSJohn Levon 
21*438d863fSJohn Levon static void vfio_user_shutdown(VFIOUserProxy *proxy);
22*438d863fSJohn Levon 
23*438d863fSJohn Levon 
24*438d863fSJohn Levon /*
25*438d863fSJohn Levon  * Functions called by main, CPU, or iothread threads
26*438d863fSJohn Levon  */
27*438d863fSJohn Levon 
28*438d863fSJohn Levon static void vfio_user_shutdown(VFIOUserProxy *proxy)
29*438d863fSJohn Levon {
30*438d863fSJohn Levon     qio_channel_shutdown(proxy->ioc, QIO_CHANNEL_SHUTDOWN_READ, NULL);
31*438d863fSJohn Levon     qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx, NULL,
32*438d863fSJohn Levon                                    proxy->ctx, NULL, NULL);
33*438d863fSJohn Levon }
34*438d863fSJohn Levon 
35*438d863fSJohn Levon /*
36*438d863fSJohn Levon  * Functions only called by iothread
37*438d863fSJohn Levon  */
38*438d863fSJohn Levon 
39*438d863fSJohn Levon static void vfio_user_cb(void *opaque)
40*438d863fSJohn Levon {
41*438d863fSJohn Levon     VFIOUserProxy *proxy = opaque;
42*438d863fSJohn Levon 
43*438d863fSJohn Levon     QEMU_LOCK_GUARD(&proxy->lock);
44*438d863fSJohn Levon 
45*438d863fSJohn Levon     proxy->state = VFIO_PROXY_CLOSED;
46*438d863fSJohn Levon     qemu_cond_signal(&proxy->close_cv);
47*438d863fSJohn Levon }
48*438d863fSJohn Levon 
49*438d863fSJohn Levon 
50*438d863fSJohn Levon /*
51*438d863fSJohn Levon  * Functions called by main or CPU threads
52*438d863fSJohn Levon  */
53*438d863fSJohn Levon 
54*438d863fSJohn Levon static QLIST_HEAD(, VFIOUserProxy) vfio_user_sockets =
55*438d863fSJohn Levon     QLIST_HEAD_INITIALIZER(vfio_user_sockets);
56*438d863fSJohn Levon 
57*438d863fSJohn Levon VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp)
58*438d863fSJohn Levon {
59*438d863fSJohn Levon     VFIOUserProxy *proxy;
60*438d863fSJohn Levon     QIOChannelSocket *sioc;
61*438d863fSJohn Levon     QIOChannel *ioc;
62*438d863fSJohn Levon     char *sockname;
63*438d863fSJohn Levon 
64*438d863fSJohn Levon     if (addr->type != SOCKET_ADDRESS_TYPE_UNIX) {
65*438d863fSJohn Levon         error_setg(errp, "vfio_user_connect - bad address family");
66*438d863fSJohn Levon         return NULL;
67*438d863fSJohn Levon     }
68*438d863fSJohn Levon     sockname = addr->u.q_unix.path;
69*438d863fSJohn Levon 
70*438d863fSJohn Levon     sioc = qio_channel_socket_new();
71*438d863fSJohn Levon     ioc = QIO_CHANNEL(sioc);
72*438d863fSJohn Levon     if (qio_channel_socket_connect_sync(sioc, addr, errp)) {
73*438d863fSJohn Levon         object_unref(OBJECT(ioc));
74*438d863fSJohn Levon         return NULL;
75*438d863fSJohn Levon     }
76*438d863fSJohn Levon     qio_channel_set_blocking(ioc, false, NULL);
77*438d863fSJohn Levon 
78*438d863fSJohn Levon     proxy = g_malloc0(sizeof(VFIOUserProxy));
79*438d863fSJohn Levon     proxy->sockname = g_strdup_printf("unix:%s", sockname);
80*438d863fSJohn Levon     proxy->ioc = ioc;
81*438d863fSJohn Levon     proxy->flags = VFIO_PROXY_CLIENT;
82*438d863fSJohn Levon     proxy->state = VFIO_PROXY_CONNECTED;
83*438d863fSJohn Levon 
84*438d863fSJohn Levon     qemu_mutex_init(&proxy->lock);
85*438d863fSJohn Levon     qemu_cond_init(&proxy->close_cv);
86*438d863fSJohn Levon 
87*438d863fSJohn Levon     if (vfio_user_iothread == NULL) {
88*438d863fSJohn Levon         vfio_user_iothread = iothread_create("VFIO user", errp);
89*438d863fSJohn Levon     }
90*438d863fSJohn Levon 
91*438d863fSJohn Levon     proxy->ctx = iothread_get_aio_context(vfio_user_iothread);
92*438d863fSJohn Levon 
93*438d863fSJohn Levon     QTAILQ_INIT(&proxy->outgoing);
94*438d863fSJohn Levon     QTAILQ_INIT(&proxy->incoming);
95*438d863fSJohn Levon     QTAILQ_INIT(&proxy->free);
96*438d863fSJohn Levon     QTAILQ_INIT(&proxy->pending);
97*438d863fSJohn Levon     QLIST_INSERT_HEAD(&vfio_user_sockets, proxy, next);
98*438d863fSJohn Levon 
99*438d863fSJohn Levon     return proxy;
100*438d863fSJohn Levon }
101*438d863fSJohn Levon 
102*438d863fSJohn Levon void vfio_user_disconnect(VFIOUserProxy *proxy)
103*438d863fSJohn Levon {
104*438d863fSJohn Levon     VFIOUserMsg *r1, *r2;
105*438d863fSJohn Levon 
106*438d863fSJohn Levon     qemu_mutex_lock(&proxy->lock);
107*438d863fSJohn Levon 
108*438d863fSJohn Levon     /* our side is quitting */
109*438d863fSJohn Levon     if (proxy->state == VFIO_PROXY_CONNECTED) {
110*438d863fSJohn Levon         vfio_user_shutdown(proxy);
111*438d863fSJohn Levon         if (!QTAILQ_EMPTY(&proxy->pending)) {
112*438d863fSJohn Levon             error_printf("vfio_user_disconnect: outstanding requests\n");
113*438d863fSJohn Levon         }
114*438d863fSJohn Levon     }
115*438d863fSJohn Levon     object_unref(OBJECT(proxy->ioc));
116*438d863fSJohn Levon     proxy->ioc = NULL;
117*438d863fSJohn Levon 
118*438d863fSJohn Levon     proxy->state = VFIO_PROXY_CLOSING;
119*438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->outgoing, next, r2) {
120*438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
121*438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->outgoing, r1, next);
122*438d863fSJohn Levon         g_free(r1);
123*438d863fSJohn Levon     }
124*438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->incoming, next, r2) {
125*438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
126*438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->incoming, r1, next);
127*438d863fSJohn Levon         g_free(r1);
128*438d863fSJohn Levon     }
129*438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->pending, next, r2) {
130*438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
131*438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->pending, r1, next);
132*438d863fSJohn Levon         g_free(r1);
133*438d863fSJohn Levon     }
134*438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->free, next, r2) {
135*438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
136*438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->free, r1, next);
137*438d863fSJohn Levon         g_free(r1);
138*438d863fSJohn Levon     }
139*438d863fSJohn Levon 
140*438d863fSJohn Levon     /*
141*438d863fSJohn Levon      * Make sure the iothread isn't blocking anywhere
142*438d863fSJohn Levon      * with a ref to this proxy by waiting for a BH
143*438d863fSJohn Levon      * handler to run after the proxy fd handlers were
144*438d863fSJohn Levon      * deleted above.
145*438d863fSJohn Levon      */
146*438d863fSJohn Levon     aio_bh_schedule_oneshot(proxy->ctx, vfio_user_cb, proxy);
147*438d863fSJohn Levon     qemu_cond_wait(&proxy->close_cv, &proxy->lock);
148*438d863fSJohn Levon 
149*438d863fSJohn Levon     /* we now hold the only ref to proxy */
150*438d863fSJohn Levon     qemu_mutex_unlock(&proxy->lock);
151*438d863fSJohn Levon     qemu_cond_destroy(&proxy->close_cv);
152*438d863fSJohn Levon     qemu_mutex_destroy(&proxy->lock);
153*438d863fSJohn Levon 
154*438d863fSJohn Levon     QLIST_REMOVE(proxy, next);
155*438d863fSJohn Levon     if (QLIST_EMPTY(&vfio_user_sockets)) {
156*438d863fSJohn Levon         iothread_destroy(vfio_user_iothread);
157*438d863fSJohn Levon         vfio_user_iothread = NULL;
158*438d863fSJohn Levon     }
159*438d863fSJohn Levon 
160*438d863fSJohn Levon     g_free(proxy->sockname);
161*438d863fSJohn Levon     g_free(proxy);
162*438d863fSJohn Levon }
163