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