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