@samitouri / QOSamiQemu / commits / 6608dca74e

vhost-user-device: Add shared memory BAR

Add shared memory BAR support to vhost-user-device-pci to enable direct file mapping for VIRTIO Shared Memory Regions. The implementation creates a consolidated shared memory BAR that contains all VIRTIO Shared Memory Regions as subregions. Each region is configured with its proper shmid, size, and offset within the BAR. The number and size of regions are retrieved via VHOST_USER_GET_SHMEM_CONFIG message sent by vhost-user-base during realization after virtio_init(). Specifically, it uses BAR 4 to avoid conflicts, as it is currently unused. The shared memory BAR is only created when the backend supports VHOST_USER_PROTOCOL_F_SHMEM and has configured shared memory regions. This maintains backward compatibility with backends that do not support shared memory functionality. Reviewed-by: Stefano Garzarella <sgarzare@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Albert Esteve <aesteve@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-Id: <20260304165223.2166175-8-aesteve@redhat.com>

Albert Esteve committed Mar 4, 2026 at 17:52 UTC 6608dca74ecfc3e59cdf876cb5490750f37d3706
2 files changed +83 -5
hw/virtio/vhost-user-base.c
+43 -3
@@ -16,6 +16,7 @@
16 #include "hw/virtio/virtio-bus.h"
17 #include "hw/virtio/vhost-user-base.h"
18 #include "qemu/error-report.h"
19 +#include "migration/blocker.h"
20
21 static void vub_start(VirtIODevice *vdev)
22 {
@@ -281,7 +282,8 @@ static void vub_device_realize(DeviceState *dev, Error **errp)
282 {
283 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
284 VHostUserBase *vub = VHOST_USER_BASE(dev);
284 - int ret;
285 + uint64_t memory_sizes[VIRTIO_MAX_SHMEM_REGIONS];
286 + int i, ret, nregions, regions_processed = 0;
287
288 if (!vub->chardev.chr) {
289 error_setg(errp, "vhost-user-base: missing chardev");
@@ -324,7 +326,7 @@ static void vub_device_realize(DeviceState *dev, Error **errp)
326
327 /* Allocate queues */
328 vub->vqs = g_ptr_array_sized_new(vub->num_vqs);
327 - for (int i = 0; i < vub->num_vqs; i++) {
329 + for (i = 0; i < vub->num_vqs; i++) {
330 g_ptr_array_add(vub->vqs,
331 virtio_add_queue(vdev, vub->vq_size,
332 vub_handle_output));
@@ -338,11 +340,49 @@ static void vub_device_realize(DeviceState *dev, Error **errp)
340 VHOST_BACKEND_TYPE_USER, 0, errp);
341
342 if (ret < 0) {
341 - do_vhost_user_cleanup(vdev, vub);
343 + goto err;
344 + }
345 +
346 + ret = vub->vhost_dev.vhost_ops->vhost_get_shmem_config(&vub->vhost_dev,
347 + &nregions,
348 + memory_sizes,
349 + errp);
350 +
351 + if (ret < 0) {
352 + goto err;
353 + }
354 +
355 + for (i = 0; i < VIRTIO_MAX_SHMEM_REGIONS && regions_processed < nregions; i++) {
356 + if (memory_sizes[i]) {
357 + regions_processed++;
358 + if (vub->vhost_dev.migration_blocker == NULL) {
359 + error_setg(&vub->vhost_dev.migration_blocker,
360 + "Migration disabled: devices with VIRTIO Shared Memory "
361 + "Regions do not support migration yet.");
362 + ret = migrate_add_blocker_normal(
363 + &vub->vhost_dev.migration_blocker,
364 + errp);
365 +
366 + if (ret < 0) {
367 + goto err;
368 + }
369 + }
370 +
371 + if (memory_sizes[i] % qemu_real_host_page_size() != 0) {
372 + error_setg(errp, "Shared memory %d size must be a multiple of "
373 + "the host page size", i);
374 + goto err;
375 + }
376 +
377 + virtio_new_shmem_region(vdev, i, memory_sizes[i]);
378 + }
379 }
380
381 qemu_chr_fe_set_handlers(&vub->chardev, NULL, NULL, vub_event, NULL,
382 dev, NULL, true);
383 + return;
384 +err:
385 + do_vhost_user_cleanup(vdev, vub);
386 }
387
388 static void vub_device_unrealize(DeviceState *dev)
hw/virtio/vhost-user-test-device-pci.c
+40 -2
@@ -12,10 +12,13 @@
12 #include "hw/virtio/vhost-user-base.h"
13 #include "hw/virtio/virtio-pci.h"
14
15 +#define VIRTIO_DEVICE_PCI_SHMEM_BAR 4
16 +
17 struct VHostUserDevicePCI {
18 VirtIOPCIProxy parent_obj;
19
20 VHostUserBase vub;
21 + MemoryRegion shmembar;
22 };
23
24 #define TYPE_VHOST_USER_TEST_DEVICE_PCI "vhost-user-test-device-pci-base"
@@ -25,10 +28,45 @@ OBJECT_DECLARE_SIMPLE_TYPE(VHostUserDevicePCI, VHOST_USER_TEST_DEVICE_PCI)
28 static void vhost_user_device_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
29 {
30 VHostUserDevicePCI *dev = VHOST_USER_TEST_DEVICE_PCI(vpci_dev);
28 - DeviceState *vdev = DEVICE(&dev->vub);
31 + DeviceState *dev_state = DEVICE(&dev->vub);
32 + VirtIODevice *vdev = VIRTIO_DEVICE(dev_state);
33 + VirtioSharedMemory *shmem;
34 + uint64_t offset = 0, shmem_size = 0;
35
36 + /* Keep modern 64-bit BARs (2 slots) away from the shared memory BAR. */
37 + vpci_dev->modern_mem_bar_idx = 2;
38 vpci_dev->nvectors = 1;
31 - qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
39 + if (!qdev_realize(dev_state, BUS(&vpci_dev->bus), errp)) {
40 + return;
41 + }
42 +
43 + QSIMPLEQ_FOREACH(shmem, &vdev->shmem_list, entry) {
44 + if (memory_region_size(&shmem->mr) > UINT64_MAX - shmem_size) {
45 + error_setg(errp, "Total shared memory required overflow");
46 + return;
47 + }
48 + shmem_size = shmem_size + memory_region_size(&shmem->mr);
49 + }
50 + if (shmem_size) {
51 + if (vpci_dev->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY) {
52 + error_setg(errp, "modern-pio-notify is not supported due to PCI BAR layout limitations");
53 + return;
54 + }
55 + memory_region_init(&dev->shmembar, OBJECT(vpci_dev),
56 + "vhost-device-pci-shmembar", shmem_size);
57 + QSIMPLEQ_FOREACH(shmem, &vdev->shmem_list, entry) {
58 + memory_region_add_subregion(&dev->shmembar, offset, &shmem->mr);
59 + virtio_pci_add_shm_cap(vpci_dev, VIRTIO_DEVICE_PCI_SHMEM_BAR,
60 + offset, memory_region_size(&shmem->mr),
61 + shmem->shmid);
62 + offset = offset + memory_region_size(&shmem->mr);
63 + }
64 + pci_register_bar(&vpci_dev->pci_dev, VIRTIO_DEVICE_PCI_SHMEM_BAR,
65 + PCI_BASE_ADDRESS_SPACE_MEMORY |
66 + PCI_BASE_ADDRESS_MEM_PREFETCH |
67 + PCI_BASE_ADDRESS_MEM_TYPE_64,
68 + &dev->shmembar);
69 + }
70 }
71
72 static void vhost_user_device_pci_class_init(ObjectClass *klass,