@samitouri / QOSamiQemu / commits / aad4254c6d

vfio-user: fix DMA write reply

The protocol specifies that DMA write replies should include address+count, but the client code was only doing so for read. Fix that up. In addition, add a protocol clarification over how short writes may be reported in that reply. QEMU never reports a short write via the count field. Reported-by: Patrick Mooney <patrick@matx.com> 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/20260410085716.877185-4-john.levon@nutanix.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

John Levon committed Apr 10, 2026 at 09:57 UTC aad4254c6d00d9382ae8a6d105a74f493760e738
2 files changed +28 -8
docs/interop/vfio-user.rst
+6
@@ -1429,6 +1429,9 @@ Reply
1429 * *count* is the size of the data transferred.
1430 * *data* is the data read.
1431
1432 +Note that whether short reads return an error or just set count appropriately is
1433 +a client-side choice; servers should be prepared to handle both cases.
1434 +
1435 ``VFIO_USER_DMA_WRITE``
1436 -----------------------
1437
@@ -1469,6 +1472,9 @@ Reply
1472 * *address* is the client DMA memory address being accessed.
1473 * *count* is the size of the data transferred.
1474
1475 +Note that whether short writes return an error or just set count appropriately
1476 +is a client-side choice; servers should be prepared to handle both cases.
1477 +
1478 ``VFIO_USER_DEVICE_RESET``
1479 --------------------------
1480
hw/vfio-user/pci.c
+22 -8
@@ -109,6 +109,10 @@ static void vfio_user_dma_read(VFIOPCIDevice *vdev, VFIOUserDMARW *msg)
109
110 r = pci_dma_read(pdev, res->offset, &res->data, res->count);
111
112 + /*
113 + * pci_dma_read() doesn't support reporting short reads via the reply's
114 + * count parameter; in this case, we'll reply with an error instead.
115 + */
116 switch (r) {
117 case MEMTX_OK:
118 if (res->hdr.flags & VFIO_USER_NO_REPLY) {
@@ -136,6 +140,7 @@ static void vfio_user_dma_write(VFIOPCIDevice *vdev, VFIOUserDMARW *msg)
140 {
141 PCIDevice *pdev = PCI_DEVICE(vdev);
142 VFIOUserProxy *proxy = vdev->vbasedev.proxy;
143 + VFIOUserDMARW *res;
144 MemTxResult r;
145
146 if (msg->hdr.size < sizeof(*msg)) {
@@ -150,26 +155,35 @@ static void vfio_user_dma_write(VFIOPCIDevice *vdev, VFIOUserDMARW *msg)
155
156 r = pci_dma_write(pdev, msg->offset, &msg->data, msg->count);
157
158 + res = g_malloc0(sizeof(*res));
159 + memcpy(res, msg, sizeof(*res));
160 + g_free(msg);
161 +
162 + /*
163 + * pci_dma_write() doesn't support reporting short writes via the reply's
164 + * count parameter; in this case, we'll reply with an error instead.
165 + */
166 switch (r) {
167 case MEMTX_OK:
155 - if ((msg->hdr.flags & VFIO_USER_NO_REPLY) == 0) {
156 - vfio_user_send_reply(proxy, &msg->hdr, sizeof(msg->hdr));
157 - } else {
158 - g_free(msg);
168 + if (res->hdr.flags & VFIO_USER_NO_REPLY) {
169 + g_free(res);
170 + return;
171 }
172 +
173 + vfio_user_send_reply(proxy, &res->hdr, sizeof(*res));
174 break;
175 case MEMTX_ERROR:
162 - vfio_user_send_error(proxy, &msg->hdr, EFAULT);
176 + vfio_user_send_error(proxy, &res->hdr, EFAULT);
177 break;
178 case MEMTX_DECODE_ERROR:
165 - vfio_user_send_error(proxy, &msg->hdr, ENODEV);
179 + vfio_user_send_error(proxy, &res->hdr, ENODEV);
180 break;
181 case MEMTX_ACCESS_ERROR:
168 - vfio_user_send_error(proxy, &msg->hdr, EPERM);
182 + vfio_user_send_error(proxy, &res->hdr, EPERM);
183 break;
184 default:
185 error_printf("vfio_user_dma_write unknown error %d\n", r);
172 - vfio_user_send_error(vdev->vbasedev.proxy, &msg->hdr, EINVAL);
186 + vfio_user_send_error(vdev->vbasedev.proxy, &res->hdr, EINVAL);
187 }
188 }
189