@samitouri / QOSamiQemu / commits / be51b7177c

vhost-user: add VHOST_USER_PROTOCOL_F_GPA_ADDRESSES

Unlike the kernel, vhost-user backend knows nothing about QEMU's userspace addresses. We can pass GPA instead and nothing changes. Generally, vhost-user servers need these addresses only to calculate offsets inside memory regions. Still, some servers (QEMU's internal is one example) may do checks for passed addresses to be "userspace addresses", for example check for non-zero. That's why we need additional negotiation for the feature. The benefit: this opens the doors for further implementation of local migration (live-update) with passing open vhost-related FDs through UNIX domain socket. This way the connection with backend is kept live and untouched. Without this change, we would have to communicate with backend to inform it about UVA address changes, but it's better to simply use more stable GPA numbers, which don't change after migration. Additionally, the current implementation exposes QEMU's process address space by passing UVA, which breaks ASLR. New protocol feature avoids that. Note, that we do nothing with backend messages and replies. Frontends have to work with backends userspace addresses anyway, because they come from userfaultfd. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Based-on: <20260206095258.894504-1-vsementsov@yandex-team.ru> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-Id: <20260420202032.714884-11-vsementsov@yandex-team.ru>

Vladimir Sementsov-Ogievskiy committed Apr 20, 2026 at 23:20 UTC be51b7177c9c7c6f1e2ff1b4cd250649e1d6dcaf
3 files changed +35 -9
docs/interop/vhost-user.rst
+17 -4
@@ -164,8 +164,16 @@ A vring address description
164
165 :log: a 64-bit guest address for logging
166
167 -Note that a ring address is an IOVA if ``VIRTIO_F_IOMMU_PLATFORM`` has
168 -been negotiated. Otherwise it is a user address.
167 +.. Note::
168 + When ``VIRTIO_F_IOMMU_PLATFORM`` is negotiated, ring addresses are IOVAs.
169 +
170 + Otherwise, when ``VHOST_USER_PROTOCOL_F_GPA_ADDRESSES`` is negotiated, the
171 + ring addresses are guest physical addresses for frontend messages. That
172 + does not apply to backend replies.
173 +
174 + Finally, when neither ``VIRTIO_F_IOMMU_PLATFORM`` nor
175 + ``VHOST_USER_PROTOCOL_F_GPA_ADDRESSES`` features are negotiated, ring
176 + addresses are user virtual addresses.
177
178 .. _memory_region_description:
179
@@ -180,7 +188,9 @@ Memory region description
188
189 :size: a 64-bit size
190
183 -:user address: a 64-bit user address
191 +:user address: a 64-bit user address. When ``VHOST_USER_PROTOCOL_F_GPA_ADDRESSES``
192 + is negotiated, this field contain guest physical address instead and must
193 + duplicate ``guest address`` field.
194
195 :mmap offset: a 64-bit offset where region starts in the mapped memory
196
@@ -252,7 +262,9 @@ An IOTLB message
262
263 :size: a 64-bit size
264
255 -:user address: a 64-bit user address
265 +:user address: a 64-bit user address. When ``VHOST_USER_PROTOCOL_F_GPA_ADDRESSES``
266 + is negotiated, this field contain guest physical address instead, except for
267 + ``VHOST_USER_BACKEND_IOTLB_MSG``, where it's user address anyway.
268
269 :permissions flags: an 8-bit value:
270 - 0: No access
@@ -1063,6 +1075,7 @@ Protocol features
1075 #define VHOST_USER_PROTOCOL_F_SHARED_OBJECT 18
1076 #define VHOST_USER_PROTOCOL_F_DEVICE_STATE 19
1077 #define VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT 20
1078 + #define VHOST_USER_PROTOCOL_F_GPA_ADDRESSES 21
1079
1080 Front-end message types
1081 -----------------------
hw/virtio/vhost-user.c
+17 -5
@@ -563,12 +563,22 @@ static MemoryRegion *vhost_user_get_mr_data(uint64_t addr, ram_addr_t *offset,
563 return mr;
564 }
565
566 -static void vhost_user_fill_msg_region(VhostUserMemoryRegion *dst,
566 +static bool vhost_user_gpa_addresses(struct vhost_dev *dev)
567 +{
568 + return vhost_user_has_protocol_feature(
569 + dev, VHOST_USER_PROTOCOL_F_GPA_ADDRESSES);
570 +}
571 +
572 +static void vhost_user_fill_msg_region(struct vhost_dev *dev,
573 + VhostUserMemoryRegion *dst,
574 struct vhost_memory_region *src,
575 uint64_t mmap_offset)
576 {
577 + bool use_phys = vhost_user_gpa_addresses(dev);
578 +
579 assert(src != NULL && dst != NULL);
571 - dst->userspace_addr = src->userspace_addr;
580 +
581 + dst->userspace_addr = use_phys ? src->guest_phys_addr : src->userspace_addr;
582 dst->memory_size = src->memory_size;
583 dst->guest_phys_addr = src->guest_phys_addr;
584 dst->mmap_offset = mmap_offset;
@@ -606,7 +616,7 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u,
616 error_report("Failed preparing vhost-user memory table msg");
617 return -ENOBUFS;
618 }
609 - vhost_user_fill_msg_region(&region_buffer, reg, offset);
619 + vhost_user_fill_msg_region(dev, &region_buffer, reg, offset);
620 msg->payload.memory.regions[*fd_num] = region_buffer;
621 fds[(*fd_num)++] = fd;
622 } else if (track_ramblocks) {
@@ -752,7 +762,7 @@ static int send_remove_regions(struct vhost_dev *dev,
762
763 if (fd > 0) {
764 msg->hdr.request = VHOST_USER_REM_MEM_REG;
755 - vhost_user_fill_msg_region(&region_buffer, shadow_reg, 0);
765 + vhost_user_fill_msg_region(dev, &region_buffer, shadow_reg, 0);
766 msg->payload.mem_reg.region = region_buffer;
767
768 ret = vhost_user_write(dev, msg, NULL, 0);
@@ -813,7 +823,7 @@ static int send_add_regions(struct vhost_dev *dev,
823 u->region_rb[reg_idx] = mr->ram_block;
824 }
825 msg->hdr.request = VHOST_USER_ADD_MEM_REG;
816 - vhost_user_fill_msg_region(&region_buffer, reg, offset);
826 + vhost_user_fill_msg_region(dev, &region_buffer, reg, offset);
827 msg->payload.mem_reg.region = region_buffer;
828
829 ret = vhost_user_write(dev, msg, &fd, 1);
@@ -3151,4 +3161,6 @@ const VhostOps user_ops = {
3161 .vhost_supports_device_state = vhost_user_supports_device_state,
3162 .vhost_set_device_state_fd = vhost_user_set_device_state_fd,
3163 .vhost_check_device_state = vhost_user_check_device_state,
3164 + .vhost_phys_vring_addr = vhost_user_gpa_addresses,
3165 + .vhost_phys_iotlb_msg = vhost_user_gpa_addresses,
3166 };
include/hw/virtio/vhost-user.h
+1
@@ -34,6 +34,7 @@ enum VhostUserProtocolFeature {
34 VHOST_USER_PROTOCOL_F_SHARED_OBJECT = 18,
35 VHOST_USER_PROTOCOL_F_DEVICE_STATE = 19,
36 VHOST_USER_PROTOCOL_F_GET_VRING_BASE_INFLIGHT = 20,
37 + VHOST_USER_PROTOCOL_F_GPA_ADDRESSES = 21,
38 VHOST_USER_PROTOCOL_F_MAX
39 };
40