mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'pull-vfio-20251203' of https://github.com/legoater/qemu into staging
vfio queue: * Fix vfio-user issues reported by Coverity * Update vfio-user documentation # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmkwTlYACgkQUaNDx8/7 # 7KH1zQ/9F0aJd70NcJnJ/RDzFf1bKPxzZ+EzIhlU2nhXPL9T5ewaYqf03+Rbir4J # 0xckidngEmRqcH/L/A5tD1hxuu14i5yOHmuAO3RC7K1pC/lWT4ifqMDihFByRuNb # 4LsQn4qEaZ8FGFQ8GszyjW4Dgeee3Xf+glt8BlP08ZFdJM7SHHFFGt75jWBMV2If # gqYcDe/0iGKTI86If8UGfWLzqiW5LlEpsK/3NVHhDXgLEFxdF4km+XVyZoc0nzwt # 3ezuKBUTtt1MAtgqTbL7HRlwOK4ui0SN+s6dDAc15HcS9VczFprVYfxeR1k172oJ # 0ofSgjFjDQTGPZYSk1V2LZ+0uYsU8dn8MI3rlmBG44ABqNzQA7Tj+QCkAuaPbYA6 # iyTqQa2gui8pH7X7dj0MUXn8URBRHKYY/WuajTpvSsFsIRbXi13CXYhyYvR9+yoB # PvTBjIsmVxFXdDg0yxZbhhRwHvRmlpgR78Aif5Jps7c6mppSL8i4e2PPmchVzTj2 # e/W8ASkvyDyeiBG5qhdsv2bagZGKEBab3PSmmIyq3sJ0OmtOj9L3mdZ5r66c+SiA # QmtA5BIoj5K9LwOxTgEfBAzIQ8lMpMaBjS5jZbSGKklH343kDtSg8d3PGCym5SrN # 3cUkU/PzhZX0YA6ywloodsQKgCwE6xbOK3LAbHwv8wcKQyHLkf4= # =9ERW # -----END PGP SIGNATURE----- # gpg: Signature made Wed 03 Dec 2025 08:51:02 AM CST # gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1 # gpg: Good signature from "Cédric Le Goater <clg@redhat.com>" [full] # gpg: aka "Cédric Le Goater <clg@kaod.org>" [full] * tag 'pull-vfio-20251203' of https://github.com/legoater/qemu: vfio-user: recycle msg on failure vfio-user: simplify vfio_user_recv_one() vfio-user: refactor out header handling vfio-user: clarify partial message handling vfio-user: simplify vfio_user_process() docs/interop/vfio-user: update protocol specification Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
+504
-46
File diff suppressed because it is too large
Load Diff
+114
-92
@@ -147,8 +147,7 @@ VFIOUserFDs *vfio_user_getfds(int numfds)
|
||||
/*
|
||||
* Process a received message.
|
||||
*/
|
||||
static void vfio_user_process(VFIOUserProxy *proxy, VFIOUserMsg *msg,
|
||||
bool isreply)
|
||||
static void vfio_user_process(VFIOUserProxy *proxy, VFIOUserMsg *msg)
|
||||
{
|
||||
|
||||
/*
|
||||
@@ -157,7 +156,7 @@ static void vfio_user_process(VFIOUserProxy *proxy, VFIOUserMsg *msg,
|
||||
*
|
||||
* Requests get queued for the BH.
|
||||
*/
|
||||
if (isreply) {
|
||||
if ((msg->hdr->flags & VFIO_USER_TYPE) == VFIO_USER_REPLY) {
|
||||
msg->complete = true;
|
||||
if (msg->type == VFIO_MSG_WAIT) {
|
||||
qemu_cond_signal(&msg->cv);
|
||||
@@ -187,7 +186,6 @@ static int vfio_user_complete(VFIOUserProxy *proxy, Error **errp)
|
||||
{
|
||||
VFIOUserMsg *msg = proxy->part_recv;
|
||||
size_t msgleft = proxy->recv_left;
|
||||
bool isreply;
|
||||
char *data;
|
||||
int ret;
|
||||
|
||||
@@ -214,13 +212,67 @@ static int vfio_user_complete(VFIOUserProxy *proxy, Error **errp)
|
||||
*/
|
||||
proxy->part_recv = NULL;
|
||||
proxy->recv_left = 0;
|
||||
isreply = (msg->hdr->flags & VFIO_USER_TYPE) == VFIO_USER_REPLY;
|
||||
vfio_user_process(proxy, msg, isreply);
|
||||
vfio_user_process(proxy, msg);
|
||||
|
||||
/* return positive value */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vfio_user_recv_hdr(VFIOUserProxy *proxy, Error **errp,
|
||||
VFIOUserHdr *hdr, int **fdp, size_t *numfdp,
|
||||
bool *isreply)
|
||||
{
|
||||
struct iovec iov = {
|
||||
.iov_base = hdr,
|
||||
.iov_len = sizeof(*hdr),
|
||||
};
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Read header
|
||||
*/
|
||||
ret = qio_channel_readv_full(proxy->ioc, &iov, 1, fdp, numfdp, 0,
|
||||
errp);
|
||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, errno, "failed to read header");
|
||||
return -1;
|
||||
} else if (ret == 0) {
|
||||
error_setg(errp, "failed to read header: EOF");
|
||||
return -1;
|
||||
} else if (ret < sizeof(*hdr)) {
|
||||
error_setg(errp, "short read of header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate header
|
||||
*/
|
||||
if (hdr->size < sizeof(*hdr)) {
|
||||
error_setg(errp, "bad header size");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (hdr->flags & VFIO_USER_TYPE) {
|
||||
case VFIO_USER_REQUEST:
|
||||
*isreply = false;
|
||||
break;
|
||||
case VFIO_USER_REPLY:
|
||||
*isreply = true;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "unknown message type");
|
||||
return -1;
|
||||
}
|
||||
|
||||
trace_vfio_user_recv_hdr(proxy->sockname, hdr->id, hdr->command, hdr->size,
|
||||
hdr->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive and process one incoming message.
|
||||
*
|
||||
@@ -229,19 +281,14 @@ static int vfio_user_complete(VFIOUserProxy *proxy, Error **errp)
|
||||
*/
|
||||
static int vfio_user_recv_one(VFIOUserProxy *proxy, Error **errp)
|
||||
{
|
||||
VFIOUserMsg *msg = NULL;
|
||||
g_autofree int *fdp = NULL;
|
||||
VFIOUserFDs *reqfds;
|
||||
VFIOUserHdr hdr;
|
||||
struct iovec iov = {
|
||||
.iov_base = &hdr,
|
||||
.iov_len = sizeof(hdr),
|
||||
};
|
||||
VFIOUserMsg *msg = NULL;
|
||||
bool isreply = false;
|
||||
int i, ret;
|
||||
size_t msgleft, numfds = 0;
|
||||
size_t msgleft = 0;
|
||||
size_t numfds = 0;
|
||||
char *data = NULL;
|
||||
char *buf = NULL;
|
||||
VFIOUserHdr hdr;
|
||||
int i, ret;
|
||||
|
||||
/*
|
||||
* Complete any partial reads
|
||||
@@ -260,49 +307,17 @@ static int vfio_user_recv_one(VFIOUserProxy *proxy, Error **errp)
|
||||
/* else fall into reading another msg */
|
||||
}
|
||||
|
||||
/*
|
||||
* Read header
|
||||
*/
|
||||
ret = qio_channel_readv_full(proxy->ioc, &iov, 1, &fdp, &numfds, 0,
|
||||
errp);
|
||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* read error or other side closed connection */
|
||||
if (ret <= 0) {
|
||||
goto fatal;
|
||||
}
|
||||
|
||||
if (ret < sizeof(hdr)) {
|
||||
error_setg(errp, "short read of header");
|
||||
ret = vfio_user_recv_hdr(proxy, errp, &hdr, &fdp, &numfds, &isreply);
|
||||
if (ret < 0) {
|
||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||
return ret;
|
||||
}
|
||||
goto fatal;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate header
|
||||
*/
|
||||
if (hdr.size < sizeof(VFIOUserHdr)) {
|
||||
error_setg(errp, "bad header size");
|
||||
goto fatal;
|
||||
}
|
||||
switch (hdr.flags & VFIO_USER_TYPE) {
|
||||
case VFIO_USER_REQUEST:
|
||||
isreply = false;
|
||||
break;
|
||||
case VFIO_USER_REPLY:
|
||||
isreply = true;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "unknown message type");
|
||||
goto fatal;
|
||||
}
|
||||
trace_vfio_user_recv_hdr(proxy->sockname, hdr.id, hdr.command, hdr.size,
|
||||
hdr.flags);
|
||||
|
||||
/*
|
||||
* For replies, find the matching pending request.
|
||||
* For requests, reap incoming FDs.
|
||||
* Find the matching request if this is a reply, or initialize a new
|
||||
* server->client request.
|
||||
*/
|
||||
if (isreply) {
|
||||
QTAILQ_FOREACH(msg, &proxy->pending, next) {
|
||||
@@ -316,56 +331,52 @@ static int vfio_user_recv_one(VFIOUserProxy *proxy, Error **errp)
|
||||
}
|
||||
QTAILQ_REMOVE(&proxy->pending, msg, next);
|
||||
|
||||
/*
|
||||
* Process any received FDs
|
||||
*/
|
||||
if (numfds != 0) {
|
||||
if (msg->fds == NULL || msg->fds->recv_fds < numfds) {
|
||||
error_setg(errp, "unexpected FDs");
|
||||
goto err;
|
||||
}
|
||||
msg->fds->recv_fds = numfds;
|
||||
memcpy(msg->fds->fds, fdp, numfds * sizeof(int));
|
||||
}
|
||||
} else {
|
||||
if (numfds != 0) {
|
||||
reqfds = vfio_user_getfds(numfds);
|
||||
memcpy(reqfds->fds, fdp, numfds * sizeof(int));
|
||||
} else {
|
||||
reqfds = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the whole message into a single buffer.
|
||||
*/
|
||||
if (isreply) {
|
||||
if (hdr.size > msg->rsize) {
|
||||
error_setg(errp, "reply larger than recv buffer");
|
||||
goto err;
|
||||
}
|
||||
*msg->hdr = hdr;
|
||||
data = (char *)msg->hdr + sizeof(hdr);
|
||||
} else {
|
||||
void *buf;
|
||||
|
||||
if (hdr.size > proxy->max_xfer_size + sizeof(VFIOUserDMARW)) {
|
||||
error_setg(errp, "vfio_user_recv request larger than max");
|
||||
goto err;
|
||||
}
|
||||
|
||||
buf = g_malloc0(hdr.size);
|
||||
memcpy(buf, &hdr, sizeof(hdr));
|
||||
data = buf + sizeof(hdr);
|
||||
msg = vfio_user_getmsg(proxy, (VFIOUserHdr *)buf, reqfds);
|
||||
msg = vfio_user_getmsg(proxy, buf, NULL);
|
||||
msg->type = VFIO_MSG_REQ;
|
||||
}
|
||||
|
||||
*msg->hdr = hdr;
|
||||
data = (char *)msg->hdr + sizeof(hdr);
|
||||
|
||||
if (numfds != 0) {
|
||||
if (msg->type == VFIO_MSG_REQ) {
|
||||
msg->fds = vfio_user_getfds(numfds);
|
||||
} else {
|
||||
if (msg->fds == NULL || msg->fds->recv_fds < numfds) {
|
||||
error_setg(errp, "unexpected FDs in reply");
|
||||
goto err;
|
||||
}
|
||||
msg->fds->recv_fds = numfds;
|
||||
}
|
||||
|
||||
memcpy(msg->fds->fds, fdp, numfds * sizeof(int));
|
||||
}
|
||||
|
||||
/*
|
||||
* Read rest of message.
|
||||
* Read rest of message into the data buffer.
|
||||
*/
|
||||
|
||||
msgleft = hdr.size - sizeof(hdr);
|
||||
while (msgleft > 0) {
|
||||
ret = qio_channel_read(proxy->ioc, data, msgleft, errp);
|
||||
|
||||
/* prepare to complete read on next iternation */
|
||||
/*
|
||||
* We'll complete this read on the next go around; keep track of the
|
||||
* partial message until then.
|
||||
*/
|
||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||
proxy->part_recv = msg;
|
||||
proxy->recv_left = msgleft;
|
||||
@@ -381,7 +392,7 @@ static int vfio_user_recv_one(VFIOUserProxy *proxy, Error **errp)
|
||||
data += ret;
|
||||
}
|
||||
|
||||
vfio_user_process(proxy, msg, isreply);
|
||||
vfio_user_process(proxy, msg);
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@@ -401,11 +412,22 @@ err:
|
||||
for (i = 0; i < numfds; i++) {
|
||||
close(fdp[i]);
|
||||
}
|
||||
if (isreply && msg != NULL) {
|
||||
/* force an error to keep sending thread from hanging */
|
||||
vfio_user_set_error(msg->hdr, EINVAL);
|
||||
msg->complete = true;
|
||||
qemu_cond_signal(&msg->cv);
|
||||
if (msg != NULL) {
|
||||
if (msg->type == VFIO_MSG_REQ) {
|
||||
/*
|
||||
* Clean up the request message on failure. Change type back to
|
||||
* NOWAIT to free.
|
||||
*/
|
||||
msg->type = VFIO_MSG_NOWAIT;
|
||||
vfio_user_recycle(proxy, msg);
|
||||
} else {
|
||||
/*
|
||||
* Report an error back to the sender. Sender will recycle msg.
|
||||
*/
|
||||
vfio_user_set_error(msg->hdr, EINVAL);
|
||||
msg->complete = true;
|
||||
qemu_cond_signal(&msg->cv);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user