diff options
| author | John Levon <john.levon@nutanix.com> | 2025-06-25 20:30:08 +0100 |
|---|---|---|
| committer | Cédric Le Goater <clg@redhat.com> | 2025-06-26 08:55:38 +0200 |
| commit | 98a906d9e5827b18c51d7d7485be2f21f8900cc7 (patch) | |
| tree | f3492e6d684d46b2c5bc7897b7a05ae6d56cf8a5 /hw/vfio-user/device.c | |
| parent | 3358d926addda99e9f29f57b40d6fd22d2c29472 (diff) | |
| download | focaccia-qemu-98a906d9e5827b18c51d7d7485be2f21f8900cc7.tar.gz focaccia-qemu-98a906d9e5827b18c51d7d7485be2f21f8900cc7.zip | |
vfio-user: support posted writes
Support an asynchronous send of a vfio-user socket message (no wait for a reply) when the write is posted. This is only safe when no regions are mappable by the VM. Add an option to explicitly disable this as well. Signed-off-by: John Levon <john.levon@nutanix.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/qemu-devel/20250625193012.2316242-17-john.levon@nutanix.com Signed-off-by: Cédric Le Goater <clg@redhat.com>
Diffstat (limited to 'hw/vfio-user/device.c')
| -rw-r--r-- | hw/vfio-user/device.c | 45 |
1 files changed, 41 insertions, 4 deletions
diff --git a/hw/vfio-user/device.c b/hw/vfio-user/device.c index 3a118e7361..aa07eac330 100644 --- a/hw/vfio-user/device.c +++ b/hw/vfio-user/device.c @@ -110,10 +110,21 @@ static int vfio_user_get_region_info(VFIOUserProxy *proxy, trace_vfio_user_get_region_info(msgp->index, msgp->flags, msgp->size); memcpy(info, &msgp->argsz, info->argsz); + + /* + * If at least one region is directly mapped into the VM, then we can no + * longer rely on the sequential nature of vfio-user request handling to + * ensure that posted writes are completed before a subsequent read. In this + * case, disable posted write support. This is a per-device property, not + * per-region. + */ + if (info->flags & VFIO_REGION_INFO_FLAG_MMAP) { + vfio_user_disable_posted_writes(proxy); + } + return 0; } - static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev, struct vfio_region_info *info, int *fd) @@ -312,33 +323,58 @@ static int vfio_user_device_io_region_read(VFIODevice *vbasedev, uint8_t index, return msgp->count; } +/* + * If this is a posted write, and VFIO_PROXY_NO_POST is not set, then we are OK + * to send the write to the socket without waiting for the server's reply: + * a subsequent read (of any region) will not pass the posted write, as all + * messages are handled sequentially. + */ static int vfio_user_device_io_region_write(VFIODevice *vbasedev, uint8_t index, off_t off, unsigned count, void *data, bool post) { - g_autofree VFIOUserRegionRW *msgp = NULL; + VFIOUserRegionRW *msgp = NULL; VFIOUserProxy *proxy = vbasedev->proxy; int size = sizeof(*msgp) + count; Error *local_err = NULL; + int flags = 0; int ret; if (count > proxy->max_xfer_size) { return -EINVAL; } + if (proxy->flags & VFIO_PROXY_NO_POST) { + post = false; + } + + if (post) { + flags |= VFIO_USER_NO_REPLY; + } + msgp = g_malloc0(size); - vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_WRITE, size, 0); + vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_WRITE, size, flags); msgp->offset = off; msgp->region = index; msgp->count = count; memcpy(&msgp->data, data, count); trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count); - /* Ignore post: all writes are synchronous/non-posted. */ + /* async send will free msg after it's sent */ + if (post) { + if (!vfio_user_send_async(proxy, &msgp->hdr, NULL, &local_err)) { + error_prepend(&local_err, "%s: ", __func__); + error_report_err(local_err); + return -EFAULT; + } + + return count; + } if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) { error_prepend(&local_err, "%s: ", __func__); error_report_err(local_err); + g_free(msgp); return -EFAULT; } @@ -348,6 +384,7 @@ static int vfio_user_device_io_region_write(VFIODevice *vbasedev, uint8_t index, ret = count; } + g_free(msgp); return ret; } |