@samitouri / QOSamiQemu / commits / e2358af583

vfio-user: support VFIO_USER_DEVICE_FEATURE

Plumb through vfio_device_get_feature to the vfio-user server. Note that we translate EINVAL into ENOTTY, as the existing generic vfio code is expecting the latter to mean "unsupported". As part of adding a trace point, clean up the trace file. 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-2-john.levon@nutanix.com Signed-off-by: Cédric Le Goater <clg@redhat.com>

John Levon committed Apr 10, 2026 at 09:57 UTC e2358af5838dc36552d71441ecdf07faad7c6446
3 files changed +67 -10
hw/vfio-user/device.c
+42
@@ -74,6 +74,47 @@ void vfio_user_device_reset(VFIOUserProxy *proxy)
74 }
75 }
76
77 +static int
78 +vfio_user_device_io_device_feature(VFIODevice *vbasedev,
79 + struct vfio_device_feature *feature)
80 +{
81 + g_autofree VFIOUserDeviceFeature *msgp = NULL;
82 + int size = sizeof(VFIOUserHdr) + feature->argsz;
83 + VFIOUserProxy *proxy = vbasedev->proxy;
84 + Error *local_err = NULL;
85 +
86 + msgp = g_malloc0(size);
87 +
88 + vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_FEATURE, size, 0);
89 +
90 + memcpy(&msgp->argsz, &feature->argsz, feature->argsz);
91 +
92 + if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, size, &local_err)) {
93 + error_prepend(&local_err, "%s: ", __func__);
94 + error_report_err(local_err);
95 + return -EFAULT;
96 + }
97 +
98 + if (msgp->hdr.flags & VFIO_USER_ERROR) {
99 + /*
100 + * Client expects ENOTTY for "not supported", but the protocol may
101 + * return EINVAL (which should only occur in the case the feature isn't
102 + * actually supported on the server).
103 + */
104 + if (msgp->hdr.error_reply == EINVAL) {
105 + return -ENOTTY;
106 + }
107 +
108 + return -msgp->hdr.error_reply;
109 + }
110 +
111 + memcpy(feature, &msgp->argsz, feature->argsz);
112 +
113 + trace_vfio_user_device_io_device_feature(msgp->argsz, msgp->flags);
114 +
115 + return 0;
116 +}
117 +
118 static int vfio_user_get_region_info(VFIOUserProxy *proxy,
119 struct vfio_region_info *info,
120 VFIOUserFDs *fds)
@@ -432,6 +473,7 @@ static int vfio_user_device_io_region_write(VFIODevice *vbasedev, uint8_t index,
473 * Socket-based io_ops
474 */
475 VFIODeviceIOOps vfio_user_device_io_ops_sock = {
476 + .device_feature = vfio_user_device_io_device_feature,
477 .get_region_info = vfio_user_device_io_get_region_info,
478 .get_irq_info = vfio_user_device_io_get_irq_info,
479 .set_irqs = vfio_user_device_io_set_irqs,
hw/vfio-user/protocol.h
+12
@@ -40,6 +40,7 @@ enum vfio_user_command {
40 VFIO_USER_DEVICE_RESET = 13,
41 VFIO_USER_DIRTY_PAGES = 14,
42 VFIO_USER_REGION_WRITE_MULTI = 15,
43 + VFIO_USER_DEVICE_FEATURE = 16,
44 VFIO_USER_MAX,
45 };
46
@@ -239,4 +240,15 @@ typedef struct {
240 VFIOUserWROne wrs[VFIO_USER_MULTI_MAX];
241 } VFIOUserWRMulti;
242
243 +/*
244 + * VFIO_USER_DEVICE_FEATURE
245 + * imported from struct vfio_device_feature
246 + */
247 +typedef struct {
248 + VFIOUserHdr hdr;
249 + uint32_t argsz;
250 + uint32_t flags;
251 + char data[];
252 +} VFIOUserDeviceFeature;
253 +
254 #endif /* VFIO_USER_PROTOCOL_H */
hw/vfio-user/trace-events
+13 -10
@@ -2,19 +2,22 @@
2 #
3 # SPDX-License-Identifier: GPL-2.0-or-later
4
5 -# common.c
5 +# container.c
6 +vfio_user_dma_map(uint64_t iova, uint64_t size, uint64_t off, uint32_t flags, bool async_ops) " iova 0x%"PRIx64" size 0x%"PRIx64" off 0x%"PRIx64" flags 0x%x async_ops %d"
7 +vfio_user_dma_unmap(uint64_t iova, uint64_t size, uint32_t flags, bool async_ops) " iova 0x%"PRIx64" size 0x%"PRIx64" flags 0x%x async_ops %d"
8 +
9 +# device.c
10 +vfio_user_device_io_device_feature(uint32_t argsz, uint32_t flags) " argsz 0x%x flags 0x%x"
11 +vfio_user_get_info(uint32_t nregions, uint32_t nirqs) " #regions %d #irqs %d"
12 +vfio_user_get_irq_info(uint32_t index, uint32_t flags, uint32_t count) " index %d flags 0x%x count %d"
13 +vfio_user_set_irqs(uint32_t index, uint32_t start, uint32_t count, uint32_t flags) " index %d start %d count %d flags 0x%x"
14 +vfio_user_get_region_info(uint32_t index, uint32_t flags, uint64_t size) " index %d flags 0x%x size 0x%"PRIx64
15 +vfio_user_region_rw(uint32_t region, uint64_t off, uint32_t count) " region %d offset 0x%"PRIx64" count %d"
16 +
17 +# proxy.c
18 vfio_user_recv_hdr(const char *name, uint16_t id, uint16_t cmd, uint32_t size, uint32_t flags) " (%s) id 0x%x cmd 0x%x size 0x%x flags 0x%x"
19 vfio_user_recv_read(uint16_t id, int read) " id 0x%x read 0x%x"
20 vfio_user_recv_request(uint16_t cmd) " command 0x%x"
21 vfio_user_send_write(uint16_t id, int wrote) " id 0x%x wrote 0x%x"
22 vfio_user_version(uint16_t major, uint16_t minor, const char *caps) " major %d minor %d caps: %s"
11 -vfio_user_get_info(uint32_t nregions, uint32_t nirqs) " #regions %d #irqs %d"
12 -vfio_user_get_region_info(uint32_t index, uint32_t flags, uint64_t size) " index %d flags 0x%x size 0x%"PRIx64
13 -vfio_user_region_rw(uint32_t region, uint64_t off, uint32_t count) " region %d offset 0x%"PRIx64" count %d"
14 -vfio_user_get_irq_info(uint32_t index, uint32_t flags, uint32_t count) " index %d flags 0x%x count %d"
15 -vfio_user_set_irqs(uint32_t index, uint32_t start, uint32_t count, uint32_t flags) " index %d start %d count %d flags 0x%x"
23 vfio_user_wrmulti(const char *s, uint64_t wr_cnt) " %s count 0x%"PRIx64
17 -
18 -# container.c
19 -vfio_user_dma_map(uint64_t iova, uint64_t size, uint64_t off, uint32_t flags, bool async_ops) " iova 0x%"PRIx64" size 0x%"PRIx64" off 0x%"PRIx64" flags 0x%x async_ops %d"
20 -vfio_user_dma_unmap(uint64_t iova, uint64_t size, uint32_t flags, bool async_ops) " iova 0x%"PRIx64" size 0x%"PRIx64" flags 0x%x async_ops %d"