xref: /qemu/hw/vfio-user/proxy.c (revision 0b3d881a061b284a3db00d7fe9d33581fb424287)
1438d863fSJohn Levon /*
2438d863fSJohn Levon  * vfio protocol over a UNIX socket.
3438d863fSJohn Levon  *
4438d863fSJohn Levon  * Copyright © 2018, 2021 Oracle and/or its affiliates.
5438d863fSJohn Levon  *
6438d863fSJohn Levon  * SPDX-License-Identifier: GPL-2.0-or-later
7438d863fSJohn Levon  */
8438d863fSJohn Levon 
9438d863fSJohn Levon #include "qemu/osdep.h"
10438d863fSJohn Levon #include <sys/ioctl.h>
11438d863fSJohn Levon 
12438d863fSJohn Levon #include "hw/vfio/vfio-device.h"
13438d863fSJohn Levon #include "hw/vfio-user/proxy.h"
14*0b3d881aSJohn Levon #include "hw/vfio-user/trace.h"
15438d863fSJohn Levon #include "qapi/error.h"
16438d863fSJohn Levon #include "qemu/error-report.h"
17438d863fSJohn Levon #include "qemu/lockable.h"
18*0b3d881aSJohn Levon #include "qemu/main-loop.h"
19438d863fSJohn Levon #include "system/iothread.h"
20438d863fSJohn Levon 
21438d863fSJohn Levon static IOThread *vfio_user_iothread;
22438d863fSJohn Levon 
23438d863fSJohn Levon static void vfio_user_shutdown(VFIOUserProxy *proxy);
24*0b3d881aSJohn Levon static VFIOUserMsg *vfio_user_getmsg(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
25*0b3d881aSJohn Levon                                      VFIOUserFDs *fds);
26*0b3d881aSJohn Levon static VFIOUserFDs *vfio_user_getfds(int numfds);
27*0b3d881aSJohn Levon static void vfio_user_recycle(VFIOUserProxy *proxy, VFIOUserMsg *msg);
28438d863fSJohn Levon 
29*0b3d881aSJohn Levon static void vfio_user_recv(void *opaque);
30*0b3d881aSJohn Levon static void vfio_user_cb(void *opaque);
31*0b3d881aSJohn Levon 
32*0b3d881aSJohn Levon static void vfio_user_request(void *opaque);
33*0b3d881aSJohn Levon 
34*0b3d881aSJohn Levon static inline void vfio_user_set_error(VFIOUserHdr *hdr, uint32_t err)
35*0b3d881aSJohn Levon {
36*0b3d881aSJohn Levon     hdr->flags |= VFIO_USER_ERROR;
37*0b3d881aSJohn Levon     hdr->error_reply = err;
38*0b3d881aSJohn Levon }
39438d863fSJohn Levon 
40438d863fSJohn Levon /*
41438d863fSJohn Levon  * Functions called by main, CPU, or iothread threads
42438d863fSJohn Levon  */
43438d863fSJohn Levon 
44438d863fSJohn Levon static void vfio_user_shutdown(VFIOUserProxy *proxy)
45438d863fSJohn Levon {
46438d863fSJohn Levon     qio_channel_shutdown(proxy->ioc, QIO_CHANNEL_SHUTDOWN_READ, NULL);
47438d863fSJohn Levon     qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx, NULL,
48438d863fSJohn Levon                                    proxy->ctx, NULL, NULL);
49438d863fSJohn Levon }
50438d863fSJohn Levon 
51*0b3d881aSJohn Levon static VFIOUserMsg *vfio_user_getmsg(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
52*0b3d881aSJohn Levon                                      VFIOUserFDs *fds)
53*0b3d881aSJohn Levon {
54*0b3d881aSJohn Levon     VFIOUserMsg *msg;
55*0b3d881aSJohn Levon 
56*0b3d881aSJohn Levon     msg = QTAILQ_FIRST(&proxy->free);
57*0b3d881aSJohn Levon     if (msg != NULL) {
58*0b3d881aSJohn Levon         QTAILQ_REMOVE(&proxy->free, msg, next);
59*0b3d881aSJohn Levon     } else {
60*0b3d881aSJohn Levon         msg = g_malloc0(sizeof(*msg));
61*0b3d881aSJohn Levon         qemu_cond_init(&msg->cv);
62*0b3d881aSJohn Levon     }
63*0b3d881aSJohn Levon 
64*0b3d881aSJohn Levon     msg->hdr = hdr;
65*0b3d881aSJohn Levon     msg->fds = fds;
66*0b3d881aSJohn Levon     return msg;
67*0b3d881aSJohn Levon }
68*0b3d881aSJohn Levon 
69*0b3d881aSJohn Levon /*
70*0b3d881aSJohn Levon  * Recycle a message list entry to the free list.
71*0b3d881aSJohn Levon  */
72*0b3d881aSJohn Levon static void vfio_user_recycle(VFIOUserProxy *proxy, VFIOUserMsg *msg)
73*0b3d881aSJohn Levon {
74*0b3d881aSJohn Levon     if (msg->type == VFIO_MSG_NONE) {
75*0b3d881aSJohn Levon         error_printf("vfio_user_recycle - freeing free msg\n");
76*0b3d881aSJohn Levon         return;
77*0b3d881aSJohn Levon     }
78*0b3d881aSJohn Levon 
79*0b3d881aSJohn Levon     /* free msg buffer if no one is waiting to consume the reply */
80*0b3d881aSJohn Levon     if (msg->type == VFIO_MSG_NOWAIT || msg->type == VFIO_MSG_ASYNC) {
81*0b3d881aSJohn Levon         g_free(msg->hdr);
82*0b3d881aSJohn Levon         if (msg->fds != NULL) {
83*0b3d881aSJohn Levon             g_free(msg->fds);
84*0b3d881aSJohn Levon         }
85*0b3d881aSJohn Levon     }
86*0b3d881aSJohn Levon 
87*0b3d881aSJohn Levon     msg->type = VFIO_MSG_NONE;
88*0b3d881aSJohn Levon     msg->hdr = NULL;
89*0b3d881aSJohn Levon     msg->fds = NULL;
90*0b3d881aSJohn Levon     msg->complete = false;
91*0b3d881aSJohn Levon     QTAILQ_INSERT_HEAD(&proxy->free, msg, next);
92*0b3d881aSJohn Levon }
93*0b3d881aSJohn Levon 
94*0b3d881aSJohn Levon static VFIOUserFDs *vfio_user_getfds(int numfds)
95*0b3d881aSJohn Levon {
96*0b3d881aSJohn Levon     VFIOUserFDs *fds = g_malloc0(sizeof(*fds) + (numfds * sizeof(int)));
97*0b3d881aSJohn Levon 
98*0b3d881aSJohn Levon     fds->fds = (int *)((char *)fds + sizeof(*fds));
99*0b3d881aSJohn Levon 
100*0b3d881aSJohn Levon     return fds;
101*0b3d881aSJohn Levon }
102*0b3d881aSJohn Levon 
103438d863fSJohn Levon /*
104438d863fSJohn Levon  * Functions only called by iothread
105438d863fSJohn Levon  */
106438d863fSJohn Levon 
107*0b3d881aSJohn Levon /*
108*0b3d881aSJohn Levon  * Process a received message.
109*0b3d881aSJohn Levon  */
110*0b3d881aSJohn Levon static void vfio_user_process(VFIOUserProxy *proxy, VFIOUserMsg *msg,
111*0b3d881aSJohn Levon                               bool isreply)
112*0b3d881aSJohn Levon {
113*0b3d881aSJohn Levon 
114*0b3d881aSJohn Levon     /*
115*0b3d881aSJohn Levon      * Replies signal a waiter, if none just check for errors
116*0b3d881aSJohn Levon      * and free the message buffer.
117*0b3d881aSJohn Levon      *
118*0b3d881aSJohn Levon      * Requests get queued for the BH.
119*0b3d881aSJohn Levon      */
120*0b3d881aSJohn Levon     if (isreply) {
121*0b3d881aSJohn Levon         msg->complete = true;
122*0b3d881aSJohn Levon         if (msg->type == VFIO_MSG_WAIT) {
123*0b3d881aSJohn Levon             qemu_cond_signal(&msg->cv);
124*0b3d881aSJohn Levon         } else {
125*0b3d881aSJohn Levon             if (msg->hdr->flags & VFIO_USER_ERROR) {
126*0b3d881aSJohn Levon                 error_printf("vfio_user_process: error reply on async ");
127*0b3d881aSJohn Levon                 error_printf("request command %x error %s\n",
128*0b3d881aSJohn Levon                              msg->hdr->command,
129*0b3d881aSJohn Levon                              strerror(msg->hdr->error_reply));
130*0b3d881aSJohn Levon             }
131*0b3d881aSJohn Levon             /* youngest nowait msg has been ack'd */
132*0b3d881aSJohn Levon             if (proxy->last_nowait == msg) {
133*0b3d881aSJohn Levon                 proxy->last_nowait = NULL;
134*0b3d881aSJohn Levon             }
135*0b3d881aSJohn Levon             vfio_user_recycle(proxy, msg);
136*0b3d881aSJohn Levon         }
137*0b3d881aSJohn Levon     } else {
138*0b3d881aSJohn Levon         QTAILQ_INSERT_TAIL(&proxy->incoming, msg, next);
139*0b3d881aSJohn Levon         qemu_bh_schedule(proxy->req_bh);
140*0b3d881aSJohn Levon     }
141*0b3d881aSJohn Levon }
142*0b3d881aSJohn Levon 
143*0b3d881aSJohn Levon /*
144*0b3d881aSJohn Levon  * Complete a partial message read
145*0b3d881aSJohn Levon  */
146*0b3d881aSJohn Levon static int vfio_user_complete(VFIOUserProxy *proxy, Error **errp)
147*0b3d881aSJohn Levon {
148*0b3d881aSJohn Levon     VFIOUserMsg *msg = proxy->part_recv;
149*0b3d881aSJohn Levon     size_t msgleft = proxy->recv_left;
150*0b3d881aSJohn Levon     bool isreply;
151*0b3d881aSJohn Levon     char *data;
152*0b3d881aSJohn Levon     int ret;
153*0b3d881aSJohn Levon 
154*0b3d881aSJohn Levon     data = (char *)msg->hdr + (msg->hdr->size - msgleft);
155*0b3d881aSJohn Levon     while (msgleft > 0) {
156*0b3d881aSJohn Levon         ret = qio_channel_read(proxy->ioc, data, msgleft, errp);
157*0b3d881aSJohn Levon 
158*0b3d881aSJohn Levon         /* error or would block */
159*0b3d881aSJohn Levon         if (ret <= 0) {
160*0b3d881aSJohn Levon             /* try for rest on next iternation */
161*0b3d881aSJohn Levon             if (ret == QIO_CHANNEL_ERR_BLOCK) {
162*0b3d881aSJohn Levon                 proxy->recv_left = msgleft;
163*0b3d881aSJohn Levon             }
164*0b3d881aSJohn Levon             return ret;
165*0b3d881aSJohn Levon         }
166*0b3d881aSJohn Levon         trace_vfio_user_recv_read(msg->hdr->id, ret);
167*0b3d881aSJohn Levon 
168*0b3d881aSJohn Levon         msgleft -= ret;
169*0b3d881aSJohn Levon         data += ret;
170*0b3d881aSJohn Levon     }
171*0b3d881aSJohn Levon 
172*0b3d881aSJohn Levon     /*
173*0b3d881aSJohn Levon      * Read complete message, process it.
174*0b3d881aSJohn Levon      */
175*0b3d881aSJohn Levon     proxy->part_recv = NULL;
176*0b3d881aSJohn Levon     proxy->recv_left = 0;
177*0b3d881aSJohn Levon     isreply = (msg->hdr->flags & VFIO_USER_TYPE) == VFIO_USER_REPLY;
178*0b3d881aSJohn Levon     vfio_user_process(proxy, msg, isreply);
179*0b3d881aSJohn Levon 
180*0b3d881aSJohn Levon     /* return positive value */
181*0b3d881aSJohn Levon     return 1;
182*0b3d881aSJohn Levon }
183*0b3d881aSJohn Levon 
184*0b3d881aSJohn Levon /*
185*0b3d881aSJohn Levon  * Receive and process one incoming message.
186*0b3d881aSJohn Levon  *
187*0b3d881aSJohn Levon  * For replies, find matching outgoing request and wake any waiters.
188*0b3d881aSJohn Levon  * For requests, queue in incoming list and run request BH.
189*0b3d881aSJohn Levon  */
190*0b3d881aSJohn Levon static int vfio_user_recv_one(VFIOUserProxy *proxy, Error **errp)
191*0b3d881aSJohn Levon {
192*0b3d881aSJohn Levon     VFIOUserMsg *msg = NULL;
193*0b3d881aSJohn Levon     g_autofree int *fdp = NULL;
194*0b3d881aSJohn Levon     VFIOUserFDs *reqfds;
195*0b3d881aSJohn Levon     VFIOUserHdr hdr;
196*0b3d881aSJohn Levon     struct iovec iov = {
197*0b3d881aSJohn Levon         .iov_base = &hdr,
198*0b3d881aSJohn Levon         .iov_len = sizeof(hdr),
199*0b3d881aSJohn Levon     };
200*0b3d881aSJohn Levon     bool isreply = false;
201*0b3d881aSJohn Levon     int i, ret;
202*0b3d881aSJohn Levon     size_t msgleft, numfds = 0;
203*0b3d881aSJohn Levon     char *data = NULL;
204*0b3d881aSJohn Levon     char *buf = NULL;
205*0b3d881aSJohn Levon 
206*0b3d881aSJohn Levon     /*
207*0b3d881aSJohn Levon      * Complete any partial reads
208*0b3d881aSJohn Levon      */
209*0b3d881aSJohn Levon     if (proxy->part_recv != NULL) {
210*0b3d881aSJohn Levon         ret = vfio_user_complete(proxy, errp);
211*0b3d881aSJohn Levon 
212*0b3d881aSJohn Levon         /* still not complete, try later */
213*0b3d881aSJohn Levon         if (ret == QIO_CHANNEL_ERR_BLOCK) {
214*0b3d881aSJohn Levon             return ret;
215*0b3d881aSJohn Levon         }
216*0b3d881aSJohn Levon 
217*0b3d881aSJohn Levon         if (ret <= 0) {
218*0b3d881aSJohn Levon             goto fatal;
219*0b3d881aSJohn Levon         }
220*0b3d881aSJohn Levon         /* else fall into reading another msg */
221*0b3d881aSJohn Levon     }
222*0b3d881aSJohn Levon 
223*0b3d881aSJohn Levon     /*
224*0b3d881aSJohn Levon      * Read header
225*0b3d881aSJohn Levon      */
226*0b3d881aSJohn Levon     ret = qio_channel_readv_full(proxy->ioc, &iov, 1, &fdp, &numfds, 0,
227*0b3d881aSJohn Levon                                  errp);
228*0b3d881aSJohn Levon     if (ret == QIO_CHANNEL_ERR_BLOCK) {
229*0b3d881aSJohn Levon         return ret;
230*0b3d881aSJohn Levon     }
231*0b3d881aSJohn Levon 
232*0b3d881aSJohn Levon     /* read error or other side closed connection */
233*0b3d881aSJohn Levon     if (ret <= 0) {
234*0b3d881aSJohn Levon         goto fatal;
235*0b3d881aSJohn Levon     }
236*0b3d881aSJohn Levon 
237*0b3d881aSJohn Levon     if (ret < sizeof(hdr)) {
238*0b3d881aSJohn Levon         error_setg(errp, "short read of header");
239*0b3d881aSJohn Levon         goto fatal;
240*0b3d881aSJohn Levon     }
241*0b3d881aSJohn Levon 
242*0b3d881aSJohn Levon     /*
243*0b3d881aSJohn Levon      * Validate header
244*0b3d881aSJohn Levon      */
245*0b3d881aSJohn Levon     if (hdr.size < sizeof(VFIOUserHdr)) {
246*0b3d881aSJohn Levon         error_setg(errp, "bad header size");
247*0b3d881aSJohn Levon         goto fatal;
248*0b3d881aSJohn Levon     }
249*0b3d881aSJohn Levon     switch (hdr.flags & VFIO_USER_TYPE) {
250*0b3d881aSJohn Levon     case VFIO_USER_REQUEST:
251*0b3d881aSJohn Levon         isreply = false;
252*0b3d881aSJohn Levon         break;
253*0b3d881aSJohn Levon     case VFIO_USER_REPLY:
254*0b3d881aSJohn Levon         isreply = true;
255*0b3d881aSJohn Levon         break;
256*0b3d881aSJohn Levon     default:
257*0b3d881aSJohn Levon         error_setg(errp, "unknown message type");
258*0b3d881aSJohn Levon         goto fatal;
259*0b3d881aSJohn Levon     }
260*0b3d881aSJohn Levon     trace_vfio_user_recv_hdr(proxy->sockname, hdr.id, hdr.command, hdr.size,
261*0b3d881aSJohn Levon                              hdr.flags);
262*0b3d881aSJohn Levon 
263*0b3d881aSJohn Levon     /*
264*0b3d881aSJohn Levon      * For replies, find the matching pending request.
265*0b3d881aSJohn Levon      * For requests, reap incoming FDs.
266*0b3d881aSJohn Levon      */
267*0b3d881aSJohn Levon     if (isreply) {
268*0b3d881aSJohn Levon         QTAILQ_FOREACH(msg, &proxy->pending, next) {
269*0b3d881aSJohn Levon             if (hdr.id == msg->id) {
270*0b3d881aSJohn Levon                 break;
271*0b3d881aSJohn Levon             }
272*0b3d881aSJohn Levon         }
273*0b3d881aSJohn Levon         if (msg == NULL) {
274*0b3d881aSJohn Levon             error_setg(errp, "unexpected reply");
275*0b3d881aSJohn Levon             goto err;
276*0b3d881aSJohn Levon         }
277*0b3d881aSJohn Levon         QTAILQ_REMOVE(&proxy->pending, msg, next);
278*0b3d881aSJohn Levon 
279*0b3d881aSJohn Levon         /*
280*0b3d881aSJohn Levon          * Process any received FDs
281*0b3d881aSJohn Levon          */
282*0b3d881aSJohn Levon         if (numfds != 0) {
283*0b3d881aSJohn Levon             if (msg->fds == NULL || msg->fds->recv_fds < numfds) {
284*0b3d881aSJohn Levon                 error_setg(errp, "unexpected FDs");
285*0b3d881aSJohn Levon                 goto err;
286*0b3d881aSJohn Levon             }
287*0b3d881aSJohn Levon             msg->fds->recv_fds = numfds;
288*0b3d881aSJohn Levon             memcpy(msg->fds->fds, fdp, numfds * sizeof(int));
289*0b3d881aSJohn Levon         }
290*0b3d881aSJohn Levon     } else {
291*0b3d881aSJohn Levon         if (numfds != 0) {
292*0b3d881aSJohn Levon             reqfds = vfio_user_getfds(numfds);
293*0b3d881aSJohn Levon             memcpy(reqfds->fds, fdp, numfds * sizeof(int));
294*0b3d881aSJohn Levon         } else {
295*0b3d881aSJohn Levon             reqfds = NULL;
296*0b3d881aSJohn Levon         }
297*0b3d881aSJohn Levon     }
298*0b3d881aSJohn Levon 
299*0b3d881aSJohn Levon     /*
300*0b3d881aSJohn Levon      * Put the whole message into a single buffer.
301*0b3d881aSJohn Levon      */
302*0b3d881aSJohn Levon     if (isreply) {
303*0b3d881aSJohn Levon         if (hdr.size > msg->rsize) {
304*0b3d881aSJohn Levon             error_setg(errp, "reply larger than recv buffer");
305*0b3d881aSJohn Levon             goto err;
306*0b3d881aSJohn Levon         }
307*0b3d881aSJohn Levon         *msg->hdr = hdr;
308*0b3d881aSJohn Levon         data = (char *)msg->hdr + sizeof(hdr);
309*0b3d881aSJohn Levon     } else {
310*0b3d881aSJohn Levon         buf = g_malloc0(hdr.size);
311*0b3d881aSJohn Levon         memcpy(buf, &hdr, sizeof(hdr));
312*0b3d881aSJohn Levon         data = buf + sizeof(hdr);
313*0b3d881aSJohn Levon         msg = vfio_user_getmsg(proxy, (VFIOUserHdr *)buf, reqfds);
314*0b3d881aSJohn Levon         msg->type = VFIO_MSG_REQ;
315*0b3d881aSJohn Levon     }
316*0b3d881aSJohn Levon 
317*0b3d881aSJohn Levon     /*
318*0b3d881aSJohn Levon      * Read rest of message.
319*0b3d881aSJohn Levon      */
320*0b3d881aSJohn Levon     msgleft = hdr.size - sizeof(hdr);
321*0b3d881aSJohn Levon     while (msgleft > 0) {
322*0b3d881aSJohn Levon         ret = qio_channel_read(proxy->ioc, data, msgleft, errp);
323*0b3d881aSJohn Levon 
324*0b3d881aSJohn Levon         /* prepare to complete read on next iternation */
325*0b3d881aSJohn Levon         if (ret == QIO_CHANNEL_ERR_BLOCK) {
326*0b3d881aSJohn Levon             proxy->part_recv = msg;
327*0b3d881aSJohn Levon             proxy->recv_left = msgleft;
328*0b3d881aSJohn Levon             return ret;
329*0b3d881aSJohn Levon         }
330*0b3d881aSJohn Levon 
331*0b3d881aSJohn Levon         if (ret <= 0) {
332*0b3d881aSJohn Levon             goto fatal;
333*0b3d881aSJohn Levon         }
334*0b3d881aSJohn Levon         trace_vfio_user_recv_read(hdr.id, ret);
335*0b3d881aSJohn Levon 
336*0b3d881aSJohn Levon         msgleft -= ret;
337*0b3d881aSJohn Levon         data += ret;
338*0b3d881aSJohn Levon     }
339*0b3d881aSJohn Levon 
340*0b3d881aSJohn Levon     vfio_user_process(proxy, msg, isreply);
341*0b3d881aSJohn Levon     return 0;
342*0b3d881aSJohn Levon 
343*0b3d881aSJohn Levon     /*
344*0b3d881aSJohn Levon      * fatal means the other side closed or we don't trust the stream
345*0b3d881aSJohn Levon      * err means this message is corrupt
346*0b3d881aSJohn Levon      */
347*0b3d881aSJohn Levon fatal:
348*0b3d881aSJohn Levon     vfio_user_shutdown(proxy);
349*0b3d881aSJohn Levon     proxy->state = VFIO_PROXY_ERROR;
350*0b3d881aSJohn Levon 
351*0b3d881aSJohn Levon     /* set error if server side closed */
352*0b3d881aSJohn Levon     if (ret == 0) {
353*0b3d881aSJohn Levon         error_setg(errp, "server closed socket");
354*0b3d881aSJohn Levon     }
355*0b3d881aSJohn Levon 
356*0b3d881aSJohn Levon err:
357*0b3d881aSJohn Levon     for (i = 0; i < numfds; i++) {
358*0b3d881aSJohn Levon         close(fdp[i]);
359*0b3d881aSJohn Levon     }
360*0b3d881aSJohn Levon     if (isreply && msg != NULL) {
361*0b3d881aSJohn Levon         /* force an error to keep sending thread from hanging */
362*0b3d881aSJohn Levon         vfio_user_set_error(msg->hdr, EINVAL);
363*0b3d881aSJohn Levon         msg->complete = true;
364*0b3d881aSJohn Levon         qemu_cond_signal(&msg->cv);
365*0b3d881aSJohn Levon     }
366*0b3d881aSJohn Levon     return -1;
367*0b3d881aSJohn Levon }
368*0b3d881aSJohn Levon 
369*0b3d881aSJohn Levon static void vfio_user_recv(void *opaque)
370*0b3d881aSJohn Levon {
371*0b3d881aSJohn Levon     VFIOUserProxy *proxy = opaque;
372*0b3d881aSJohn Levon 
373*0b3d881aSJohn Levon     QEMU_LOCK_GUARD(&proxy->lock);
374*0b3d881aSJohn Levon 
375*0b3d881aSJohn Levon     if (proxy->state == VFIO_PROXY_CONNECTED) {
376*0b3d881aSJohn Levon         Error *local_err = NULL;
377*0b3d881aSJohn Levon 
378*0b3d881aSJohn Levon         while (vfio_user_recv_one(proxy, &local_err) == 0) {
379*0b3d881aSJohn Levon             ;
380*0b3d881aSJohn Levon         }
381*0b3d881aSJohn Levon 
382*0b3d881aSJohn Levon         if (local_err != NULL) {
383*0b3d881aSJohn Levon             error_report_err(local_err);
384*0b3d881aSJohn Levon         }
385*0b3d881aSJohn Levon     }
386*0b3d881aSJohn Levon }
387*0b3d881aSJohn Levon 
388438d863fSJohn Levon static void vfio_user_cb(void *opaque)
389438d863fSJohn Levon {
390438d863fSJohn Levon     VFIOUserProxy *proxy = opaque;
391438d863fSJohn Levon 
392438d863fSJohn Levon     QEMU_LOCK_GUARD(&proxy->lock);
393438d863fSJohn Levon 
394438d863fSJohn Levon     proxy->state = VFIO_PROXY_CLOSED;
395438d863fSJohn Levon     qemu_cond_signal(&proxy->close_cv);
396438d863fSJohn Levon }
397438d863fSJohn Levon 
398438d863fSJohn Levon 
399438d863fSJohn Levon /*
400438d863fSJohn Levon  * Functions called by main or CPU threads
401438d863fSJohn Levon  */
402438d863fSJohn Levon 
403*0b3d881aSJohn Levon /*
404*0b3d881aSJohn Levon  * Process incoming requests.
405*0b3d881aSJohn Levon  *
406*0b3d881aSJohn Levon  * The bus-specific callback has the form:
407*0b3d881aSJohn Levon  *    request(opaque, msg)
408*0b3d881aSJohn Levon  * where 'opaque' was specified in vfio_user_set_handler
409*0b3d881aSJohn Levon  * and 'msg' is the inbound message.
410*0b3d881aSJohn Levon  *
411*0b3d881aSJohn Levon  * The callback is responsible for disposing of the message buffer,
412*0b3d881aSJohn Levon  * usually by re-using it when calling vfio_send_reply or vfio_send_error,
413*0b3d881aSJohn Levon  * both of which free their message buffer when the reply is sent.
414*0b3d881aSJohn Levon  *
415*0b3d881aSJohn Levon  * If the callback uses a new buffer, it needs to free the old one.
416*0b3d881aSJohn Levon  */
417*0b3d881aSJohn Levon static void vfio_user_request(void *opaque)
418*0b3d881aSJohn Levon {
419*0b3d881aSJohn Levon     VFIOUserProxy *proxy = opaque;
420*0b3d881aSJohn Levon     VFIOUserMsgQ new, free;
421*0b3d881aSJohn Levon     VFIOUserMsg *msg, *m1;
422*0b3d881aSJohn Levon 
423*0b3d881aSJohn Levon     /* reap all incoming */
424*0b3d881aSJohn Levon     QTAILQ_INIT(&new);
425*0b3d881aSJohn Levon     WITH_QEMU_LOCK_GUARD(&proxy->lock) {
426*0b3d881aSJohn Levon         QTAILQ_FOREACH_SAFE(msg, &proxy->incoming, next, m1) {
427*0b3d881aSJohn Levon             QTAILQ_REMOVE(&proxy->incoming, msg, next);
428*0b3d881aSJohn Levon             QTAILQ_INSERT_TAIL(&new, msg, next);
429*0b3d881aSJohn Levon         }
430*0b3d881aSJohn Levon     }
431*0b3d881aSJohn Levon 
432*0b3d881aSJohn Levon     /* process list */
433*0b3d881aSJohn Levon     QTAILQ_INIT(&free);
434*0b3d881aSJohn Levon     QTAILQ_FOREACH_SAFE(msg, &new, next, m1) {
435*0b3d881aSJohn Levon         QTAILQ_REMOVE(&new, msg, next);
436*0b3d881aSJohn Levon         trace_vfio_user_recv_request(msg->hdr->command);
437*0b3d881aSJohn Levon         proxy->request(proxy->req_arg, msg);
438*0b3d881aSJohn Levon         QTAILQ_INSERT_HEAD(&free, msg, next);
439*0b3d881aSJohn Levon     }
440*0b3d881aSJohn Levon 
441*0b3d881aSJohn Levon     /* free list */
442*0b3d881aSJohn Levon     WITH_QEMU_LOCK_GUARD(&proxy->lock) {
443*0b3d881aSJohn Levon         QTAILQ_FOREACH_SAFE(msg, &free, next, m1) {
444*0b3d881aSJohn Levon             vfio_user_recycle(proxy, msg);
445*0b3d881aSJohn Levon         }
446*0b3d881aSJohn Levon     }
447*0b3d881aSJohn Levon }
448*0b3d881aSJohn Levon 
449*0b3d881aSJohn Levon 
450438d863fSJohn Levon static QLIST_HEAD(, VFIOUserProxy) vfio_user_sockets =
451438d863fSJohn Levon     QLIST_HEAD_INITIALIZER(vfio_user_sockets);
452438d863fSJohn Levon 
453438d863fSJohn Levon VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp)
454438d863fSJohn Levon {
455438d863fSJohn Levon     VFIOUserProxy *proxy;
456438d863fSJohn Levon     QIOChannelSocket *sioc;
457438d863fSJohn Levon     QIOChannel *ioc;
458438d863fSJohn Levon     char *sockname;
459438d863fSJohn Levon 
460438d863fSJohn Levon     if (addr->type != SOCKET_ADDRESS_TYPE_UNIX) {
461438d863fSJohn Levon         error_setg(errp, "vfio_user_connect - bad address family");
462438d863fSJohn Levon         return NULL;
463438d863fSJohn Levon     }
464438d863fSJohn Levon     sockname = addr->u.q_unix.path;
465438d863fSJohn Levon 
466438d863fSJohn Levon     sioc = qio_channel_socket_new();
467438d863fSJohn Levon     ioc = QIO_CHANNEL(sioc);
468438d863fSJohn Levon     if (qio_channel_socket_connect_sync(sioc, addr, errp)) {
469438d863fSJohn Levon         object_unref(OBJECT(ioc));
470438d863fSJohn Levon         return NULL;
471438d863fSJohn Levon     }
472438d863fSJohn Levon     qio_channel_set_blocking(ioc, false, NULL);
473438d863fSJohn Levon 
474438d863fSJohn Levon     proxy = g_malloc0(sizeof(VFIOUserProxy));
475438d863fSJohn Levon     proxy->sockname = g_strdup_printf("unix:%s", sockname);
476438d863fSJohn Levon     proxy->ioc = ioc;
477438d863fSJohn Levon     proxy->flags = VFIO_PROXY_CLIENT;
478438d863fSJohn Levon     proxy->state = VFIO_PROXY_CONNECTED;
479438d863fSJohn Levon 
480438d863fSJohn Levon     qemu_mutex_init(&proxy->lock);
481438d863fSJohn Levon     qemu_cond_init(&proxy->close_cv);
482438d863fSJohn Levon 
483438d863fSJohn Levon     if (vfio_user_iothread == NULL) {
484438d863fSJohn Levon         vfio_user_iothread = iothread_create("VFIO user", errp);
485438d863fSJohn Levon     }
486438d863fSJohn Levon 
487438d863fSJohn Levon     proxy->ctx = iothread_get_aio_context(vfio_user_iothread);
488*0b3d881aSJohn Levon     proxy->req_bh = qemu_bh_new(vfio_user_request, proxy);
489438d863fSJohn Levon 
490438d863fSJohn Levon     QTAILQ_INIT(&proxy->outgoing);
491438d863fSJohn Levon     QTAILQ_INIT(&proxy->incoming);
492438d863fSJohn Levon     QTAILQ_INIT(&proxy->free);
493438d863fSJohn Levon     QTAILQ_INIT(&proxy->pending);
494438d863fSJohn Levon     QLIST_INSERT_HEAD(&vfio_user_sockets, proxy, next);
495438d863fSJohn Levon 
496438d863fSJohn Levon     return proxy;
497438d863fSJohn Levon }
498438d863fSJohn Levon 
499*0b3d881aSJohn Levon void vfio_user_set_handler(VFIODevice *vbasedev,
500*0b3d881aSJohn Levon                            void (*handler)(void *opaque, VFIOUserMsg *msg),
501*0b3d881aSJohn Levon                            void *req_arg)
502*0b3d881aSJohn Levon {
503*0b3d881aSJohn Levon     VFIOUserProxy *proxy = vbasedev->proxy;
504*0b3d881aSJohn Levon 
505*0b3d881aSJohn Levon     proxy->request = handler;
506*0b3d881aSJohn Levon     proxy->req_arg = req_arg;
507*0b3d881aSJohn Levon     qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx,
508*0b3d881aSJohn Levon                                    vfio_user_recv, NULL, NULL, proxy);
509*0b3d881aSJohn Levon }
510*0b3d881aSJohn Levon 
511438d863fSJohn Levon void vfio_user_disconnect(VFIOUserProxy *proxy)
512438d863fSJohn Levon {
513438d863fSJohn Levon     VFIOUserMsg *r1, *r2;
514438d863fSJohn Levon 
515438d863fSJohn Levon     qemu_mutex_lock(&proxy->lock);
516438d863fSJohn Levon 
517438d863fSJohn Levon     /* our side is quitting */
518438d863fSJohn Levon     if (proxy->state == VFIO_PROXY_CONNECTED) {
519438d863fSJohn Levon         vfio_user_shutdown(proxy);
520438d863fSJohn Levon         if (!QTAILQ_EMPTY(&proxy->pending)) {
521438d863fSJohn Levon             error_printf("vfio_user_disconnect: outstanding requests\n");
522438d863fSJohn Levon         }
523438d863fSJohn Levon     }
524438d863fSJohn Levon     object_unref(OBJECT(proxy->ioc));
525438d863fSJohn Levon     proxy->ioc = NULL;
526*0b3d881aSJohn Levon     qemu_bh_delete(proxy->req_bh);
527*0b3d881aSJohn Levon     proxy->req_bh = NULL;
528438d863fSJohn Levon 
529438d863fSJohn Levon     proxy->state = VFIO_PROXY_CLOSING;
530438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->outgoing, next, r2) {
531438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
532438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->outgoing, r1, next);
533438d863fSJohn Levon         g_free(r1);
534438d863fSJohn Levon     }
535438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->incoming, next, r2) {
536438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
537438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->incoming, r1, next);
538438d863fSJohn Levon         g_free(r1);
539438d863fSJohn Levon     }
540438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->pending, next, r2) {
541438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
542438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->pending, r1, next);
543438d863fSJohn Levon         g_free(r1);
544438d863fSJohn Levon     }
545438d863fSJohn Levon     QTAILQ_FOREACH_SAFE(r1, &proxy->free, next, r2) {
546438d863fSJohn Levon         qemu_cond_destroy(&r1->cv);
547438d863fSJohn Levon         QTAILQ_REMOVE(&proxy->free, r1, next);
548438d863fSJohn Levon         g_free(r1);
549438d863fSJohn Levon     }
550438d863fSJohn Levon 
551438d863fSJohn Levon     /*
552438d863fSJohn Levon      * Make sure the iothread isn't blocking anywhere
553438d863fSJohn Levon      * with a ref to this proxy by waiting for a BH
554438d863fSJohn Levon      * handler to run after the proxy fd handlers were
555438d863fSJohn Levon      * deleted above.
556438d863fSJohn Levon      */
557438d863fSJohn Levon     aio_bh_schedule_oneshot(proxy->ctx, vfio_user_cb, proxy);
558438d863fSJohn Levon     qemu_cond_wait(&proxy->close_cv, &proxy->lock);
559438d863fSJohn Levon 
560438d863fSJohn Levon     /* we now hold the only ref to proxy */
561438d863fSJohn Levon     qemu_mutex_unlock(&proxy->lock);
562438d863fSJohn Levon     qemu_cond_destroy(&proxy->close_cv);
563438d863fSJohn Levon     qemu_mutex_destroy(&proxy->lock);
564438d863fSJohn Levon 
565438d863fSJohn Levon     QLIST_REMOVE(proxy, next);
566438d863fSJohn Levon     if (QLIST_EMPTY(&vfio_user_sockets)) {
567438d863fSJohn Levon         iothread_destroy(vfio_user_iothread);
568438d863fSJohn Levon         vfio_user_iothread = NULL;
569438d863fSJohn Levon     }
570438d863fSJohn Levon 
571438d863fSJohn Levon     g_free(proxy->sockname);
572438d863fSJohn Levon     g_free(proxy);
573438d863fSJohn Levon }
574