[RFC PATCH v2 2/5] vhost_user: Add frontend command for shmem config

2024-06-28 Thread Albert Esteve
The frontend can use this command to retrieve
VIRTIO Shared Memory Regions configuration from
the backend. The response contains the number of
shared memory regions, their size, and shmid.

This is useful when the frontend is unaware of
specific backend type and configuration,
for example, in the `vhost-user-device` case.

Signed-off-by: Albert Esteve 
---
 docs/interop/vhost-user.rst   | 31 +++
 hw/virtio/vhost-user.c| 42 +++
 include/hw/virtio/vhost-backend.h |  6 +
 include/hw/virtio/vhost-user.h|  1 +
 4 files changed, 80 insertions(+)

diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index d52ba719d5..51f01d1d84 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -348,6 +348,19 @@ Device state transfer parameters
   In the future, additional phases might be added e.g. to allow
   iterative migration while the device is running.
 
+VIRTIO Shared Memory Region configuration
+^
+
++-+-++++
+| num regions | padding | mem size 0 | .. | mem size 7 |
++-+-++++
+
+:num regions: a 32-bit number of regions
+
+:padding: 32-bit
+
+:mem size: 64-bit size of VIRTIO Shared Memory Region
+
 C structure
 ---
 
@@ -369,6 +382,10 @@ In QEMU the vhost-user message is implemented with the 
following struct:
   VhostUserConfig config;
   VhostUserVringArea area;
   VhostUserInflight inflight;
+  VhostUserShared object;
+  VhostUserTransferDeviceState transfer_state;
+  VhostUserMMap mmap;
+  VhostUserShMemConfig shmem;
   };
   } QEMU_PACKED VhostUserMsg;
 
@@ -1051,6 +1068,7 @@ Protocol features
   #define VHOST_USER_PROTOCOL_F_XEN_MMAP 17
   #define VHOST_USER_PROTOCOL_F_SHARED_OBJECT18
   #define VHOST_USER_PROTOCOL_F_DEVICE_STATE 19
+  #define VHOST_USER_PROTOCOL_F_SHMEM20
 
 Front-end message types
 ---
@@ -1725,6 +1743,19 @@ Front-end message types
   Using this function requires prior negotiation of the
   ``VHOST_USER_PROTOCOL_F_DEVICE_STATE`` feature.
 
+``VHOST_USER_GET_SHMEM_CONFIG``
+  :id: 44
+  :equivalent ioctl: N/A
+  :request payload: N/A
+  :reply payload: ``struct VhostUserShMemConfig``
+
+  When the ``VHOST_USER_PROTOCOL_F_SHMEM`` protocol feature has been
+  successfully negotiated, this message can be submitted by the front-end
+  to gather the VIRTIO Shared Memory Region configuration. Back-end will 
respond
+  with the number of VIRTIO Shared Memory Regions it requires, and each shared 
memory
+  region size in an array. The shared memory IDs are represented by the index
+  of the array.
+
 Back-end message types
 --
 
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 7ee8a472c6..57406dc8b4 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -104,6 +104,7 @@ typedef enum VhostUserRequest {
 VHOST_USER_GET_SHARED_OBJECT = 41,
 VHOST_USER_SET_DEVICE_STATE_FD = 42,
 VHOST_USER_CHECK_DEVICE_STATE = 43,
+VHOST_USER_GET_SHMEM_CONFIG = 44,
 VHOST_USER_MAX
 } VhostUserRequest;
 
@@ -138,6 +139,12 @@ typedef struct VhostUserMemRegMsg {
 VhostUserMemoryRegion region;
 } VhostUserMemRegMsg;
 
+typedef struct VhostUserShMemConfig {
+uint32_t nregions;
+uint32_t padding;
+uint64_t memory_sizes[VHOST_MEMORY_BASELINE_NREGIONS];
+} VhostUserShMemConfig;
+
 typedef struct VhostUserLog {
 uint64_t mmap_size;
 uint64_t mmap_offset;
@@ -245,6 +252,7 @@ typedef union {
 VhostUserShared object;
 VhostUserTransferDeviceState transfer_state;
 VhostUserMMap mmap;
+VhostUserShMemConfig shmem;
 } VhostUserPayload;
 
 typedef struct VhostUserMsg {
@@ -3136,6 +3144,39 @@ static int vhost_user_check_device_state(struct 
vhost_dev *dev, Error **errp)
 return 0;
 }
 
+static int vhost_user_get_shmem_config(struct vhost_dev *dev,
+   int *nregions,
+   uint64_t *memory_sizes,
+   Error **errp)
+{
+int ret;
+VhostUserMsg msg = {
+.hdr.request = VHOST_USER_GET_SHMEM_CONFIG,
+.hdr.flags = VHOST_USER_VERSION,
+};
+
+if (!virtio_has_feature(dev->protocol_features,
+VHOST_USER_PROTOCOL_F_SHMEM)) {
+return 0;
+}
+
+ret = vhost_user_write(dev, , NULL, 0);
+if (ret < 0) {
+return ret;
+}
+
+ret = vhost_user_read(dev, );
+if (ret < 0) {
+return ret;
+}
+
+*nregions = msg.payload.shmem.nregions;
+memcpy(memory_sizes,
+   _sizes,
+   sizeof(uint64_t) * VHOST_MEMORY_BASELINE_NREGIONS);
+return 0;
+}
+
 const VhostOps user_ops = {
 .backend_type = VHOST_BACKEND_

[RFC PATCH v2 4/5] vhost_user: Add MEM_READ/WRITE backend requests

2024-06-28 Thread Albert Esteve
With SHMEM_MAP messages, sharing descriptors between
devices will cause that these devices do not see the
mappings, and fail to access these memory regions.

To solve this, introduce MEM_READ/WRITE requests
that will get triggered as a fallback when
vhost-user memory translation fails.

Signed-off-by: Albert Esteve 
---
 hw/virtio/vhost-user.c| 31 +
 subprojects/libvhost-user/libvhost-user.c | 84 +++
 subprojects/libvhost-user/libvhost-user.h | 38 ++
 3 files changed, 153 insertions(+)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 57406dc8b4..18cacb2d68 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -118,6 +118,8 @@ typedef enum VhostUserBackendRequest {
 VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP = 8,
 VHOST_USER_BACKEND_SHMEM_MAP = 9,
 VHOST_USER_BACKEND_SHMEM_UNMAP = 10,
+VHOST_USER_BACKEND_MEM_READ = 11,
+VHOST_USER_BACKEND_MEM_WRITE = 12,
 VHOST_USER_BACKEND_MAX
 }  VhostUserBackendRequest;
 
@@ -145,6 +147,12 @@ typedef struct VhostUserShMemConfig {
 uint64_t memory_sizes[VHOST_MEMORY_BASELINE_NREGIONS];
 } VhostUserShMemConfig;
 
+typedef struct VhostUserMemRWMsg {
+uint64_t guest_address;
+uint32_t size;
+uint8_t data[];
+} VhostUserMemRWMsg;
+
 typedef struct VhostUserLog {
 uint64_t mmap_size;
 uint64_t mmap_offset;
@@ -253,6 +261,7 @@ typedef union {
 VhostUserTransferDeviceState transfer_state;
 VhostUserMMap mmap;
 VhostUserShMemConfig shmem;
+VhostUserMemRWMsg mem_rw;
 } VhostUserPayload;
 
 typedef struct VhostUserMsg {
@@ -1871,6 +1880,22 @@ vhost_user_backend_handle_shmem_unmap(struct vhost_dev 
*dev,
 return 0;
 }
 
+static int
+vhost_user_backend_handle_mem_read(struct vhost_dev *dev,
+   VhostUserMemRWMsg *mem_rw)
+{
+/* TODO */
+return -EPERM;
+}
+
+static int
+vhost_user_backend_handle_mem_write(struct vhost_dev *dev,
+   VhostUserMemRWMsg *mem_rw)
+{
+/* TODO */
+return -EPERM;
+}
+
 static void close_backend_channel(struct vhost_user *u)
 {
 g_source_destroy(u->backend_src);
@@ -1946,6 +1971,12 @@ static gboolean backend_read(QIOChannel *ioc, 
GIOCondition condition,
 case VHOST_USER_BACKEND_SHMEM_UNMAP:
 ret = vhost_user_backend_handle_shmem_unmap(dev, );
 break;
+case VHOST_USER_BACKEND_MEM_READ:
+ret = vhost_user_backend_handle_mem_read(dev, _rw);
+break;
+case VHOST_USER_BACKEND_MEM_WRITE:
+ret = vhost_user_backend_handle_mem_write(dev, _rw);
+break;
 default:
 error_report("Received unexpected msg type: %d.", hdr.request);
 ret = -EINVAL;
diff --git a/subprojects/libvhost-user/libvhost-user.c 
b/subprojects/libvhost-user/libvhost-user.c
index 28556d183a..b5184064b5 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -1651,6 +1651,90 @@ vu_shmem_unmap(VuDev *dev, uint8_t shmid, uint64_t 
fd_offset,
 return vu_process_message_reply(dev, );
 }
 
+bool
+vu_send_mem_read(VuDev *dev, uint64_t guest_addr, uint32_t size,
+ uint8_t *data)
+{
+VhostUserMsg msg_reply;
+VhostUserMsg msg = {
+.request = VHOST_USER_BACKEND_MEM_READ,
+.size = sizeof(msg.payload.mem_rw),
+.flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK,
+.payload = {
+.mem_rw = {
+.guest_address = guest_addr,
+.size = size,
+}
+}
+};
+
+pthread_mutex_lock(>backend_mutex);
+if (!vu_message_write(dev, dev->backend_fd, )) {
+goto out_err;
+}
+
+if (!vu_message_read_default(dev, dev->backend_fd, _reply)) {
+goto out_err;
+}
+
+if (msg_reply.request != msg.request) {
+DPRINT("Received unexpected msg type. Expected %d, received %d",
+   msg.request, msg_reply.request);
+goto out_err;
+}
+
+if (msg_reply.payload.mem_rw.size != size) {
+DPRINT("Received unexpected number of bytes in the response. "
+   "Expected %d, received %d",
+   size, msg_reply.payload.mem_rw.size);
+goto out_err;
+}
+
+data = malloc(msg_reply.payload.mem_rw.size);
+if (!data) {
+DPRINT("Failed to malloc read memory data");
+goto out_err;
+}
+
+memcpy(data, msg_reply.payload.mem_rw.data, size);
+pthread_mutex_unlock(>backend_mutex);
+return true;
+
+out_err:
+pthread_mutex_unlock(>backend_mutex);
+return false;
+}
+
+bool
+vu_send_mem_write(VuDev *dev, uint64_t guest_addr, uint32_t size,
+  uint8_t *data)
+{
+VhostUserMsg msg = {
+.request = VHOST_USER_BACKEND_MEM_WRITE,
+.size = sizeof(msg.payload.mem_rw),
+.flags = VHOST_USER_VERSION,
+.payload = {
+

[RFC PATCH v2 5/5] vhost_user: Implement mem_read/mem_write handlers

2024-06-28 Thread Albert Esteve
Implement function handlers for memory read and write
operations.

Signed-off-by: Albert Esteve 
---
 hw/virtio/vhost-user.c | 34 ++
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 18cacb2d68..79becbc87b 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1884,16 +1884,42 @@ static int
 vhost_user_backend_handle_mem_read(struct vhost_dev *dev,
VhostUserMemRWMsg *mem_rw)
 {
-/* TODO */
-return -EPERM;
+ram_addr_t offset;
+int fd;
+MemoryRegion *mr;
+
+mr = vhost_user_get_mr_data(mem_rw->guest_address, , );
+
+if (!mr) {
+error_report("Failed to get memory region with address %" PRIx64,
+ mem_rw->guest_address);
+return -EFAULT;
+}
+
+memcpy(mem_rw->data, memory_region_get_ram_ptr(mr) + offset, mem_rw->size);
+
+return 0;
 }
 
 static int
 vhost_user_backend_handle_mem_write(struct vhost_dev *dev,
VhostUserMemRWMsg *mem_rw)
 {
-/* TODO */
-return -EPERM;
+ram_addr_t offset;
+int fd;
+MemoryRegion *mr;
+
+mr = vhost_user_get_mr_data(mem_rw->guest_address, , );
+
+if (!mr) {
+error_report("Failed to get memory region with address %" PRIx64,
+ mem_rw->guest_address);
+return -EFAULT;
+}
+
+memcpy(memory_region_get_ram_ptr(mr) + offset, mem_rw->data, mem_rw->size);
+
+return 0;
 }
 
 static void close_backend_channel(struct vhost_user *u)
-- 
2.45.2




[RFC PATCH v2 0/5] vhost-user: Add SHMEM_MAP/UNMAP requests

2024-06-28 Thread Albert Esteve
Hi all,

v1->v2:
- Corrected typos and clarifications from
  first review
- Added SHMEM_CONFIG frontend request to
  query VIRTIO shared memory regions from
  backends
- vhost-user-device to use SHMEM_CONFIG
  to request and initialise regions
- Added MEM_READ/WRITE backend requests
  in case address translation fails
  accessing VIRTIO Shared Memory Regions
  with MMAPs

This is an update of my attempt to have
backends support dynamic fd mapping into VIRTIO
Shared Memory Regions. After the first review
I have added more commits and new messages
to the vhost-user protocol.
However, I still have some doubts as to
how will this work, specially regarding
the MEM_READ and MEM_WRITE commands.
Thus, I am still looking for feedback,
to ensure that I am going in the right
direction with the implementation.

The usecase for this patch is, e.g., to support
vhost-user-gpu RESOURCE_BLOB operations,
or DAX Window request for virtio-fs. In
general, any operation where a backend
need to request the frontend to mmap an
fd into a VIRTIO Shared Memory Region,
so that the guest can then access it.

After receiving the SHMEM_MAP/UNMAP request,
the frontend will perform the mmap with the
instructed parameters (i.e., shmid, shm_offset,
fd_offset, fd, lenght).

As there are already a couple devices
that could benefit of such a feature,
and more could require it in the future,
the goal is to make the implementation
generic.

To that end, the VIRTIO Shared Memory
Region list is declared in the `VirtIODevice`
struct.

This patch also includes:
SHMEM_CONFIG frontend request that is
specifically meant to allow generic
vhost-user-device frontend to be able to
query VIRTIO Shared Memory settings from the
backend (as this device is generic and agnostic
of the actual backend configuration).

Finally, MEM_READ/WRITE backend requests are
added to deal with a potential issue when having
any backend sharing a descriptor that references
a mapping to another backend. The first
backend will not be able to see these
mappings. So these requests are a fallback
for vhost-user memory translation fails.

Albert Esteve (5):
  vhost-user: Add VIRTIO Shared Memory map request
  vhost_user: Add frontend command for shmem config
  vhost-user-dev: Add cache BAR
  vhost_user: Add MEM_READ/WRITE backend requests
  vhost_user: Implement mem_read/mem_write handlers

 docs/interop/vhost-user.rst   |  58 ++
 hw/virtio/vhost-user-base.c   |  39 +++-
 hw/virtio/vhost-user-device-pci.c |  37 +++-
 hw/virtio/vhost-user.c| 221 ++
 hw/virtio/virtio.c|  12 ++
 include/hw/virtio/vhost-backend.h |   6 +
 include/hw/virtio/vhost-user.h|   1 +
 include/hw/virtio/virtio.h|   5 +
 subprojects/libvhost-user/libvhost-user.c | 149 +++
 subprojects/libvhost-user/libvhost-user.h |  91 +
 10 files changed, 614 insertions(+), 5 deletions(-)

-- 
2.45.2




[RFC PATCH v2 3/5] vhost-user-dev: Add cache BAR

2024-06-28 Thread Albert Esteve
Add a cache BAR in the vhost-user-device
into which files can be directly mapped.

The number, shmid, and size of the VIRTIO Shared
Memory subregions is retrieved through a get_shmem_config
message sent by the vhost-user-base module
on the realize step, after virtio_init().

By default, if VHOST_USER_PROTOCOL_F_SHMEM
feature is not supported by the backend,
there is no cache.

Signed-off-by: Albert Esteve 
---
 hw/virtio/vhost-user-base.c   | 39 +--
 hw/virtio/vhost-user-device-pci.c | 37 ++---
 2 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/hw/virtio/vhost-user-base.c b/hw/virtio/vhost-user-base.c
index a83167191e..e47c568a55 100644
--- a/hw/virtio/vhost-user-base.c
+++ b/hw/virtio/vhost-user-base.c
@@ -268,7 +268,9 @@ static void vub_device_realize(DeviceState *dev, Error 
**errp)
 {
 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
 VHostUserBase *vub = VHOST_USER_BASE(dev);
-int ret;
+uint64_t memory_sizes[8];
+void *cache_ptr;
+int i, ret, nregions;
 
 if (!vub->chardev.chr) {
 error_setg(errp, "vhost-user-base: missing chardev");
@@ -311,7 +313,7 @@ static void vub_device_realize(DeviceState *dev, Error 
**errp)
 
 /* Allocate queues */
 vub->vqs = g_ptr_array_sized_new(vub->num_vqs);
-for (int i = 0; i < vub->num_vqs; i++) {
+for (i = 0; i < vub->num_vqs; i++) {
 g_ptr_array_add(vub->vqs,
 virtio_add_queue(vdev, vub->vq_size,
  vub_handle_output));
@@ -328,6 +330,39 @@ static void vub_device_realize(DeviceState *dev, Error 
**errp)
 do_vhost_user_cleanup(vdev, vub);
 }
 
+ret = vub->vhost_dev.vhost_ops->vhost_get_shmem_config(>vhost_dev,
+   ,
+   memory_sizes,
+   errp);
+
+if (ret < 0) {
+do_vhost_user_cleanup(vdev, vub);
+}
+
+for (i = 0; i < nregions; i++) {
+if (memory_sizes[i]) {
+if (!is_power_of_2(memory_sizes[i]) ||
+memory_sizes[i] < qemu_real_host_page_size()) {
+error_setg(errp, "Shared memory %d size must be a power of 2 "
+ "no smaller than the page size", i);
+return;
+}
+
+cache_ptr = mmap(NULL, memory_sizes[i], PROT_READ,
+MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+if (cache_ptr == MAP_FAILED) {
+error_setg(errp, "Unable to mmap blank cache: %s",
+   strerror(errno));
+return;
+}
+
+virtio_new_shmem_region(vdev);
+memory_region_init_ram_ptr(>shmem_list[i],
+OBJECT(vdev), "vub-shm-" + i,
+memory_sizes[i], cache_ptr);
+}
+}
+
 qemu_chr_fe_set_handlers(>chardev, NULL, NULL, vub_event, NULL,
  dev, NULL, true);
 }
diff --git a/hw/virtio/vhost-user-device-pci.c 
b/hw/virtio/vhost-user-device-pci.c
index efaf55d3dd..314bacfb7a 100644
--- a/hw/virtio/vhost-user-device-pci.c
+++ b/hw/virtio/vhost-user-device-pci.c
@@ -8,14 +8,18 @@
  */
 
 #include "qemu/osdep.h"
+#include "qapi/error.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/vhost-user-base.h"
 #include "hw/virtio/virtio-pci.h"
 
+#define VIRTIO_DEVICE_PCI_CACHE_BAR 2
+
 struct VHostUserDevicePCI {
 VirtIOPCIProxy parent_obj;
 
 VHostUserBase vub;
+MemoryRegion cachebar;
 };
 
 #define TYPE_VHOST_USER_DEVICE_PCI "vhost-user-device-pci-base"
@@ -25,10 +29,37 @@ OBJECT_DECLARE_SIMPLE_TYPE(VHostUserDevicePCI, 
VHOST_USER_DEVICE_PCI)
 static void vhost_user_device_pci_realize(VirtIOPCIProxy *vpci_dev, Error 
**errp)
 {
 VHostUserDevicePCI *dev = VHOST_USER_DEVICE_PCI(vpci_dev);
-DeviceState *vdev = DEVICE(>vub);
-
+DeviceState *dev_state = DEVICE(>vub);
+VirtIODevice *vdev = VIRTIO_DEVICE(dev_state);
+uint64_t offset = 0, cache_size = 0;
+int i;
+
 vpci_dev->nvectors = 1;
-qdev_realize(vdev, BUS(_dev->bus), errp);
+qdev_realize(dev_state, BUS(_dev->bus), errp);
+
+for (i = 0; i < vdev->n_shmem_regions; i++) {
+if (vdev->shmem_list[i].size > UINT64_MAX - cache_size) {
+error_setg(errp, "Total shared memory required overflow");
+return;
+}
+cache_size = cache_size + vdev->shmem_list[i].size;
+}
+if (cache_size) {
+memory_region_init(>cachebar, OBJECT(vpci_dev),
+   "vhost-device-pci-cachebar", cache_size);
+  

[RFC PATCH v2 1/5] vhost-user: Add VIRTIO Shared Memory map request

2024-06-28 Thread Albert Esteve
Add SHMEM_MAP/UNMAP requests to vhost-user to
handle VIRTIO Shared Memory mappings.

This request allows backends to dynamically map
fds into a VIRTIO Shared Memory Region indentified
by its `shmid`. Then, the fd memory is advertised
to the driver as a base addres + offset, so it
can be read/written (depending on the mmap flags
requested) while its valid.

The backend can munmap the memory range
in a given VIRTIO Shared Memory Region (again,
identified by its `shmid`), to free it. Upon
receiving this message, the front-end must
mmap the regions with PROT_NONE to reserve
the virtual memory space.

The device model needs to create MemoryRegion
instances for the VIRTIO Shared Memory Regions
and add them to the `VirtIODevice` instance.

Signed-off-by: Albert Esteve 
---
 docs/interop/vhost-user.rst   |  27 +
 hw/virtio/vhost-user.c| 122 ++
 hw/virtio/virtio.c|  12 +++
 include/hw/virtio/virtio.h|   5 +
 subprojects/libvhost-user/libvhost-user.c |  65 
 subprojects/libvhost-user/libvhost-user.h |  53 ++
 6 files changed, 284 insertions(+)

diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index d8419fd2f1..d52ba719d5 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -1859,6 +1859,33 @@ is sent by the front-end.
   when the operation is successful, or non-zero otherwise. Note that if the
   operation fails, no fd is sent to the backend.
 
+``VHOST_USER_BACKEND_SHMEM_MAP``
+  :id: 9
+  :equivalent ioctl: N/A
+  :request payload: fd and ``struct VhostUserMMap``
+  :reply payload: N/A
+
+  This message can be submitted by the backends to advertise a new mapping
+  to be made in a given VIRTIO Shared Memory Region. Upon receiving the 
message,
+  The front-end will mmap the given fd into the VIRTIO Shared Memory Region
+  with the requested ``shmid``. A reply is generated indicating whether mapping
+  succeeded.
+
+  Mapping over an already existing map is not allowed and request shall fail.
+  Therefore, the memory range in the request must correspond with a valid,
+  free region of the VIRTIO Shared Memory Region.
+
+``VHOST_USER_BACKEND_SHMEM_UNMAP``
+  :id: 10
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserMMap``
+  :reply payload: N/A
+
+  This message can be submitted by the backends so that the front-end un-mmap
+  a given range (``offset``, ``len``) in the VIRTIO Shared Memory Region with
+  the requested ``shmid``.
+  A reply is generated indicating whether unmapping succeeded.
+
 .. _reply_ack:
 
 VHOST_USER_PROTOCOL_F_REPLY_ACK
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index cdf9af4a4b..7ee8a472c6 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -115,6 +115,8 @@ typedef enum VhostUserBackendRequest {
 VHOST_USER_BACKEND_SHARED_OBJECT_ADD = 6,
 VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE = 7,
 VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP = 8,
+VHOST_USER_BACKEND_SHMEM_MAP = 9,
+VHOST_USER_BACKEND_SHMEM_UNMAP = 10,
 VHOST_USER_BACKEND_MAX
 }  VhostUserBackendRequest;
 
@@ -192,6 +194,24 @@ typedef struct VhostUserShared {
 unsigned char uuid[16];
 } VhostUserShared;
 
+/* For the flags field of VhostUserMMap */
+#define VHOST_USER_FLAG_MAP_R (1u << 0)
+#define VHOST_USER_FLAG_MAP_W (1u << 1)
+
+typedef struct {
+/* VIRTIO Shared Memory Region ID */
+uint8_t shmid;
+uint8_t padding[7];
+/* File offset */
+uint64_t fd_offset;
+/* Offset within the VIRTIO Shared Memory Region */
+uint64_t shm_offset;
+/* Size of the mapping */
+uint64_t len;
+/* Flags for the mmap operation, from VHOST_USER_FLAG_* */
+uint64_t flags;
+} VhostUserMMap;
+
 typedef struct {
 VhostUserRequest request;
 
@@ -224,6 +244,7 @@ typedef union {
 VhostUserInflight inflight;
 VhostUserShared object;
 VhostUserTransferDeviceState transfer_state;
+VhostUserMMap mmap;
 } VhostUserPayload;
 
 typedef struct VhostUserMsg {
@@ -1748,6 +1769,100 @@ vhost_user_backend_handle_shared_object_lookup(struct 
vhost_user *u,
 return 0;
 }
 
+static int
+vhost_user_backend_handle_shmem_map(struct vhost_dev *dev,
+VhostUserMMap *vu_mmap,
+int fd)
+{
+void *addr = 0;
+MemoryRegion *mr = NULL;
+
+if (fd < 0) {
+error_report("Bad fd for map");
+return -EBADF;
+}
+
+if (!dev->vdev->shmem_list ||
+dev->vdev->n_shmem_regions <= vu_mmap->shmid) {
+error_report("Device only has %d VIRTIO Shared Memory Regions. "
+ "Requested ID: %d",
+ dev->vdev->n_shmem_regions, vu_mmap->shmid);
+return -EFAULT;
+}
+
+mr = >vdev->shmem_list[vu_mmap->shmid];
+
+if (!mr) {
+error_report(&qu

Re: [RFC PATCH 1/1] vhost-user: add shmem mmap request

2024-06-26 Thread Albert Esteve
Hi Stefan,

On Wed, Jun 5, 2024 at 4:28 PM Stefan Hajnoczi  wrote:

> On Wed, Jun 05, 2024 at 10:13:32AM +0200, Albert Esteve wrote:
> > On Tue, Jun 4, 2024 at 8:54 PM Stefan Hajnoczi 
> wrote:
> >
> > > On Thu, May 30, 2024 at 05:22:23PM +0200, Albert Esteve wrote:
> > > > Add SHMEM_MAP/UNMAP requests to vhost-user.
> > > >
> > > > This request allows backends to dynamically map
> > > > fds into a shared memory region indentified by
> > >
> > > Please call this "VIRTIO Shared Memory Region" everywhere (code,
> > > vhost-user spec, commit description, etc) so it's clear that this is
> not
> > > about vhost-user shared memory tables/regions.
> > >
> > > > its `shmid`. Then, the fd memory is advertised
> > > > to the frontend through a BAR+offset, so it can
> > > > be read by the driver while its valid.
> > >
> > > Why is a PCI BAR mentioned here? vhost-user does not know about the
> > > VIRTIO Transport (e.g. PCI) being used. It's the frontend's job to
> > > report VIRTIO Shared Memory Regions to the driver.
> > >
> > >
> > I will remove PCI BAR, as it is true that it depends on the
> > transport. I was trying to explain that the driver
> > will use the shm_base + shm_offset to access
> > the mapped memory.
> >
> >
> > > >
> > > > Then, the backend can munmap the memory range
> > > > in a given shared memory region (again, identified
> > > > by its `shmid`), to free it. After this, the
> > > > region becomes private and shall not be accessed
> > > > by the frontend anymore.
> > >
> > > What does "private" mean?
> > >
> > > The frontend must mmap PROT_NONE to reserve the virtual memory space
> > > when no fd is mapped in the VIRTIO Shared Memory Region. Otherwise an
> > > unrelated mmap(NULL, ...) might use that address range and the guest
> > > would have access to the host memory! This is a security issue and
> needs
> > > to be mentioned explicitly in the spec.
> > >
> >
> > I mentioned private because it changes the mapping from MAP_SHARED
> > to MAP_PRIVATE. I will highlight PROT_NONE instead.
>
> I see. Then "MAP_PRIVATE" would be clearer. I wasn't sure whether you
> mean mmap flags or something like the memory range is no longer
> accessible to the driver.
>
> >
> >
> > >
> > > >
> > > > Initializing the memory region is reponsiblity
> > > > of the PCI device that will using it.
> > >
> > > What does this mean?
> > >
> >
> > The MemoryRegion is declared in `struct VirtIODevice`,
> > but it is uninitialized in this commit. So I was trying to say
> > that the initialization will happen in, e.g., vhost-user-gpu-pci.c
> > with something like `memory_region_init` , and later `pci_register_bar`.
>
> Okay. The device model needs to create MemoryRegion instances for the
> device's Shared Memory Regions and add them to the VirtIODevice.
>
> --device vhost-user-device will need to query the backend since, unlike
> vhost-user-gpu-pci and friends, it doesn't have knowledge of specific
> device types. It will need to create MemoryRegions enumerated from the
> backend.
>
> By the way, the VIRTIO MMIO Transport also supports VIRTIO Shared Memory
> Regions so this work should not be tied to PCI.
>
> >
> > I am testing that part still.
> >
> >
> > >
> > > >
> > > > Signed-off-by: Albert Esteve 
> > > > ---
> > > >  docs/interop/vhost-user.rst |  23 
> > > >  hw/virtio/vhost-user.c  | 106
> 
> > > >  hw/virtio/virtio.c  |   2 +
> > > >  include/hw/virtio/virtio.h  |   3 +
> > > >  4 files changed, 134 insertions(+)
> > >
> > > Two missing pieces:
> > >
> > > 1. QEMU's --device vhost-user-device needs a way to enumerate VIRTIO
> > > Shared Memory Regions from the vhost-user backend. vhost-user-device is
> > > a generic vhost-user frontend without knowledge of the device type, so
> > > it doesn't know what the valid shmids are and what size the regions
> > > have.
> > >
> >
> > Ok. I was assuming that if a device (backend) makes a request without a
> > valid shmid or not enough size in the region to perform the mmap, would
> > just fail in the VMM performing the actual mmap operation. So it would
> > not neces

Re: [RFC PATCH 0/1] vhost-user: Add SHMEM_MAP/UNMAP requests

2024-06-05 Thread Albert Esteve
On Wed, Jun 5, 2024 at 1:16 PM Stefan Hajnoczi  wrote:

> On Wed, Jun 05, 2024 at 09:24:36AM +0200, Albert Esteve wrote:
> > On Tue, Jun 4, 2024 at 8:16 PM Stefan Hajnoczi 
> wrote:
> >
> > > On Thu, May 30, 2024 at 05:22:22PM +0200, Albert Esteve wrote:
> > > > Hi all,
> > > >
> > > > This is an early attempt to have backends
> > > > support dynamic fd mapping into shared
> > > > memory regions. As such, there are a few
> > > > things that need settling, so I wanted to
> > > > post this first to have some early feedback.
> > > >
> > > > The usecase for this is, e.g., to support
> > > > vhost-user-gpu RESOURCE_BLOB operations,
> > > > or DAX Window request for virtio-fs. In
> > > > general, any operation where a backend
> > > > would need to mmap an fd to a shared
> > > > memory so that the guest can access it.
> > >
> > > I wanted to mention that this sentence confuses me because:
> > >
> > > - The frontend will mmap an fd into the guest's memory space so that a
> > >   VIRTIO Shared Memory Region is exposed to the guest. The backend
> > >   requests the frontend to perform this operation. The backend does not
> > >   invoke mmap itself.
> > >
> >
> > Sorry for the confused wording. It is true that the backend does not
> > do the mmap, but requests it to be done. One point of confusion for
> > me from your sentence is that I refer to the driver as the frontend,
>
> They are different concepts. Frontend is defined in the vhost-user spec
> and driver is defined in the VIRTIO spec.
>

Ah! I see. Then you may probably want to ignore some of my responses to
other mail of this series :P

Thanks for the clarification.


>
> The frontend is the application that uses vhost-user protocol messages
> to communicate with the backend.
>
> The driver uses VIRTIO device model interfaces like virtqueues to
> communicate with the device.
>
> > and the mapping is done by the VMM (i.e., QEMU).
> >
> > But yeah, I agree and the scenario you describe is what
> > I had in mind. Thanks for pointing it out. I will rephrase it
> > in follow-up patches.
>
> Thanks!
>
> >
> >
> > >
> > > - "Shared memory" is ambiguous. Please call it VIRTIO Shared Memory
> > >   Region to differentiate from vhost-user shared memory tables/regions.
> > >
> >
> > Ok!
> >
> >
> > >
> > > > The request will be processed by the VMM,
> > > > that will, in turn, trigger a mmap with
> > > > the instructed parameters (i.e., shmid,
> > > > shm_offset, fd_offset, fd, lenght).
> > > >
> > > > As there are already a couple devices
> > > > that could benefit of such a feature,
> > > > and more could require it in the future,
> > > > my intention was to make it generic.
> > > >
> > > > To that end, I declared the shared
> > > > memory region list in `VirtIODevice`.
> > > > I could add a couple commodity
> > > > functions to add new regions to the list,
> > > > so that the devices can use them. But
> > > > I wanted to gather some feedback before
> > > > refining it further, as I am probably
> > > > missing some required steps/or security
> > > > concerns that I am not taking into account.
> > > >
> > > > Albert Esteve (1):
> > > >   vhost-user: add shmem mmap request
> > > >
> > > >  docs/interop/vhost-user.rst |  23 
> > > >  hw/virtio/vhost-user.c  | 106
> 
> > > >  hw/virtio/virtio.c  |   2 +
> > > >  include/hw/virtio/virtio.h  |   3 +
> > > >  4 files changed, 134 insertions(+)
> > > >
> > > > --
> > > > 2.44.0
> > > >
> > >
>


Re: [RFC PATCH 1/1] vhost-user: add shmem mmap request

2024-06-05 Thread Albert Esteve
On Tue, Jun 4, 2024 at 8:54 PM Stefan Hajnoczi  wrote:

> On Thu, May 30, 2024 at 05:22:23PM +0200, Albert Esteve wrote:
> > Add SHMEM_MAP/UNMAP requests to vhost-user.
> >
> > This request allows backends to dynamically map
> > fds into a shared memory region indentified by
>
> Please call this "VIRTIO Shared Memory Region" everywhere (code,
> vhost-user spec, commit description, etc) so it's clear that this is not
> about vhost-user shared memory tables/regions.
>
> > its `shmid`. Then, the fd memory is advertised
> > to the frontend through a BAR+offset, so it can
> > be read by the driver while its valid.
>
> Why is a PCI BAR mentioned here? vhost-user does not know about the
> VIRTIO Transport (e.g. PCI) being used. It's the frontend's job to
> report VIRTIO Shared Memory Regions to the driver.
>
>
I will remove PCI BAR, as it is true that it depends on the
transport. I was trying to explain that the driver
will use the shm_base + shm_offset to access
the mapped memory.


> >
> > Then, the backend can munmap the memory range
> > in a given shared memory region (again, identified
> > by its `shmid`), to free it. After this, the
> > region becomes private and shall not be accessed
> > by the frontend anymore.
>
> What does "private" mean?
>
> The frontend must mmap PROT_NONE to reserve the virtual memory space
> when no fd is mapped in the VIRTIO Shared Memory Region. Otherwise an
> unrelated mmap(NULL, ...) might use that address range and the guest
> would have access to the host memory! This is a security issue and needs
> to be mentioned explicitly in the spec.
>

I mentioned private because it changes the mapping from MAP_SHARED
to MAP_PRIVATE. I will highlight PROT_NONE instead.


>
> >
> > Initializing the memory region is reponsiblity
> > of the PCI device that will using it.
>
> What does this mean?
>

The MemoryRegion is declared in `struct VirtIODevice`,
but it is uninitialized in this commit. So I was trying to say
that the initialization will happen in, e.g., vhost-user-gpu-pci.c
with something like `memory_region_init` , and later `pci_register_bar`.

I am testing that part still.


>
> >
> > Signed-off-by: Albert Esteve 
> > ---
> >  docs/interop/vhost-user.rst |  23 
> >  hw/virtio/vhost-user.c  | 106 
> >  hw/virtio/virtio.c  |   2 +
> >  include/hw/virtio/virtio.h  |   3 +
> >  4 files changed, 134 insertions(+)
>
> Two missing pieces:
>
> 1. QEMU's --device vhost-user-device needs a way to enumerate VIRTIO
> Shared Memory Regions from the vhost-user backend. vhost-user-device is
> a generic vhost-user frontend without knowledge of the device type, so
> it doesn't know what the valid shmids are and what size the regions
> have.
>

Ok. I was assuming that if a device (backend) makes a request without a
valid shmid or not enough size in the region to perform the mmap, would
just fail in the VMM performing the actual mmap operation. So it would
not necessarily need to know about valid shmids or region sizes.


>
> 2. Other backends don't see these mappings. If the guest submits a vring
> descriptor referencing a mapping to another backend, then that backend
> won't be able to access this memory. David Gilbert hit this problem when
> working on the virtiofs DAX Window. Either the frontend needs to forward
> all SHMAP_MAP/UNMAP messages to the other backends (inefficient and
> maybe racy!) or a new "memcpy" message is needed as a fallback for when
> vhost-user memory region translation fails.
>

Ok. In which scenario would another device want to access the same mapping?
If it is for a shared VIRTIO object, the device that receives the dmabuf fd
could
just do a new mapping in its VIRTIO shared memory region.


>
> >
> > diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
> > index d8419fd2f1..3caf2a290c 100644
> > --- a/docs/interop/vhost-user.rst
> > +++ b/docs/interop/vhost-user.rst
> > @@ -1859,6 +1859,29 @@ is sent by the front-end.
> >when the operation is successful, or non-zero otherwise. Note that if
> the
> >operation fails, no fd is sent to the backend.
> >
> > +``VHOST_USER_BACKEND_SHMEM_MAP``
> > +  :id: 9
> > +  :equivalent ioctl: N/A
> > +  :request payload: fd and ``struct VhostUserMMap``
> > +  :reply payload: N/A
> > +
> > +  This message can be submitted by the backends to advertise a new
> mapping
> > +  to be made in a given shared memory region. Upon receiving the
> message,
> > +  QEMU will mmap the given fd into the shared memory region with the
>
> s/QEMU/

Re: [RFC PATCH 0/1] vhost-user: Add SHMEM_MAP/UNMAP requests

2024-06-05 Thread Albert Esteve
On Tue, Jun 4, 2024 at 8:16 PM Stefan Hajnoczi  wrote:

> On Thu, May 30, 2024 at 05:22:22PM +0200, Albert Esteve wrote:
> > Hi all,
> >
> > This is an early attempt to have backends
> > support dynamic fd mapping into shared
> > memory regions. As such, there are a few
> > things that need settling, so I wanted to
> > post this first to have some early feedback.
> >
> > The usecase for this is, e.g., to support
> > vhost-user-gpu RESOURCE_BLOB operations,
> > or DAX Window request for virtio-fs. In
> > general, any operation where a backend
> > would need to mmap an fd to a shared
> > memory so that the guest can access it.
>
> I wanted to mention that this sentence confuses me because:
>
> - The frontend will mmap an fd into the guest's memory space so that a
>   VIRTIO Shared Memory Region is exposed to the guest. The backend
>   requests the frontend to perform this operation. The backend does not
>   invoke mmap itself.
>

Sorry for the confused wording. It is true that the backend does not
do the mmap, but requests it to be done. One point of confusion for
me from your sentence is that I refer to the driver as the frontend,
and the mapping is done by the VMM (i.e., QEMU).

But yeah, I agree and the scenario you describe is what
I had in mind. Thanks for pointing it out. I will rephrase it
in follow-up patches.


>
> - "Shared memory" is ambiguous. Please call it VIRTIO Shared Memory
>   Region to differentiate from vhost-user shared memory tables/regions.
>

Ok!


>
> > The request will be processed by the VMM,
> > that will, in turn, trigger a mmap with
> > the instructed parameters (i.e., shmid,
> > shm_offset, fd_offset, fd, lenght).
> >
> > As there are already a couple devices
> > that could benefit of such a feature,
> > and more could require it in the future,
> > my intention was to make it generic.
> >
> > To that end, I declared the shared
> > memory region list in `VirtIODevice`.
> > I could add a couple commodity
> > functions to add new regions to the list,
> > so that the devices can use them. But
> > I wanted to gather some feedback before
> > refining it further, as I am probably
> > missing some required steps/or security
> > concerns that I am not taking into account.
> >
> > Albert Esteve (1):
> >   vhost-user: add shmem mmap request
> >
> >  docs/interop/vhost-user.rst |  23 
> >  hw/virtio/vhost-user.c  | 106 
> >  hw/virtio/virtio.c  |   2 +
> >  include/hw/virtio/virtio.h  |   3 +
> >  4 files changed, 134 insertions(+)
> >
> > --
> > 2.44.0
> >
>


[RFC PATCH 0/1] vhost-user: Add SHMEM_MAP/UNMAP requests

2024-05-30 Thread Albert Esteve
Hi all,

This is an early attempt to have backends
support dynamic fd mapping into shared
memory regions. As such, there are a few
things that need settling, so I wanted to
post this first to have some early feedback.

The usecase for this is, e.g., to support
vhost-user-gpu RESOURCE_BLOB operations,
or DAX Window request for virtio-fs. In
general, any operation where a backend
would need to mmap an fd to a shared
memory so that the guest can access it.
The request will be processed by the VMM,
that will, in turn, trigger a mmap with
the instructed parameters (i.e., shmid,
shm_offset, fd_offset, fd, lenght).

As there are already a couple devices
that could benefit of such a feature,
and more could require it in the future,
my intention was to make it generic.

To that end, I declared the shared
memory region list in `VirtIODevice`.
I could add a couple commodity
functions to add new regions to the list,
so that the devices can use them. But
I wanted to gather some feedback before
refining it further, as I am probably
missing some required steps/or security
concerns that I am not taking into account.

Albert Esteve (1):
  vhost-user: add shmem mmap request

 docs/interop/vhost-user.rst |  23 
 hw/virtio/vhost-user.c  | 106 
 hw/virtio/virtio.c  |   2 +
 include/hw/virtio/virtio.h  |   3 +
 4 files changed, 134 insertions(+)

-- 
2.44.0




[RFC PATCH 1/1] vhost-user: add shmem mmap request

2024-05-30 Thread Albert Esteve
Add SHMEM_MAP/UNMAP requests to vhost-user.

This request allows backends to dynamically map
fds into a shared memory region indentified by
its `shmid`. Then, the fd memory is advertised
to the frontend through a BAR+offset, so it can
be read by the driver while its valid.

Then, the backend can munmap the memory range
in a given shared memory region (again, identified
by its `shmid`), to free it. After this, the
region becomes private and shall not be accessed
by the frontend anymore.

Initializing the memory region is reponsiblity
of the PCI device that will using it.

Signed-off-by: Albert Esteve 
---
 docs/interop/vhost-user.rst |  23 
 hw/virtio/vhost-user.c  | 106 
 hw/virtio/virtio.c  |   2 +
 include/hw/virtio/virtio.h  |   3 +
 4 files changed, 134 insertions(+)

diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index d8419fd2f1..3caf2a290c 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -1859,6 +1859,29 @@ is sent by the front-end.
   when the operation is successful, or non-zero otherwise. Note that if the
   operation fails, no fd is sent to the backend.
 
+``VHOST_USER_BACKEND_SHMEM_MAP``
+  :id: 9
+  :equivalent ioctl: N/A
+  :request payload: fd and ``struct VhostUserMMap``
+  :reply payload: N/A
+
+  This message can be submitted by the backends to advertise a new mapping
+  to be made in a given shared memory region. Upon receiving the message,
+  QEMU will mmap the given fd into the shared memory region with the
+  requested ``shmid``. A reply is generated indicating whether mapping
+  succeeded.
+
+``VHOST_USER_BACKEND_SHMEM_UNMAP``
+  :id: 10
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserMMap``
+  :reply payload: N/A
+
+  This message can be submitted by the backends so that QEMU un-mmap
+  a given range (``offset``, ``len``) in the shared memory region with the
+  requested ``shmid``.
+  A reply is generated indicating whether unmapping succeeded.
+
 .. _reply_ack:
 
 VHOST_USER_PROTOCOL_F_REPLY_ACK
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index cdf9af4a4b..9526b9d07f 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -115,6 +115,8 @@ typedef enum VhostUserBackendRequest {
 VHOST_USER_BACKEND_SHARED_OBJECT_ADD = 6,
 VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE = 7,
 VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP = 8,
+VHOST_USER_BACKEND_SHMEM_MAP = 9,
+VHOST_USER_BACKEND_SHMEM_UNMAP = 10,
 VHOST_USER_BACKEND_MAX
 }  VhostUserBackendRequest;
 
@@ -192,6 +194,23 @@ typedef struct VhostUserShared {
 unsigned char uuid[16];
 } VhostUserShared;
 
+/* For the flags field of VhostUserMMap */
+#define VHOST_USER_FLAG_MAP_R (1u << 0)
+#define VHOST_USER_FLAG_MAP_W (1u << 1)
+
+typedef struct {
+/* Shared memory region ID */
+uint8_t shmid;
+/* File offset */
+uint64_t fd_offset;
+/* Offset within the shared memory region */
+uint64_t shm_offset;
+/* Size of region to map */
+uint64_t len;
+/* Flags for the mmap operation, from VHOST_USER_FLAG_* */
+uint64_t flags;
+} VhostUserMMap;
+
 typedef struct {
 VhostUserRequest request;
 
@@ -224,6 +243,7 @@ typedef union {
 VhostUserInflight inflight;
 VhostUserShared object;
 VhostUserTransferDeviceState transfer_state;
+VhostUserMMap mmap;
 } VhostUserPayload;
 
 typedef struct VhostUserMsg {
@@ -1748,6 +1768,85 @@ vhost_user_backend_handle_shared_object_lookup(struct 
vhost_user *u,
 return 0;
 }
 
+static int
+vhost_user_backend_handle_shmem_map(struct vhost_dev *dev,
+  VhostUserMMap *vu_mmap,
+  int fd)
+{
+void *addr = 0;
+MemoryRegion *mr = NULL;
+
+if (fd < 0) {
+error_report("Bad fd for map");
+return -EBADF;
+}
+
+if (!dev->vdev->shmem_list ||
+dev->vdev->n_shmem_regions <= vu_mmap->shmid) {
+error_report("Shared memory region at "
+ "ID %d unitialized", vu_mmap->shmid);
+return -EFAULT;
+}
+
+mr = >vdev->shmem_list[vu_mmap->shmid];
+
+if ((vu_mmap->shm_offset + vu_mmap->len) < vu_mmap->len ||
+(vu_mmap->shm_offset + vu_mmap->len) > mr->size) {
+error_report("Bad offset/len for mmap %" PRIx64 "+%" PRIx64,
+ vu_mmap->shm_offset, vu_mmap->len);
+return -EFAULT;
+}
+
+void *shmem_ptr = memory_region_get_ram_ptr(mr);
+
+addr = mmap(shmem_ptr + vu_mmap->shm_offset, vu_mmap->len,
+((vu_mmap->flags & VHOST_USER_FLAG_MAP_R) ? PROT_READ : 0) |
+((vu_mmap->flags & VHOST_USER_FLAG_MAP_W) ? PROT_WRITE : 0),
+MAP_SHARED | MAP_FIXED, fd, vu_mmap->fd_offset);
+if (addr == MAP_FAILED) {
+error_report(&quo

Re: [PATCH v4 0/5] Virtio dmabuf improvements

2024-03-13 Thread Albert Esteve
On Tue, Mar 12, 2024 at 7:23 PM Michael S. Tsirkin  wrote:

> On Mon, Feb 19, 2024 at 03:34:18PM +0100, Albert Esteve wrote:
> > v1: https://www.mail-archive.com/qemu-devel@nongnu.org/msg1005257.html
> > v2: https://www.mail-archive.com/qemu-devel@nongnu.org/msg1014615.html
> > v3: Virtio dmabuf improvements
> > v3 -> v4
> >   - Changed GMutex by QemuMutex in virtio-dmabuf
> >   - Made the value at VirtioSharedObject an union
> > to make naming more clear
> >   - Added some documentation
>
> Dropped everything except patch 1 for now.
>

Got it. Thanks!


>
> > Various improvements for the virtio-dmabuf module.
> > This patch includes:
> >
> > - Check for ownership before allowing a vhost device
> >   to remove an object from the table.
> > - Properly cleanup shared resources if a vhost device
> >   object gets cleaned up.
> > - Rename virtio dmabuf functions to `virtio_dmabuf_*`
> >
> > Albert Esteve (5):
> >   hw/virtio: check owner for removing objects
> >   hw/virtio: document SharedObject structures
> >   hw/virtio: change dmabuf mutex to QemuMutex
> >   hw/virtio: cleanup shared resources
> >   hw/virtio: rename virtio dmabuf API
> >
> >  docs/interop/vhost-user.rst   |  4 +-
> >  hw/display/virtio-dmabuf.c| 98 +++
> >  hw/virtio/vhost-user.c| 31 +++---
> >  hw/virtio/vhost.c |  3 +
> >  hw/virtio/virtio.c|  3 +
> >  include/hw/virtio/virtio-dmabuf.h | 73 +--
> >  tests/unit/test-virtio-dmabuf.c   | 82 +++---
> >  7 files changed, 211 insertions(+), 83 deletions(-)
> >
> > --
> > 2.43.1
>
>


Re: [PATCH v4 3/5] hw/virtio: change dmabuf mutex to QemuMutex

2024-03-11 Thread Albert Esteve
On Tue, Feb 20, 2024 at 11:39 AM Manos Pitsidianakis <
manos.pitsidiana...@linaro.org> wrote:

> Hello Albert,
>
> This is a point of confusion for me; Volker recently pointed out in a
> patch for virtio-snd that all its code runs under the BQL.


Hello Manos,

I updated it to QemuMutex after a suggestion from Alex Benee, but I was not
really aware it existed before his comment. So for your question I had to
check what
exactly BQL stands for in this context (big QEMU lock). Therefore, as you
can see,
I am probably not the right person to answer it.


> Is this code
> ever called without BQL, for example do the backend read/write functions
> from vhost-user.c run without the BQL?
>

To my understanding, they should as every access to the shared table may
incur
in a race. But I'd need to read the code better to verify if that is
indeed the case.

The only thing I can say is that, if this change is confusing or may lead
to issues
related to the scope of the lock, it may be better to dismiss the change and
split it to its own specific patch, so I have the chance to verify the
chance in
a better way without delaying the other commits here.


>
> On Mon, 19 Feb 2024 16:34, Albert Esteve  wrote:
> >Change GMutex by QemuMutex to be able to use
> >lock contexts with `WITH_QEMU_LOCK_GUARD`.
> >
> >As the lock needs to be initialised and there
> >is no central point for initialisation, add
> >an init public function and call it from
> >virtio.c, each time a new backend structure
> >is initialised.
> >
> >Signed-off-by: Albert Esteve 
> >---
> > hw/display/virtio-dmabuf.c| 55 +--
> > hw/virtio/virtio.c|  3 ++
> > include/hw/virtio/virtio-dmabuf.h |  5 +++
> > tests/unit/test-virtio-dmabuf.c   |  5 +++
> > 4 files changed, 43 insertions(+), 25 deletions(-)
> >
> >diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
> >index 497cb6fa7c..961094a561 100644
> >--- a/hw/display/virtio-dmabuf.c
> >+++ b/hw/display/virtio-dmabuf.c
> >@@ -11,11 +11,12 @@
> >  */
> >
> > #include "qemu/osdep.h"
> >+#include "include/qemu/lockable.h"
> >
> > #include "hw/virtio/virtio-dmabuf.h"
> >
> >
> >-static GMutex lock;
> >+static QemuMutex lock;
> > static GHashTable *resource_uuids;
> >
> > /*
> >@@ -27,23 +28,27 @@ static int uuid_equal_func(const void *lhv, const
> void *rhv)
> > return qemu_uuid_is_equal(lhv, rhv);
> > }
> >
> >+void virtio_dmabuf_init(void) {
> >+qemu_mutex_init();
> >+}
> >+
> > static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject
> *value)
> > {
> > bool result = true;
> >
> >-g_mutex_lock();
> >-if (resource_uuids == NULL) {
> >-resource_uuids = g_hash_table_new_full(qemu_uuid_hash,
> >-   uuid_equal_func,
> >-   NULL,
> >-   g_free);
> >-}
> >-if (g_hash_table_lookup(resource_uuids, uuid) == NULL) {
> >-g_hash_table_insert(resource_uuids, uuid, value);
> >-} else {
> >-result = false;
> >+WITH_QEMU_LOCK_GUARD() {
> >+if (resource_uuids == NULL) {
> >+resource_uuids = g_hash_table_new_full(qemu_uuid_hash,
> >+uuid_equal_func,
> >+NULL,
> >+g_free);
> >+}
> >+if (g_hash_table_lookup(resource_uuids, uuid) == NULL) {
> >+g_hash_table_insert(resource_uuids, uuid, value);
> >+} else {
> >+result = false;
> >+}
> > }
> >-g_mutex_unlock();
> >
> > return result;
> > }
> >@@ -87,9 +92,9 @@ bool virtio_add_vhost_device(QemuUUID *uuid, struct
> vhost_dev *dev)
> > bool virtio_remove_resource(const QemuUUID *uuid)
> > {
> > bool result;
> >-g_mutex_lock();
> >-result = g_hash_table_remove(resource_uuids, uuid);
> >-g_mutex_unlock();
> >+WITH_QEMU_LOCK_GUARD() {
> >+result = g_hash_table_remove(resource_uuids, uuid);
> >+}
> >
> > return result;
> > }
> >@@ -98,11 +103,11 @@ static VirtioSharedObject *get_shared_object(const
> QemuUUID *uuid)
> > {
> > gpointer lookup_res = NULL;
> >
> >-g_mutex_lock();
> >-if (resource_uuids != NULL) {
> >-   

Re: [PATCH v4 2/5] hw/virtio: document SharedObject structures

2024-03-06 Thread Albert Esteve
On Tue, Feb 20, 2024 at 11:34 AM Manos Pitsidianakis <
manos.pitsidiana...@linaro.org> wrote:

> On Mon, 19 Feb 2024 16:34, Albert Esteve  wrote:
> >Change VirtioSharedObject value type from
> >a generic pointer to a union storing the different
> >supported underlying types, which makes naming
> >less confusing.
> >
> >With the update, use the chance to add kdoc
> >to both the SharedObjectType enum and
> >VirtioSharedObject struct.
> >
> >Signed-off-by: Albert Esteve 
> >---
> > hw/display/virtio-dmabuf.c|  8 
> > include/hw/virtio/virtio-dmabuf.h | 25 -
> > 2 files changed, 28 insertions(+), 5 deletions(-)
> >
> >diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
> >index 3dba4577ca..497cb6fa7c 100644
> >--- a/hw/display/virtio-dmabuf.c
> >+++ b/hw/display/virtio-dmabuf.c
> >@@ -57,7 +57,7 @@ bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
> > }
> > vso = g_new(VirtioSharedObject, 1);
> > vso->type = TYPE_DMABUF;
> >-vso->value = GINT_TO_POINTER(udmabuf_fd);
> >+vso->value.udma_buf = udmabuf_fd;
> > result = virtio_add_resource(uuid, vso);
> > if (!result) {
> > g_free(vso);
> >@@ -75,7 +75,7 @@ bool virtio_add_vhost_device(QemuUUID *uuid, struct
> vhost_dev *dev)
> > }
> > vso = g_new(VirtioSharedObject, 1);
> > vso->type = TYPE_VHOST_DEV;
> >-vso->value = dev;
> >+vso->value.dev = dev;
> > result = virtio_add_resource(uuid, vso);
> > if (!result) {
> > g_free(vso);
> >@@ -114,7 +114,7 @@ int virtio_lookup_dmabuf(const QemuUUID *uuid)
> > return -1;
> > }
> > assert(vso->type == TYPE_DMABUF);
> >-return GPOINTER_TO_INT(vso->value);
> >+return vso->value.udma_buf;
> > }
> >
> > struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
> >@@ -124,7 +124,7 @@ struct vhost_dev *virtio_lookup_vhost_device(const
> QemuUUID *uuid)
> > return NULL;
> > }
> > assert(vso->type == TYPE_VHOST_DEV);
> >-return (struct vhost_dev *) vso->value;
> >+return (struct vhost_dev *) vso->value.dev;
>
> Is the casting still required?
>
> You're right, probably not anymore. I'll remove it.


>
> > }
> >
> > SharedObjectType virtio_object_type(const QemuUUID *uuid)
> >diff --git a/include/hw/virtio/virtio-dmabuf.h
> b/include/hw/virtio/virtio-dmabuf.h
> >index 627c3b6db7..891a43162d 100644
> >--- a/include/hw/virtio/virtio-dmabuf.h
> >+++ b/include/hw/virtio/virtio-dmabuf.h
> >@@ -16,15 +16,38 @@
> > #include "qemu/uuid.h"
> > #include "vhost.h"
> >
> >+/**
> >+ * SharedObjectType:
> >+ *
> >+ * Identifies the type of the underlying type that the current lookup
> >+ * table entry is holding.
> >+ *
> >+ * TYPE_INVALID: Invalid entry
> >+ * TYPE_DMABUF: Entry is a dmabuf file descriptor that can be directly
> >+ *  shared with the requestor
> >+ * TYPE_VHOST_DEV: Entry is a pointer to a vhost device that is holding
> >+ * the shared object.
>
>
> nit:
>
> + * TYPE_INVALID:   Invalid entry.
> + * TYPE_DMABUF:Entry is a dmabuf file descriptor that can be
> + * directly shared with the requestor.
> + * TYPE_VHOST_DEV: Entry is a pointer to a vhost device that is holding
> + * the shared object.
>
>
> >+ */
> > typedef enum SharedObjectType {
> > TYPE_INVALID = 0,
> > TYPE_DMABUF,
> > TYPE_VHOST_DEV,
> > } SharedObjectType;
> >
> >+/**
> >+ * VirtioSharedObject:
> >+ * @type: Shared object type identifier
> >+ * @value: Union containing to the underlying type
> >+ *
> >+ * The VirtioSharedObject object provides a way to distinguish,
> >+ * store, and handle the different types supported by the lookup table.
> >+ */
> > typedef struct VirtioSharedObject {
> > SharedObjectType type;
> >-gpointer value;
> >+union {
> >+struct vhost_dev *dev;  /* TYPE_VHOST_DEV */
> >+int udma_buf;   /* TYPE_DMABUF */
> >+} value;
> > } VirtioSharedObject;
> >
> > /**
> >--
> >2.43.1
> >
> >
>
>


[PATCH v4 4/5] hw/virtio: cleanup shared resources

2024-02-19 Thread Albert Esteve
Ensure that we cleanup all virtio shared
resources when the vhost devices is cleaned
up (after a hot unplug, or a crash).

To do so, we add a new function to the virtio_dmabuf
API called `virtio_dmabuf_vhost_cleanup`, which
loop through the table and removes all
resources owned by the vhost device parameter.

Also, add a test to verify that the new
function in the API behaves as expected.

Signed-off-by: Albert Esteve 
Acked-by: Stefan Hajnoczi 
---
 hw/display/virtio-dmabuf.c| 21 
 hw/virtio/vhost.c |  3 +++
 include/hw/virtio/virtio-dmabuf.h | 10 ++
 tests/unit/test-virtio-dmabuf.c   | 33 +++
 4 files changed, 67 insertions(+)

diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
index 961094a561..703b5bd979 100644
--- a/hw/display/virtio-dmabuf.c
+++ b/hw/display/virtio-dmabuf.c
@@ -141,6 +141,27 @@ SharedObjectType virtio_object_type(const QemuUUID *uuid)
 return vso->type;
 }
 
+static bool virtio_dmabuf_resource_is_owned(gpointer key,
+gpointer value,
+gpointer dev)
+{
+VirtioSharedObject *vso;
+
+vso = (VirtioSharedObject *) value;
+return vso->type == TYPE_VHOST_DEV && vso->value.dev == dev;
+}
+
+int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev)
+{
+int num_removed;
+
+WITH_QEMU_LOCK_GUARD() {
+num_removed = g_hash_table_foreach_remove(
+resource_uuids, (GHRFunc) virtio_dmabuf_resource_is_owned, dev);
+}
+return num_removed;
+}
+
 void virtio_free_resources(void)
 {
 WITH_QEMU_LOCK_GUARD() {
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 2c9ac79468..c5622eac14 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -16,6 +16,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "hw/virtio/vhost.h"
+#include "hw/virtio/virtio-dmabuf.h"
 #include "qemu/atomic.h"
 #include "qemu/range.h"
 #include "qemu/error-report.h"
@@ -1599,6 +1600,8 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
 migrate_del_blocker(>migration_blocker);
 g_free(hdev->mem);
 g_free(hdev->mem_sections);
+/* free virtio shared objects */
+virtio_dmabuf_vhost_cleanup(hdev);
 if (hdev->vhost_ops) {
 hdev->vhost_ops->vhost_backend_cleanup(hdev);
 }
diff --git a/include/hw/virtio/virtio-dmabuf.h 
b/include/hw/virtio/virtio-dmabuf.h
index 627d84dce9..950cd24967 100644
--- a/include/hw/virtio/virtio-dmabuf.h
+++ b/include/hw/virtio/virtio-dmabuf.h
@@ -119,6 +119,16 @@ struct vhost_dev *virtio_lookup_vhost_device(const 
QemuUUID *uuid);
  */
 SharedObjectType virtio_object_type(const QemuUUID *uuid);
 
+/**
+ * virtio_dmabuf_vhost_cleanup() - Destroys all entries of the shared
+ * resources lookup table that are owned by the vhost backend
+ * @dev: the pointer to the vhost device that owns the entries. Data is owned
+ *   by the called of the function.
+ * 
+ * Return: the number of resource entries removed.
+ */
+int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev);
+
 /**
  * virtio_free_resources() - Destroys all keys and values of the shared
  * resources lookup table, and frees them
diff --git a/tests/unit/test-virtio-dmabuf.c b/tests/unit/test-virtio-dmabuf.c
index 20213455ee..e5cf7ee19f 100644
--- a/tests/unit/test-virtio-dmabuf.c
+++ b/tests/unit/test-virtio-dmabuf.c
@@ -107,6 +107,38 @@ static void test_add_invalid_resource(void)
 }
 }
 
+static void test_cleanup_res(void)
+{
+QemuUUID uuids[20], uuid_alt;
+struct vhost_dev *dev = g_new0(struct vhost_dev, 1);
+struct vhost_dev *dev_alt = g_new0(struct vhost_dev, 1);
+int i, num_removed;
+
+for (i = 0; i < ARRAY_SIZE(uuids); ++i) {
+qemu_uuid_generate([i]);
+virtio_add_vhost_device([i], dev);
+/* vhost device is found */
+g_assert(virtio_lookup_vhost_device([i]) != NULL);
+}
+qemu_uuid_generate(_alt);
+virtio_add_vhost_device(_alt, dev_alt);
+/* vhost device is found */
+g_assert(virtio_lookup_vhost_device(_alt) != NULL);
+/* cleanup all dev resources */
+num_removed = virtio_dmabuf_vhost_cleanup(dev);
+g_assert_cmpint(num_removed, ==, ARRAY_SIZE(uuids));
+for (i = 0; i < ARRAY_SIZE(uuids); ++i) {
+/* None of the dev resources is found after free'd */
+g_assert_cmpint(virtio_lookup_dmabuf([i]), ==, -1);
+}
+/* uuid_alt is still in the hash table */
+g_assert(virtio_lookup_vhost_device(_alt) != NULL);
+
+virtio_free_resources();
+g_free(dev);
+g_free(dev_alt);
+}
+
 static void test_free_resources(void)
 {
 QemuUUID uuids[20];
@@ -136,6 +168,7 @@ int main(int argc, char **argv)
 test_remove_invalid_resource);
 g_test_add_func("/virtio-dmabuf/add_invalid_res",
 test_add_inva

[PATCH v4 3/5] hw/virtio: change dmabuf mutex to QemuMutex

2024-02-19 Thread Albert Esteve
Change GMutex by QemuMutex to be able to use
lock contexts with `WITH_QEMU_LOCK_GUARD`.

As the lock needs to be initialised and there
is no central point for initialisation, add
an init public function and call it from
virtio.c, each time a new backend structure
is initialised.

Signed-off-by: Albert Esteve 
---
 hw/display/virtio-dmabuf.c| 55 +--
 hw/virtio/virtio.c|  3 ++
 include/hw/virtio/virtio-dmabuf.h |  5 +++
 tests/unit/test-virtio-dmabuf.c   |  5 +++
 4 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
index 497cb6fa7c..961094a561 100644
--- a/hw/display/virtio-dmabuf.c
+++ b/hw/display/virtio-dmabuf.c
@@ -11,11 +11,12 @@
  */
 
 #include "qemu/osdep.h"
+#include "include/qemu/lockable.h"
 
 #include "hw/virtio/virtio-dmabuf.h"
 
 
-static GMutex lock;
+static QemuMutex lock;
 static GHashTable *resource_uuids;
 
 /*
@@ -27,23 +28,27 @@ static int uuid_equal_func(const void *lhv, const void *rhv)
 return qemu_uuid_is_equal(lhv, rhv);
 }
 
+void virtio_dmabuf_init(void) {
+qemu_mutex_init();
+}
+
 static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value)
 {
 bool result = true;
 
-g_mutex_lock();
-if (resource_uuids == NULL) {
-resource_uuids = g_hash_table_new_full(qemu_uuid_hash,
-   uuid_equal_func,
-   NULL,
-   g_free);
-}
-if (g_hash_table_lookup(resource_uuids, uuid) == NULL) {
-g_hash_table_insert(resource_uuids, uuid, value);
-} else {
-result = false;
+WITH_QEMU_LOCK_GUARD() {
+if (resource_uuids == NULL) {
+resource_uuids = g_hash_table_new_full(qemu_uuid_hash,
+uuid_equal_func,
+NULL,
+g_free);
+}
+if (g_hash_table_lookup(resource_uuids, uuid) == NULL) {
+g_hash_table_insert(resource_uuids, uuid, value);
+} else {
+result = false;
+}
 }
-g_mutex_unlock();
 
 return result;
 }
@@ -87,9 +92,9 @@ bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev 
*dev)
 bool virtio_remove_resource(const QemuUUID *uuid)
 {
 bool result;
-g_mutex_lock();
-result = g_hash_table_remove(resource_uuids, uuid);
-g_mutex_unlock();
+WITH_QEMU_LOCK_GUARD() {
+result = g_hash_table_remove(resource_uuids, uuid);
+}
 
 return result;
 }
@@ -98,11 +103,11 @@ static VirtioSharedObject *get_shared_object(const 
QemuUUID *uuid)
 {
 gpointer lookup_res = NULL;
 
-g_mutex_lock();
-if (resource_uuids != NULL) {
-lookup_res = g_hash_table_lookup(resource_uuids, uuid);
+WITH_QEMU_LOCK_GUARD() {
+if (resource_uuids != NULL) {
+lookup_res = g_hash_table_lookup(resource_uuids, uuid);
+}
 }
-g_mutex_unlock();
 
 return (VirtioSharedObject *) lookup_res;
 }
@@ -138,9 +143,9 @@ SharedObjectType virtio_object_type(const QemuUUID *uuid)
 
 void virtio_free_resources(void)
 {
-g_mutex_lock();
-g_hash_table_destroy(resource_uuids);
-/* Reference count shall be 0 after the implicit unref on destroy */
-resource_uuids = NULL;
-g_mutex_unlock();
+WITH_QEMU_LOCK_GUARD() {
+g_hash_table_destroy(resource_uuids);
+/* Reference count shall be 0 after the implicit unref on destroy */
+resource_uuids = NULL;
+}
 }
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index d229755eae..88189e7178 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -29,6 +29,7 @@
 #include "hw/virtio/virtio-bus.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-access.h"
+#include "hw/virtio/virtio-dmabuf.h"
 #include "sysemu/dma.h"
 #include "sysemu/runstate.h"
 #include "virtio-qmp.h"
@@ -3221,6 +3222,8 @@ void virtio_init(VirtIODevice *vdev, uint16_t device_id, 
size_t config_size)
 int i;
 int nvectors = k->query_nvectors ? k->query_nvectors(qbus->parent) : 0;
 
+// Ensure virtio dmabuf table is initialised.
+virtio_dmabuf_init();
 if (nvectors) {
 vdev->vector_queues =
 g_malloc0(sizeof(*vdev->vector_queues) * nvectors);
diff --git a/include/hw/virtio/virtio-dmabuf.h 
b/include/hw/virtio/virtio-dmabuf.h
index 891a43162d..627d84dce9 100644
--- a/include/hw/virtio/virtio-dmabuf.h
+++ b/include/hw/virtio/virtio-dmabuf.h
@@ -50,6 +50,11 @@ typedef struct VirtioSharedObject {
 } value;
 } VirtioSharedObject;
 
+/**
+ * virtio_dmabuf_init() - Initialise virtio dmabuf internal structures.
+ */
+void virtio_dmabuf_init(void);
+
 /**
  * virtio_add_dmabuf() - Add a new dma-buf re

[PATCH v4 2/5] hw/virtio: document SharedObject structures

2024-02-19 Thread Albert Esteve
Change VirtioSharedObject value type from
a generic pointer to a union storing the different
supported underlying types, which makes naming
less confusing.

With the update, use the chance to add kdoc
to both the SharedObjectType enum and
VirtioSharedObject struct.

Signed-off-by: Albert Esteve 
---
 hw/display/virtio-dmabuf.c|  8 
 include/hw/virtio/virtio-dmabuf.h | 25 -
 2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
index 3dba4577ca..497cb6fa7c 100644
--- a/hw/display/virtio-dmabuf.c
+++ b/hw/display/virtio-dmabuf.c
@@ -57,7 +57,7 @@ bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
 }
 vso = g_new(VirtioSharedObject, 1);
 vso->type = TYPE_DMABUF;
-vso->value = GINT_TO_POINTER(udmabuf_fd);
+vso->value.udma_buf = udmabuf_fd;
 result = virtio_add_resource(uuid, vso);
 if (!result) {
 g_free(vso);
@@ -75,7 +75,7 @@ bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev 
*dev)
 }
 vso = g_new(VirtioSharedObject, 1);
 vso->type = TYPE_VHOST_DEV;
-vso->value = dev;
+vso->value.dev = dev;
 result = virtio_add_resource(uuid, vso);
 if (!result) {
 g_free(vso);
@@ -114,7 +114,7 @@ int virtio_lookup_dmabuf(const QemuUUID *uuid)
 return -1;
 }
 assert(vso->type == TYPE_DMABUF);
-return GPOINTER_TO_INT(vso->value);
+return vso->value.udma_buf;
 }
 
 struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
@@ -124,7 +124,7 @@ struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID 
*uuid)
 return NULL;
 }
 assert(vso->type == TYPE_VHOST_DEV);
-return (struct vhost_dev *) vso->value;
+return (struct vhost_dev *) vso->value.dev;
 }
 
 SharedObjectType virtio_object_type(const QemuUUID *uuid)
diff --git a/include/hw/virtio/virtio-dmabuf.h 
b/include/hw/virtio/virtio-dmabuf.h
index 627c3b6db7..891a43162d 100644
--- a/include/hw/virtio/virtio-dmabuf.h
+++ b/include/hw/virtio/virtio-dmabuf.h
@@ -16,15 +16,38 @@
 #include "qemu/uuid.h"
 #include "vhost.h"
 
+/**
+ * SharedObjectType:
+ * 
+ * Identifies the type of the underlying type that the current lookup
+ * table entry is holding.
+ * 
+ * TYPE_INVALID: Invalid entry
+ * TYPE_DMABUF: Entry is a dmabuf file descriptor that can be directly
+ *  shared with the requestor
+ * TYPE_VHOST_DEV: Entry is a pointer to a vhost device that is holding
+ * the shared object.
+ */
 typedef enum SharedObjectType {
 TYPE_INVALID = 0,
 TYPE_DMABUF,
 TYPE_VHOST_DEV,
 } SharedObjectType;
 
+/**
+ * VirtioSharedObject:
+ * @type: Shared object type identifier
+ * @value: Union containing to the underlying type
+ * 
+ * The VirtioSharedObject object provides a way to distinguish,
+ * store, and handle the different types supported by the lookup table.
+ */
 typedef struct VirtioSharedObject {
 SharedObjectType type;
-gpointer value;
+union {
+struct vhost_dev *dev;  /* TYPE_VHOST_DEV */
+int udma_buf;   /* TYPE_DMABUF */
+} value;
 } VirtioSharedObject;
 
 /**
-- 
2.43.1




[PATCH v4 5/5] hw/virtio: rename virtio dmabuf API

2024-02-19 Thread Albert Esteve
Functions in the virtio-dmabuf module
start with 'virtio_*', which is too
generic and may not correctly identify
them as part of the virtio dmabuf API.

Rename all functions to 'virtio_dmabuf_*'
instead to avoid confusion.

Signed-off-by: Albert Esteve 
Acked-by: Stefan Hajnoczi 
Reviewed-by: Philippe Mathieu-Daudé 
---
 hw/display/virtio-dmabuf.c| 14 
 hw/virtio/vhost-user.c| 14 
 include/hw/virtio/virtio-dmabuf.h | 33 +-
 tests/unit/test-virtio-dmabuf.c   | 58 +++
 4 files changed, 60 insertions(+), 59 deletions(-)

diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
index 703b5bd979..4e32af2ad0 100644
--- a/hw/display/virtio-dmabuf.c
+++ b/hw/display/virtio-dmabuf.c
@@ -53,7 +53,7 @@ static bool virtio_add_resource(QemuUUID *uuid, 
VirtioSharedObject *value)
 return result;
 }
 
-bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
+bool virtio_dmabuf_add(QemuUUID *uuid, int udmabuf_fd)
 {
 bool result;
 VirtioSharedObject *vso;
@@ -71,7 +71,7 @@ bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
 return result;
 }
 
-bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
+bool virtio_dmabuf_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
 {
 bool result;
 VirtioSharedObject *vso;
@@ -89,7 +89,7 @@ bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev 
*dev)
 return result;
 }
 
-bool virtio_remove_resource(const QemuUUID *uuid)
+bool virtio_dmabuf_remove_resource(const QemuUUID *uuid)
 {
 bool result;
 WITH_QEMU_LOCK_GUARD() {
@@ -112,7 +112,7 @@ static VirtioSharedObject *get_shared_object(const QemuUUID 
*uuid)
 return (VirtioSharedObject *) lookup_res;
 }
 
-int virtio_lookup_dmabuf(const QemuUUID *uuid)
+int virtio_dmabuf_lookup(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -122,7 +122,7 @@ int virtio_lookup_dmabuf(const QemuUUID *uuid)
 return vso->value.udma_buf;
 }
 
-struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
+struct vhost_dev *virtio_dmabuf_lookup_vhost_device(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -132,7 +132,7 @@ struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID 
*uuid)
 return (struct vhost_dev *) vso->value.dev;
 }
 
-SharedObjectType virtio_object_type(const QemuUUID *uuid)
+SharedObjectType virtio_dmabuf_object_type(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -162,7 +162,7 @@ int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev)
 return num_removed;
 }
 
-void virtio_free_resources(void)
+void virtio_dmabuf_free_resources(void)
 {
 WITH_QEMU_LOCK_GUARD() {
 g_hash_table_destroy(resource_uuids);
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 152710d30d..104d7d4e62 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1607,7 +1607,7 @@ vhost_user_backend_handle_shared_object_add(struct 
vhost_dev *dev,
 QemuUUID uuid;
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
-return virtio_add_vhost_device(, dev);
+return virtio_dmabuf_add_vhost_device(, dev);
 }
 
 static int
@@ -1617,10 +1617,10 @@ vhost_user_backend_handle_shared_object_remove(struct 
vhost_dev *dev,
 QemuUUID uuid;
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
-switch (virtio_object_type()) {
+switch (virtio_dmabuf_object_type()) {
 case TYPE_VHOST_DEV:
 {
-struct vhost_dev *owner = virtio_lookup_vhost_device();
+struct vhost_dev *owner = virtio_dmabuf_lookup_vhost_device();
 if (dev != owner) {
 /* Not allowed to remove non-owned entries */
 return 0;
@@ -1632,7 +1632,7 @@ vhost_user_backend_handle_shared_object_remove(struct 
vhost_dev *dev,
 return 0;
 }
 
-return virtio_remove_resource();
+return virtio_dmabuf_remove_resource();
 }
 
 static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr,
@@ -1710,13 +1710,13 @@ vhost_user_backend_handle_shared_object_lookup(struct 
vhost_user *u,
 memcpy(uuid.data, payload->object.uuid, sizeof(payload->object.uuid));
 
 payload->u64 = 0;
-switch (virtio_object_type()) {
+switch (virtio_dmabuf_object_type()) {
 case TYPE_DMABUF:
-dmabuf_fd = virtio_lookup_dmabuf();
+dmabuf_fd = virtio_dmabuf_lookup();
 break;
 case TYPE_VHOST_DEV:
 {
-struct vhost_dev *dev = virtio_lookup_vhost_device();
+struct vhost_dev *dev = virtio_dmabuf_lookup_vhost_device();
 if (dev == NULL) {
 payload->u64 = -EINVAL;
 break;
diff --git a/include/hw/virtio/virtio-dmabuf.h 
b/include/hw/virtio/virtio-dmabuf.h
index 950cd24967..b9ee761a0c 100644
--- a/include/hw/virtio/virtio-dmabuf.h
+++ b/inc

[PATCH v4 1/5] hw/virtio: check owner for removing objects

2024-02-19 Thread Albert Esteve
Shared objects lack spoofing protection.
For VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE messages
received by the vhost-user interface, any backend was
allowed to remove entries from the shared table just
by knowing the UUID. Only the owner of the entry
shall be allowed to removed their resources
from the table.

To fix that, add a check for all
*SHARED_OBJECT_REMOVE messages received.
A vhost device can only remove TYPE_VHOST_DEV
entries that are owned by them, otherwise skip
the removal, and inform the device that the entry
has not been removed in the answer.

Signed-off-by: Albert Esteve 
Acked-by: Stefan Hajnoczi 
---
 docs/interop/vhost-user.rst |  4 +++-
 hw/virtio/vhost-user.c  | 21 +++--
 2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index ad6e142f23..32496b5aa9 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -1839,7 +1839,9 @@ is sent by the front-end.
   When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
   feature has been successfully negotiated, this message can be submitted
   by the backend to remove themselves from to the virtio-dmabuf shared
-  table API. The shared table will remove the back-end device associated with
+  table API. Only the back-end owning the entry (i.e., the one that first added
+  it) will have permission to remove it. Otherwise, the message is ignored.
+  The shared table will remove the back-end device associated with
   the UUID. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and the
   back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond
   with zero when operation is successfully completed, or non-zero otherwise.
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index f214df804b..152710d30d 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1611,11 +1611,27 @@ vhost_user_backend_handle_shared_object_add(struct 
vhost_dev *dev,
 }
 
 static int
-vhost_user_backend_handle_shared_object_remove(VhostUserShared *object)
+vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
+   VhostUserShared *object)
 {
 QemuUUID uuid;
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
+switch (virtio_object_type()) {
+case TYPE_VHOST_DEV:
+{
+struct vhost_dev *owner = virtio_lookup_vhost_device();
+if (dev != owner) {
+/* Not allowed to remove non-owned entries */
+return 0;
+}
+break;
+}
+default:
+/* Not allowed to remove non-owned entries */
+return 0;
+}
+
 return virtio_remove_resource();
 }
 
@@ -1794,7 +1810,8 @@ static gboolean backend_read(QIOChannel *ioc, 
GIOCondition condition,
 ret = vhost_user_backend_handle_shared_object_add(dev, 
);
 break;
 case VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE:
-ret = vhost_user_backend_handle_shared_object_remove();
+ret = vhost_user_backend_handle_shared_object_remove(dev,
+ );
 break;
 case VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP:
 ret = vhost_user_backend_handle_shared_object_lookup(dev->opaque, ioc,
-- 
2.43.1




[PATCH v4 0/5] Virtio dmabuf improvements

2024-02-19 Thread Albert Esteve
v1: https://www.mail-archive.com/qemu-devel@nongnu.org/msg1005257.html
v2: https://www.mail-archive.com/qemu-devel@nongnu.org/msg1014615.html
v3: Virtio dmabuf improvements
v3 -> v4
  - Changed GMutex by QemuMutex in virtio-dmabuf
  - Made the value at VirtioSharedObject an union
to make naming more clear
  - Added some documentation

Various improvements for the virtio-dmabuf module.
This patch includes:

- Check for ownership before allowing a vhost device
  to remove an object from the table.
- Properly cleanup shared resources if a vhost device
  object gets cleaned up.
- Rename virtio dmabuf functions to `virtio_dmabuf_*`

Albert Esteve (5):
  hw/virtio: check owner for removing objects
  hw/virtio: document SharedObject structures
  hw/virtio: change dmabuf mutex to QemuMutex
  hw/virtio: cleanup shared resources
  hw/virtio: rename virtio dmabuf API

 docs/interop/vhost-user.rst   |  4 +-
 hw/display/virtio-dmabuf.c| 98 +++
 hw/virtio/vhost-user.c| 31 +++---
 hw/virtio/vhost.c |  3 +
 hw/virtio/virtio.c|  3 +
 include/hw/virtio/virtio-dmabuf.h | 73 +--
 tests/unit/test-virtio-dmabuf.c   | 82 +++---
 7 files changed, 211 insertions(+), 83 deletions(-)

-- 
2.43.1




Re: [PATCH v3 2/3] hw/virtio: cleanup shared resources

2024-02-19 Thread Albert Esteve
On Mon, Feb 19, 2024 at 11:45 AM Albert Esteve  wrote:

>
>
>
> On Thu, Feb 15, 2024 at 10:45 AM Albert Esteve  wrote:
>
>>
>>
>> On Tue, Feb 6, 2024 at 12:11 AM Alex Bennée 
>> wrote:
>>
>>> Albert Esteve  writes:
>>>
>>> > Ensure that we cleanup all virtio shared
>>> > resources when the vhost devices is cleaned
>>> > up (after a hot unplug, or a crash).
>>> >
>>> > To do so, we add a new function to the virtio_dmabuf
>>> > API called `virtio_dmabuf_vhost_cleanup`, which
>>> > loop through the table and removes all
>>> > resources owned by the vhost device parameter.
>>> >
>>> > Also, add a test to verify that the new
>>> > function in the API behaves as expected.
>>> >
>>> > Signed-off-by: Albert Esteve 
>>> > Acked-by: Stefan Hajnoczi 
>>> > ---
>>> >  hw/display/virtio-dmabuf.c| 22 +
>>> >  hw/virtio/vhost.c |  3 +++
>>> >  include/hw/virtio/virtio-dmabuf.h | 10 ++
>>> >  tests/unit/test-virtio-dmabuf.c   | 33 +++
>>> >  4 files changed, 68 insertions(+)
>>> >
>>> > diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
>>> > index 3dba4577ca..6688809777 100644
>>> > --- a/hw/display/virtio-dmabuf.c
>>> > +++ b/hw/display/virtio-dmabuf.c
>>> > @@ -136,6 +136,28 @@ SharedObjectType virtio_object_type(const
>>> QemuUUID *uuid)
>>> >  return vso->type;
>>> >  }
>>> >
>>> > +static bool virtio_dmabuf_resource_is_owned(gpointer key,
>>> > +gpointer value,
>>> > +gpointer dev)
>>> > +{
>>> > +VirtioSharedObject *vso;
>>> > +
>>> > +vso = (VirtioSharedObject *) value;
>>> > +return vso->type == TYPE_VHOST_DEV && vso->value == dev;
>>>
>>> It's a bit surprising to see vso->value being an anonymous gpointer
>>> rather than the proper type and a bit confusing between value and
>>> vso->value.
>>>
>>>
>> It is the signature required for this to be used with
>> `g_hash_table_foreach_remove`.
>> For the naming, the HashMap stores gpointers, that point to
>> `VirtioSharedObject`, and
>> these point to the underlying type (stored at `vso->value`). It may sound
>> a bit confusing,
>> but is a byproduct of the VirtioSharedObject indirection. Not sure which
>> names could be
>> more fit for this, but I'm open to change them.
>>
>>
>>> > +}
>>> > +
>>> > +int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev)
>>> > +{
>>> > +int num_removed;
>>> > +
>>> > +g_mutex_lock();
>>> > +num_removed = g_hash_table_foreach_remove(
>>> > +resource_uuids, (GHRFunc) virtio_dmabuf_resource_is_owned,
>>> dev);
>>> > +g_mutex_unlock();
>>>
>>> I'll note if we used a QemuMutex for the lock we could:
>>>
>>>   - use WITH_QEMU_LOCK_GUARD() { }
>>>   - enable QSP porfiling for the lock
>>>
>>>
>> Was not aware of these QemuMutex's. I wouldn't mind changing the mutex in
>> this
>> file in a different commit.
>>
>
> The problem is that current lock is a global static, and `QemuMutex` needs
> to be
> initialised by doing `qemu_mutex_init();`.
>
> Maybe can be initialised at vhost-user.c by adding a public function?
>

I think `virtio_init` at `virtio.c` will be a better candidate.


>
>
>>
>>
>>> > +
>>> > +return num_removed;
>>> > +}
>>> > +
>>> >  void virtio_free_resources(void)
>>> >  {
>>> >  g_mutex_lock();
>>> > diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
>>> > index 2c9ac79468..c5622eac14 100644
>>> > --- a/hw/virtio/vhost.c
>>> > +++ b/hw/virtio/vhost.c
>>> > @@ -16,6 +16,7 @@
>>> >  #include "qemu/osdep.h"
>>> >  #include "qapi/error.h"
>>> >  #include "hw/virtio/vhost.h"
>>> > +#include "hw/virtio/virtio-dmabuf.h"
>>> >  #include "qemu/atomic.h"
>>> >  #include "qemu/range.h"
>>> >  #include 

Re: [PATCH v3 2/3] hw/virtio: cleanup shared resources

2024-02-19 Thread Albert Esteve
On Thu, Feb 15, 2024 at 10:45 AM Albert Esteve  wrote:

>
>
> On Tue, Feb 6, 2024 at 12:11 AM Alex Bennée 
> wrote:
>
>> Albert Esteve  writes:
>>
>> > Ensure that we cleanup all virtio shared
>> > resources when the vhost devices is cleaned
>> > up (after a hot unplug, or a crash).
>> >
>> > To do so, we add a new function to the virtio_dmabuf
>> > API called `virtio_dmabuf_vhost_cleanup`, which
>> > loop through the table and removes all
>> > resources owned by the vhost device parameter.
>> >
>> > Also, add a test to verify that the new
>> > function in the API behaves as expected.
>> >
>> > Signed-off-by: Albert Esteve 
>> > Acked-by: Stefan Hajnoczi 
>> > ---
>> >  hw/display/virtio-dmabuf.c| 22 +
>> >  hw/virtio/vhost.c |  3 +++
>> >  include/hw/virtio/virtio-dmabuf.h | 10 ++
>> >  tests/unit/test-virtio-dmabuf.c   | 33 +++
>> >  4 files changed, 68 insertions(+)
>> >
>> > diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
>> > index 3dba4577ca..6688809777 100644
>> > --- a/hw/display/virtio-dmabuf.c
>> > +++ b/hw/display/virtio-dmabuf.c
>> > @@ -136,6 +136,28 @@ SharedObjectType virtio_object_type(const QemuUUID
>> *uuid)
>> >  return vso->type;
>> >  }
>> >
>> > +static bool virtio_dmabuf_resource_is_owned(gpointer key,
>> > +gpointer value,
>> > +gpointer dev)
>> > +{
>> > +VirtioSharedObject *vso;
>> > +
>> > +vso = (VirtioSharedObject *) value;
>> > +return vso->type == TYPE_VHOST_DEV && vso->value == dev;
>>
>> It's a bit surprising to see vso->value being an anonymous gpointer
>> rather than the proper type and a bit confusing between value and
>> vso->value.
>>
>>
> It is the signature required for this to be used with
> `g_hash_table_foreach_remove`.
> For the naming, the HashMap stores gpointers, that point to
> `VirtioSharedObject`, and
> these point to the underlying type (stored at `vso->value`). It may sound
> a bit confusing,
> but is a byproduct of the VirtioSharedObject indirection. Not sure which
> names could be
> more fit for this, but I'm open to change them.
>
>
>> > +}
>> > +
>> > +int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev)
>> > +{
>> > +int num_removed;
>> > +
>> > +g_mutex_lock();
>> > +num_removed = g_hash_table_foreach_remove(
>> > +resource_uuids, (GHRFunc) virtio_dmabuf_resource_is_owned,
>> dev);
>> > +g_mutex_unlock();
>>
>> I'll note if we used a QemuMutex for the lock we could:
>>
>>   - use WITH_QEMU_LOCK_GUARD() { }
>>   - enable QSP porfiling for the lock
>>
>>
> Was not aware of these QemuMutex's. I wouldn't mind changing the mutex in
> this
> file in a different commit.
>

The problem is that current lock is a global static, and `QemuMutex` needs
to be
initialised by doing `qemu_mutex_init();`.

Maybe can be initialised at vhost-user.c by adding a public function?


>
>
>> > +
>> > +return num_removed;
>> > +}
>> > +
>> >  void virtio_free_resources(void)
>> >  {
>> >  g_mutex_lock();
>> > diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
>> > index 2c9ac79468..c5622eac14 100644
>> > --- a/hw/virtio/vhost.c
>> > +++ b/hw/virtio/vhost.c
>> > @@ -16,6 +16,7 @@
>> >  #include "qemu/osdep.h"
>> >  #include "qapi/error.h"
>> >  #include "hw/virtio/vhost.h"
>> > +#include "hw/virtio/virtio-dmabuf.h"
>> >  #include "qemu/atomic.h"
>> >  #include "qemu/range.h"
>> >  #include "qemu/error-report.h"
>> > @@ -1599,6 +1600,8 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
>> >  migrate_del_blocker(>migration_blocker);
>> >  g_free(hdev->mem);
>> >  g_free(hdev->mem_sections);
>> > +/* free virtio shared objects */
>> > +virtio_dmabuf_vhost_cleanup(hdev);
>> >  if (hdev->vhost_ops) {
>> >  hdev->vhost_ops->vhost_backend_cleanup(hdev);
>> >  }
>> > diff --git a/include/hw/virtio/virtio-dmabuf.h
>> b/include/hw/virtio/virtio-dmabuf.h
>> &

Re: [PATCH v3 2/3] hw/virtio: cleanup shared resources

2024-02-15 Thread Albert Esteve
On Tue, Feb 6, 2024 at 12:11 AM Alex Bennée  wrote:

> Albert Esteve  writes:
>
> > Ensure that we cleanup all virtio shared
> > resources when the vhost devices is cleaned
> > up (after a hot unplug, or a crash).
> >
> > To do so, we add a new function to the virtio_dmabuf
> > API called `virtio_dmabuf_vhost_cleanup`, which
> > loop through the table and removes all
> > resources owned by the vhost device parameter.
> >
> > Also, add a test to verify that the new
> > function in the API behaves as expected.
> >
> > Signed-off-by: Albert Esteve 
> > Acked-by: Stefan Hajnoczi 
> > ---
> >  hw/display/virtio-dmabuf.c| 22 +
> >  hw/virtio/vhost.c |  3 +++
> >  include/hw/virtio/virtio-dmabuf.h | 10 ++
> >  tests/unit/test-virtio-dmabuf.c   | 33 +++
> >  4 files changed, 68 insertions(+)
> >
> > diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
> > index 3dba4577ca..6688809777 100644
> > --- a/hw/display/virtio-dmabuf.c
> > +++ b/hw/display/virtio-dmabuf.c
> > @@ -136,6 +136,28 @@ SharedObjectType virtio_object_type(const QemuUUID
> *uuid)
> >  return vso->type;
> >  }
> >
> > +static bool virtio_dmabuf_resource_is_owned(gpointer key,
> > +gpointer value,
> > +gpointer dev)
> > +{
> > +VirtioSharedObject *vso;
> > +
> > +vso = (VirtioSharedObject *) value;
> > +return vso->type == TYPE_VHOST_DEV && vso->value == dev;
>
> It's a bit surprising to see vso->value being an anonymous gpointer
> rather than the proper type and a bit confusing between value and
> vso->value.
>
>
It is the signature required for this to be used with
`g_hash_table_foreach_remove`.
For the naming, the HashMap stores gpointers, that point to
`VirtioSharedObject`, and
these point to the underlying type (stored at `vso->value`). It may sound a
bit confusing,
but is a byproduct of the VirtioSharedObject indirection. Not sure which
names could be
more fit for this, but I'm open to change them.


> > +}
> > +
> > +int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev)
> > +{
> > +int num_removed;
> > +
> > +g_mutex_lock();
> > +num_removed = g_hash_table_foreach_remove(
> > +resource_uuids, (GHRFunc) virtio_dmabuf_resource_is_owned, dev);
> > +g_mutex_unlock();
>
> I'll note if we used a QemuMutex for the lock we could:
>
>   - use WITH_QEMU_LOCK_GUARD() { }
>   - enable QSP porfiling for the lock
>
>
Was not aware of these QemuMutex's. I wouldn't mind changing the mutex in
this
file in a different commit.


> > +
> > +return num_removed;
> > +}
> > +
> >  void virtio_free_resources(void)
> >  {
> >  g_mutex_lock();
> > diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
> > index 2c9ac79468..c5622eac14 100644
> > --- a/hw/virtio/vhost.c
> > +++ b/hw/virtio/vhost.c
> > @@ -16,6 +16,7 @@
> >  #include "qemu/osdep.h"
> >  #include "qapi/error.h"
> >  #include "hw/virtio/vhost.h"
> > +#include "hw/virtio/virtio-dmabuf.h"
> >  #include "qemu/atomic.h"
> >  #include "qemu/range.h"
> >  #include "qemu/error-report.h"
> > @@ -1599,6 +1600,8 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
> >  migrate_del_blocker(>migration_blocker);
> >  g_free(hdev->mem);
> >  g_free(hdev->mem_sections);
> > +/* free virtio shared objects */
> > +virtio_dmabuf_vhost_cleanup(hdev);
> >  if (hdev->vhost_ops) {
> >  hdev->vhost_ops->vhost_backend_cleanup(hdev);
> >  }
> > diff --git a/include/hw/virtio/virtio-dmabuf.h
> b/include/hw/virtio/virtio-dmabuf.h
> > index 627c3b6db7..73f70fb482 100644
> > --- a/include/hw/virtio/virtio-dmabuf.h
> > +++ b/include/hw/virtio/virtio-dmabuf.h
> > @@ -91,6 +91,16 @@ struct vhost_dev *virtio_lookup_vhost_device(const
> QemuUUID *uuid);
> >   */
> >  SharedObjectType virtio_object_type(const QemuUUID *uuid);
> >
> > +/**
> > + * virtio_dmabuf_vhost_cleanup() - Destroys all entries of the shared
> > + * resources lookup table that are owned by the vhost backend
> > + * @dev: the pointer to the vhost device that owns the entries. Data is
> owned
> > + *   by the called of the function.
> > + *
> > + * Return: the number of resource entries removed.
> >

Re: [PATCH v3 1/3] hw/virtio: check owner for removing objects

2024-02-15 Thread Albert Esteve
On Mon, Feb 5, 2024 at 1:57 PM Alex Bennée  wrote:

> Albert Esteve  writes:
>
> > Shared objects lack spoofing protection.
> > For VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE messages
> > received by the vhost-user interface, any backend was
> > allowed to remove entries from the shared table just
> > by knowing the UUID. Only the owner of the entry
> > shall be allowed to removed their resources
> > from the table.
>
> Was this buggy behaviour on the part of the vhost-user daemon?
>

Yes, although the feature is not really used yet, and it requires to know
the UUID to be able to exploit it. But yes, any vhost-user backend could
remove any entry.


>
> > To fix that, add a check for all
> > *SHARED_OBJECT_REMOVE messages received.
> > A vhost device can only remove TYPE_VHOST_DEV
> > entries that are owned by them, otherwise skip
> > the removal, and inform the device that the entry
> > has not been removed in the answer.
> >
> > Signed-off-by: Albert Esteve 
> > Acked-by: Stefan Hajnoczi 
> > ---
> >  docs/interop/vhost-user.rst |  4 +++-
> >  hw/virtio/vhost-user.c  | 21 +++--
> >  2 files changed, 22 insertions(+), 3 deletions(-)
> >
> > diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
> > index 9f1103f85a..60ec2c9d48 100644
> > --- a/docs/interop/vhost-user.rst
> > +++ b/docs/interop/vhost-user.rst
> > @@ -1839,7 +1839,9 @@ is sent by the front-end.
> >When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
> >feature has been successfully negotiated, this message can be
> submitted
> >by the backend to remove themselves from to the virtio-dmabuf shared
> > -  table API. The shared table will remove the back-end device
> associated with
> > +  table API. Only the back-end owning the entry (i.e., the one that
> first added
> > +  it) will have permission to remove it. Otherwise, the message is
> ignored.
> > +  The shared table will remove the back-end device associated with
> >the UUID. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and
> the
> >back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must
> respond
> >with zero when operation is successfully completed, or non-zero
> otherwise.
> > diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
> > index f214df804b..1c3f2357be 100644
> > --- a/hw/virtio/vhost-user.c
> > +++ b/hw/virtio/vhost-user.c
> > @@ -1611,11 +1611,27 @@
> vhost_user_backend_handle_shared_object_add(struct vhost_dev *dev,
> >  }
> >
> >  static int
> > -vhost_user_backend_handle_shared_object_remove(VhostUserShared *object)
> > +vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
> > +   VhostUserShared *object)
> >  {
> >  QemuUUID uuid;
> >
> >  memcpy(uuid.data, object->uuid, sizeof(object->uuid));
> > +switch (virtio_object_type()) {
> > +case TYPE_VHOST_DEV:
>
> It would be nice if we could add a kdoc annotation to SharedObjectType
> describing what the various types mean.
>

I can add it.


>
> > +{
> > +struct vhost_dev *owner = virtio_lookup_vhost_device();
> > +if (owner == NULL || dev != owner) {
>
> I dev is always set dev != owner should also cover the NULL case.
>

True, I can remove the NULL case from the condition.


> However will we see uuid's that aren't associated with anything?
>

Theoretically, it shouldn't happen. Dmabufs in the host and the guest are
aligned,
and when one buffer is cleaned up it should not be requested anymore, as
the drivers
in the guest are aware. But a vhost-user backend could have buggy/malicious
requests, so worth the check.


>
> > +/* Not allowed to remove non-owned entries */
> > +return 0;
> > +}
> > +break;
> > +}
> > +default:
> > +/* Not allowed to remove non-owned entries */
> > +return 0;
> > +}
> > +
> >  return virtio_remove_resource();
> >  }
> >
> > @@ -1794,7 +1810,8 @@ static gboolean backend_read(QIOChannel *ioc,
> GIOCondition condition,
> >  ret = vhost_user_backend_handle_shared_object_add(dev,
> );
> >  break;
> >  case VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE:
> > -ret =
> vhost_user_backend_handle_shared_object_remove();
> > +ret = vhost_user_backend_handle_shared_object_remove(dev,
> > +
>  );
> >  break;
> >  case VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP:
> >  ret =
> vhost_user_backend_handle_shared_object_lookup(dev->opaque, ioc,
>
> --
> Alex Bennée
> Virtualisation Tech Lead @ Linaro
>
>


Re: [PATCH v3 0/3] Virtio dmabuf improvements

2024-02-05 Thread Albert Esteve
Friendly reminder & bump

Is this series waiting to be picked up, or is there anything left to do?

BR,
Albert




On Tue, Jan 9, 2024 at 1:56 PM Albert Esteve  wrote:

> v1: https://www.mail-archive.com/qemu-devel@nongnu.org/msg1005257.html
> v2: https://www.mail-archive.com/qemu-devel@nongnu.org/msg1014615.html
> v2 -> v3
>   - Documented the new owner check for shared object removal
>   - Updated test function names error in the last patch
>
> Various improvements for the virtio-dmabuf module.
> This patch includes:
>
> - Check for ownership before allowing a vhost device
>   to remove an object from the table.
> - Properly cleanup shared resources if a vhost device
>   object gets cleaned up.
> - Rename virtio dmabuf functions to `virtio_dmabuf_*`
>
> Albert Esteve (3):
>   hw/virtio: check owner for removing objects
>   hw/virtio: cleanup shared resources
>   hw/virtio: rename virtio dmabuf API
>
>  docs/interop/vhost-user.rst   |  4 +-
>  hw/display/virtio-dmabuf.c| 36 ---
>  hw/virtio/vhost-user.c| 31 ++---
>  hw/virtio/vhost.c |  3 ++
>  include/hw/virtio/virtio-dmabuf.h | 43 ++---
>  tests/unit/test-virtio-dmabuf.c   | 77 ++-
>  6 files changed, 141 insertions(+), 53 deletions(-)
>
> --
> 2.43.0
>
>


[PATCH v3 1/3] hw/virtio: check owner for removing objects

2024-01-09 Thread Albert Esteve
Shared objects lack spoofing protection.
For VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE messages
received by the vhost-user interface, any backend was
allowed to remove entries from the shared table just
by knowing the UUID. Only the owner of the entry
shall be allowed to removed their resources
from the table.

To fix that, add a check for all
*SHARED_OBJECT_REMOVE messages received.
A vhost device can only remove TYPE_VHOST_DEV
entries that are owned by them, otherwise skip
the removal, and inform the device that the entry
has not been removed in the answer.

Signed-off-by: Albert Esteve 
Acked-by: Stefan Hajnoczi 
---
 docs/interop/vhost-user.rst |  4 +++-
 hw/virtio/vhost-user.c  | 21 +++--
 2 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index 9f1103f85a..60ec2c9d48 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -1839,7 +1839,9 @@ is sent by the front-end.
   When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
   feature has been successfully negotiated, this message can be submitted
   by the backend to remove themselves from to the virtio-dmabuf shared
-  table API. The shared table will remove the back-end device associated with
+  table API. Only the back-end owning the entry (i.e., the one that first added
+  it) will have permission to remove it. Otherwise, the message is ignored.
+  The shared table will remove the back-end device associated with
   the UUID. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and the
   back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond
   with zero when operation is successfully completed, or non-zero otherwise.
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index f214df804b..1c3f2357be 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1611,11 +1611,27 @@ vhost_user_backend_handle_shared_object_add(struct 
vhost_dev *dev,
 }
 
 static int
-vhost_user_backend_handle_shared_object_remove(VhostUserShared *object)
+vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
+   VhostUserShared *object)
 {
 QemuUUID uuid;
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
+switch (virtio_object_type()) {
+case TYPE_VHOST_DEV:
+{
+struct vhost_dev *owner = virtio_lookup_vhost_device();
+if (owner == NULL || dev != owner) {
+/* Not allowed to remove non-owned entries */
+return 0;
+}
+break;
+}
+default:
+/* Not allowed to remove non-owned entries */
+return 0;
+}
+
 return virtio_remove_resource();
 }
 
@@ -1794,7 +1810,8 @@ static gboolean backend_read(QIOChannel *ioc, 
GIOCondition condition,
 ret = vhost_user_backend_handle_shared_object_add(dev, 
);
 break;
 case VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE:
-ret = vhost_user_backend_handle_shared_object_remove();
+ret = vhost_user_backend_handle_shared_object_remove(dev,
+ );
 break;
 case VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP:
 ret = vhost_user_backend_handle_shared_object_lookup(dev->opaque, ioc,
-- 
2.43.0




[PATCH v3 3/3] hw/virtio: rename virtio dmabuf API

2024-01-09 Thread Albert Esteve
Functions in the virtio-dmabuf module
start with 'virtio_*', which is too
generic and may not correctly identify
them as part of the virtio dmabuf API.

Rename all functions to 'virtio_dmabuf_*'
instead to avoid confusion.

Signed-off-by: Albert Esteve 
Acked-by: Stefan Hajnoczi 
---
 hw/display/virtio-dmabuf.c| 14 
 hw/virtio/vhost-user.c| 14 
 include/hw/virtio/virtio-dmabuf.h | 33 +-
 tests/unit/test-virtio-dmabuf.c   | 58 +++
 4 files changed, 60 insertions(+), 59 deletions(-)

diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
index 6688809777..42495f87ec 100644
--- a/hw/display/virtio-dmabuf.c
+++ b/hw/display/virtio-dmabuf.c
@@ -48,7 +48,7 @@ static bool virtio_add_resource(QemuUUID *uuid, 
VirtioSharedObject *value)
 return result;
 }
 
-bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
+bool virtio_dmabuf_add(QemuUUID *uuid, int udmabuf_fd)
 {
 bool result;
 VirtioSharedObject *vso;
@@ -66,7 +66,7 @@ bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
 return result;
 }
 
-bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
+bool virtio_dmabuf_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
 {
 bool result;
 VirtioSharedObject *vso;
@@ -84,7 +84,7 @@ bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev 
*dev)
 return result;
 }
 
-bool virtio_remove_resource(const QemuUUID *uuid)
+bool virtio_dmabuf_remove_resource(const QemuUUID *uuid)
 {
 bool result;
 g_mutex_lock();
@@ -107,7 +107,7 @@ static VirtioSharedObject *get_shared_object(const QemuUUID 
*uuid)
 return (VirtioSharedObject *) lookup_res;
 }
 
-int virtio_lookup_dmabuf(const QemuUUID *uuid)
+int virtio_dmabuf_lookup(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -117,7 +117,7 @@ int virtio_lookup_dmabuf(const QemuUUID *uuid)
 return GPOINTER_TO_INT(vso->value);
 }
 
-struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
+struct vhost_dev *virtio_dmabuf_lookup_vhost_device(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -127,7 +127,7 @@ struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID 
*uuid)
 return (struct vhost_dev *) vso->value;
 }
 
-SharedObjectType virtio_object_type(const QemuUUID *uuid)
+SharedObjectType virtio_dmabuf_object_type(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -158,7 +158,7 @@ int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev)
 return num_removed;
 }
 
-void virtio_free_resources(void)
+void virtio_dmabuf_free_resources(void)
 {
 g_mutex_lock();
 g_hash_table_destroy(resource_uuids);
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 1c3f2357be..2ab9e13f9e 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1607,7 +1607,7 @@ vhost_user_backend_handle_shared_object_add(struct 
vhost_dev *dev,
 QemuUUID uuid;
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
-return virtio_add_vhost_device(, dev);
+return virtio_dmabuf_add_vhost_device(, dev);
 }
 
 static int
@@ -1617,10 +1617,10 @@ vhost_user_backend_handle_shared_object_remove(struct 
vhost_dev *dev,
 QemuUUID uuid;
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
-switch (virtio_object_type()) {
+switch (virtio_dmabuf_object_type()) {
 case TYPE_VHOST_DEV:
 {
-struct vhost_dev *owner = virtio_lookup_vhost_device();
+struct vhost_dev *owner = virtio_dmabuf_lookup_vhost_device();
 if (owner == NULL || dev != owner) {
 /* Not allowed to remove non-owned entries */
 return 0;
@@ -1632,7 +1632,7 @@ vhost_user_backend_handle_shared_object_remove(struct 
vhost_dev *dev,
 return 0;
 }
 
-return virtio_remove_resource();
+return virtio_dmabuf_remove_resource();
 }
 
 static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr,
@@ -1710,13 +1710,13 @@ vhost_user_backend_handle_shared_object_lookup(struct 
vhost_user *u,
 memcpy(uuid.data, payload->object.uuid, sizeof(payload->object.uuid));
 
 payload->u64 = 0;
-switch (virtio_object_type()) {
+switch (virtio_dmabuf_object_type()) {
 case TYPE_DMABUF:
-dmabuf_fd = virtio_lookup_dmabuf();
+dmabuf_fd = virtio_dmabuf_lookup();
 break;
 case TYPE_VHOST_DEV:
 {
-struct vhost_dev *dev = virtio_lookup_vhost_device();
+struct vhost_dev *dev = virtio_dmabuf_lookup_vhost_device();
 if (dev == NULL) {
 payload->u64 = -EINVAL;
 break;
diff --git a/include/hw/virtio/virtio-dmabuf.h 
b/include/hw/virtio/virtio-dmabuf.h
index 73f70fb482..186a18a33b 100644
--- a/include/hw/virtio/virtio-dmabuf.h
+++ b/include/hw/virtio/virtio-dmabuf.h
@@

[PATCH v3 2/3] hw/virtio: cleanup shared resources

2024-01-09 Thread Albert Esteve
Ensure that we cleanup all virtio shared
resources when the vhost devices is cleaned
up (after a hot unplug, or a crash).

To do so, we add a new function to the virtio_dmabuf
API called `virtio_dmabuf_vhost_cleanup`, which
loop through the table and removes all
resources owned by the vhost device parameter.

Also, add a test to verify that the new
function in the API behaves as expected.

Signed-off-by: Albert Esteve 
Acked-by: Stefan Hajnoczi 
---
 hw/display/virtio-dmabuf.c| 22 +
 hw/virtio/vhost.c |  3 +++
 include/hw/virtio/virtio-dmabuf.h | 10 ++
 tests/unit/test-virtio-dmabuf.c   | 33 +++
 4 files changed, 68 insertions(+)

diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
index 3dba4577ca..6688809777 100644
--- a/hw/display/virtio-dmabuf.c
+++ b/hw/display/virtio-dmabuf.c
@@ -136,6 +136,28 @@ SharedObjectType virtio_object_type(const QemuUUID *uuid)
 return vso->type;
 }
 
+static bool virtio_dmabuf_resource_is_owned(gpointer key,
+gpointer value,
+gpointer dev)
+{
+VirtioSharedObject *vso;
+
+vso = (VirtioSharedObject *) value;
+return vso->type == TYPE_VHOST_DEV && vso->value == dev;
+}
+
+int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev)
+{
+int num_removed;
+
+g_mutex_lock();
+num_removed = g_hash_table_foreach_remove(
+resource_uuids, (GHRFunc) virtio_dmabuf_resource_is_owned, dev);
+g_mutex_unlock();
+
+return num_removed;
+}
+
 void virtio_free_resources(void)
 {
 g_mutex_lock();
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 2c9ac79468..c5622eac14 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -16,6 +16,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "hw/virtio/vhost.h"
+#include "hw/virtio/virtio-dmabuf.h"
 #include "qemu/atomic.h"
 #include "qemu/range.h"
 #include "qemu/error-report.h"
@@ -1599,6 +1600,8 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
 migrate_del_blocker(>migration_blocker);
 g_free(hdev->mem);
 g_free(hdev->mem_sections);
+/* free virtio shared objects */
+virtio_dmabuf_vhost_cleanup(hdev);
 if (hdev->vhost_ops) {
 hdev->vhost_ops->vhost_backend_cleanup(hdev);
 }
diff --git a/include/hw/virtio/virtio-dmabuf.h 
b/include/hw/virtio/virtio-dmabuf.h
index 627c3b6db7..73f70fb482 100644
--- a/include/hw/virtio/virtio-dmabuf.h
+++ b/include/hw/virtio/virtio-dmabuf.h
@@ -91,6 +91,16 @@ struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID 
*uuid);
  */
 SharedObjectType virtio_object_type(const QemuUUID *uuid);
 
+/**
+ * virtio_dmabuf_vhost_cleanup() - Destroys all entries of the shared
+ * resources lookup table that are owned by the vhost backend
+ * @dev: the pointer to the vhost device that owns the entries. Data is owned
+ *   by the called of the function.
+ * 
+ * Return: the number of resource entries removed.
+ */
+int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev);
+
 /**
  * virtio_free_resources() - Destroys all keys and values of the shared
  * resources lookup table, and frees them
diff --git a/tests/unit/test-virtio-dmabuf.c b/tests/unit/test-virtio-dmabuf.c
index a45ec52f42..1c8123c2d2 100644
--- a/tests/unit/test-virtio-dmabuf.c
+++ b/tests/unit/test-virtio-dmabuf.c
@@ -103,6 +103,38 @@ static void test_add_invalid_resource(void)
 }
 }
 
+static void test_cleanup_res(void)
+{
+QemuUUID uuids[20], uuid_alt;
+struct vhost_dev *dev = g_new0(struct vhost_dev, 1);
+struct vhost_dev *dev_alt = g_new0(struct vhost_dev, 1);
+int i, num_removed;
+
+for (i = 0; i < ARRAY_SIZE(uuids); ++i) {
+qemu_uuid_generate([i]);
+virtio_add_vhost_device([i], dev);
+/* vhost device is found */
+g_assert(virtio_lookup_vhost_device([i]) != NULL);
+}
+qemu_uuid_generate(_alt);
+virtio_add_vhost_device(_alt, dev_alt);
+/* vhost device is found */
+g_assert(virtio_lookup_vhost_device(_alt) != NULL);
+/* cleanup all dev resources */
+num_removed = virtio_dmabuf_vhost_cleanup(dev);
+g_assert_cmpint(num_removed, ==, ARRAY_SIZE(uuids));
+for (i = 0; i < ARRAY_SIZE(uuids); ++i) {
+/* None of the dev resources is found after free'd */
+g_assert_cmpint(virtio_lookup_dmabuf([i]), ==, -1);
+}
+/* uuid_alt is still in the hash table */
+g_assert(virtio_lookup_vhost_device(_alt) != NULL);
+
+virtio_free_resources();
+g_free(dev);
+g_free(dev_alt);
+}
+
 static void test_free_resources(void)
 {
 QemuUUID uuids[20];
@@ -131,6 +163,7 @@ int main(int argc, char **argv)
 test_remove_invalid_resource);
 g_test_add_func("/virtio-dmabuf/add_invalid_res",
 test_add_invalid_resou

[PATCH v3 0/3] Virtio dmabuf improvements

2024-01-09 Thread Albert Esteve
v1: https://www.mail-archive.com/qemu-devel@nongnu.org/msg1005257.html
v2: https://www.mail-archive.com/qemu-devel@nongnu.org/msg1014615.html
v2 -> v3
  - Documented the new owner check for shared object removal
  - Updated test function names error in the last patch

Various improvements for the virtio-dmabuf module.
This patch includes:

- Check for ownership before allowing a vhost device
  to remove an object from the table.
- Properly cleanup shared resources if a vhost device
  object gets cleaned up.
- Rename virtio dmabuf functions to `virtio_dmabuf_*`

Albert Esteve (3):
  hw/virtio: check owner for removing objects
  hw/virtio: cleanup shared resources
  hw/virtio: rename virtio dmabuf API

 docs/interop/vhost-user.rst   |  4 +-
 hw/display/virtio-dmabuf.c| 36 ---
 hw/virtio/vhost-user.c| 31 ++---
 hw/virtio/vhost.c |  3 ++
 include/hw/virtio/virtio-dmabuf.h | 43 ++---
 tests/unit/test-virtio-dmabuf.c   | 77 ++-
 6 files changed, 141 insertions(+), 53 deletions(-)

-- 
2.43.0




Re: [PATCH v2 0/3] Virtio dmabuf improvements

2024-01-08 Thread Albert Esteve
On Mon, Dec 11, 2023 at 10:48 PM Stefan Hajnoczi  wrote:

> On Thu, 7 Dec 2023 at 09:55, Albert Esteve  wrote:
> >
> > v1: https://www.mail-archive.com/qemu-devel@nongnu.org/msg1005257.html
> > v1 -> v2:
> >   - Solved an unitialized uuid value on vhost-user source
> >   - Changed cleanup strategy, and traverse all objects in the
> > table to remove them instead.
>
> Please update the vhost-user specification
> (docs/interop/vhost-user.rst) so people implementing front-ends and
> back-ends are aware that only the back-end that added a shared
> resource can remove it.
>
> Acked-by: Stefan Hajnoczi 
>
>
Will do :)

Should I add the `Acked-by` manually to the commits or does it
get automatically picked up later?

BR,
Albert

PS: Happy New Year!


> >
> > Various improvements for the virtio-dmabuf module.
> > This patch includes:
> >
> > - Check for ownership before allowing a vhost device
> >   to remove an object from the table.
> > - Properly cleanup shared resources if a vhost device
> >   object gets cleaned up.
> > - Rename virtio dmabuf functions to `virtio_dmabuf_*`
> >
> > Albert Esteve (3):
> >   hw/virtio: check owner for removing objects
> >   hw/virtio: cleanup shared resources
> >   hw/virtio: rename virtio dmabuf API
> >
> >  hw/display/virtio-dmabuf.c| 36 ---
> >  hw/virtio/vhost-user.c| 31 ++---
> >  hw/virtio/vhost.c |  3 ++
> >  include/hw/virtio/virtio-dmabuf.h | 43 ++---
> >  tests/unit/test-virtio-dmabuf.c   | 77 ++-
> >  5 files changed, 138 insertions(+), 52 deletions(-)
> >
> > --
> > 2.43.0
> >
>
>


Re: [PATCH v2 3/3] hw/virtio: rename virtio dmabuf API

2023-12-07 Thread Albert Esteve
On Thu, Dec 7, 2023 at 3:55 PM Albert Esteve  wrote:

> Functions in the virtio-dmabuf module
> start with 'virtio_*', which is too
> generic and may not correctly identify
> them as part of the virtio dmabuf API.
>
> Rename all functions to 'virtio_dmabuf_*'
> instead to avoid confusion.
>
> Signed-off-by: Albert Esteve 
> ---
>  hw/display/virtio-dmabuf.c| 14 +-
>  hw/virtio/vhost-user.c| 14 +-
>  include/hw/virtio/virtio-dmabuf.h | 33 ---
>  tests/unit/test-virtio-dmabuf.c   | 44 +++
>  4 files changed, 53 insertions(+), 52 deletions(-)
>
> diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
> index 6688809777..42495f87ec 100644
> --- a/hw/display/virtio-dmabuf.c
> +++ b/hw/display/virtio-dmabuf.c
> @@ -48,7 +48,7 @@ static bool virtio_add_resource(QemuUUID *uuid,
> VirtioSharedObject *value)
>  return result;
>  }
>
> -bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
> +bool virtio_dmabuf_add(QemuUUID *uuid, int udmabuf_fd)
>  {
>  bool result;
>  VirtioSharedObject *vso;
> @@ -66,7 +66,7 @@ bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
>  return result;
>  }
>
> -bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
> +bool virtio_dmabuf_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
>  {
>  bool result;
>  VirtioSharedObject *vso;
> @@ -84,7 +84,7 @@ bool virtio_add_vhost_device(QemuUUID *uuid, struct
> vhost_dev *dev)
>  return result;
>  }
>
> -bool virtio_remove_resource(const QemuUUID *uuid)
> +bool virtio_dmabuf_remove_resource(const QemuUUID *uuid)
>  {
>  bool result;
>  g_mutex_lock();
> @@ -107,7 +107,7 @@ static VirtioSharedObject *get_shared_object(const
> QemuUUID *uuid)
>  return (VirtioSharedObject *) lookup_res;
>  }
>
> -int virtio_lookup_dmabuf(const QemuUUID *uuid)
> +int virtio_dmabuf_lookup(const QemuUUID *uuid)
>  {
>  VirtioSharedObject *vso = get_shared_object(uuid);
>  if (vso == NULL) {
> @@ -117,7 +117,7 @@ int virtio_lookup_dmabuf(const QemuUUID *uuid)
>  return GPOINTER_TO_INT(vso->value);
>  }
>
> -struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
> +struct vhost_dev *virtio_dmabuf_lookup_vhost_device(const QemuUUID *uuid)
>  {
>  VirtioSharedObject *vso = get_shared_object(uuid);
>  if (vso == NULL) {
> @@ -127,7 +127,7 @@ struct vhost_dev *virtio_lookup_vhost_device(const
> QemuUUID *uuid)
>  return (struct vhost_dev *) vso->value;
>  }
>
> -SharedObjectType virtio_object_type(const QemuUUID *uuid)
> +SharedObjectType virtio_dmabuf_object_type(const QemuUUID *uuid)
>  {
>  VirtioSharedObject *vso = get_shared_object(uuid);
>  if (vso == NULL) {
> @@ -158,7 +158,7 @@ int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev)
>  return num_removed;
>  }
>
> -void virtio_free_resources(void)
> +void virtio_dmabuf_free_resources(void)
>  {
>  g_mutex_lock();
>  g_hash_table_destroy(resource_uuids);
> diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
> index 1c3f2357be..2ab9e13f9e 100644
> --- a/hw/virtio/vhost-user.c
> +++ b/hw/virtio/vhost-user.c
> @@ -1607,7 +1607,7 @@ vhost_user_backend_handle_shared_object_add(struct
> vhost_dev *dev,
>  QemuUUID uuid;
>
>  memcpy(uuid.data, object->uuid, sizeof(object->uuid));
> -return virtio_add_vhost_device(, dev);
> +return virtio_dmabuf_add_vhost_device(, dev);
>  }
>
>  static int
> @@ -1617,10 +1617,10 @@
> vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
>  QemuUUID uuid;
>
>  memcpy(uuid.data, object->uuid, sizeof(object->uuid));
> -switch (virtio_object_type()) {
> +switch (virtio_dmabuf_object_type()) {
>  case TYPE_VHOST_DEV:
>  {
> -struct vhost_dev *owner = virtio_lookup_vhost_device();
> +struct vhost_dev *owner =
> virtio_dmabuf_lookup_vhost_device();
>  if (owner == NULL || dev != owner) {
>  /* Not allowed to remove non-owned entries */
>  return 0;
> @@ -1632,7 +1632,7 @@
> vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
>  return 0;
>  }
>
> -return virtio_remove_resource();
> +return virtio_dmabuf_remove_resource();
>  }
>
>  static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr,
> @@ -1710,13 +1710,13 @@
> vhost_user_backend_handle_shared_object_lookup(struct vhost_user *u,
>  memcpy(uuid.data, payload->object.uuid, sizeof(payload->object.uuid));
>
>  payload->u64 = 0;
&g

[PATCH v2 3/3] hw/virtio: rename virtio dmabuf API

2023-12-07 Thread Albert Esteve
Functions in the virtio-dmabuf module
start with 'virtio_*', which is too
generic and may not correctly identify
them as part of the virtio dmabuf API.

Rename all functions to 'virtio_dmabuf_*'
instead to avoid confusion.

Signed-off-by: Albert Esteve 
---
 hw/display/virtio-dmabuf.c| 14 +-
 hw/virtio/vhost-user.c| 14 +-
 include/hw/virtio/virtio-dmabuf.h | 33 ---
 tests/unit/test-virtio-dmabuf.c   | 44 +++
 4 files changed, 53 insertions(+), 52 deletions(-)

diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
index 6688809777..42495f87ec 100644
--- a/hw/display/virtio-dmabuf.c
+++ b/hw/display/virtio-dmabuf.c
@@ -48,7 +48,7 @@ static bool virtio_add_resource(QemuUUID *uuid, 
VirtioSharedObject *value)
 return result;
 }
 
-bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
+bool virtio_dmabuf_add(QemuUUID *uuid, int udmabuf_fd)
 {
 bool result;
 VirtioSharedObject *vso;
@@ -66,7 +66,7 @@ bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
 return result;
 }
 
-bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
+bool virtio_dmabuf_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
 {
 bool result;
 VirtioSharedObject *vso;
@@ -84,7 +84,7 @@ bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev 
*dev)
 return result;
 }
 
-bool virtio_remove_resource(const QemuUUID *uuid)
+bool virtio_dmabuf_remove_resource(const QemuUUID *uuid)
 {
 bool result;
 g_mutex_lock();
@@ -107,7 +107,7 @@ static VirtioSharedObject *get_shared_object(const QemuUUID 
*uuid)
 return (VirtioSharedObject *) lookup_res;
 }
 
-int virtio_lookup_dmabuf(const QemuUUID *uuid)
+int virtio_dmabuf_lookup(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -117,7 +117,7 @@ int virtio_lookup_dmabuf(const QemuUUID *uuid)
 return GPOINTER_TO_INT(vso->value);
 }
 
-struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
+struct vhost_dev *virtio_dmabuf_lookup_vhost_device(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -127,7 +127,7 @@ struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID 
*uuid)
 return (struct vhost_dev *) vso->value;
 }
 
-SharedObjectType virtio_object_type(const QemuUUID *uuid)
+SharedObjectType virtio_dmabuf_object_type(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -158,7 +158,7 @@ int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev)
 return num_removed;
 }
 
-void virtio_free_resources(void)
+void virtio_dmabuf_free_resources(void)
 {
 g_mutex_lock();
 g_hash_table_destroy(resource_uuids);
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 1c3f2357be..2ab9e13f9e 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1607,7 +1607,7 @@ vhost_user_backend_handle_shared_object_add(struct 
vhost_dev *dev,
 QemuUUID uuid;
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
-return virtio_add_vhost_device(, dev);
+return virtio_dmabuf_add_vhost_device(, dev);
 }
 
 static int
@@ -1617,10 +1617,10 @@ vhost_user_backend_handle_shared_object_remove(struct 
vhost_dev *dev,
 QemuUUID uuid;
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
-switch (virtio_object_type()) {
+switch (virtio_dmabuf_object_type()) {
 case TYPE_VHOST_DEV:
 {
-struct vhost_dev *owner = virtio_lookup_vhost_device();
+struct vhost_dev *owner = virtio_dmabuf_lookup_vhost_device();
 if (owner == NULL || dev != owner) {
 /* Not allowed to remove non-owned entries */
 return 0;
@@ -1632,7 +1632,7 @@ vhost_user_backend_handle_shared_object_remove(struct 
vhost_dev *dev,
 return 0;
 }
 
-return virtio_remove_resource();
+return virtio_dmabuf_remove_resource();
 }
 
 static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr,
@@ -1710,13 +1710,13 @@ vhost_user_backend_handle_shared_object_lookup(struct 
vhost_user *u,
 memcpy(uuid.data, payload->object.uuid, sizeof(payload->object.uuid));
 
 payload->u64 = 0;
-switch (virtio_object_type()) {
+switch (virtio_dmabuf_object_type()) {
 case TYPE_DMABUF:
-dmabuf_fd = virtio_lookup_dmabuf();
+dmabuf_fd = virtio_dmabuf_lookup();
 break;
 case TYPE_VHOST_DEV:
 {
-struct vhost_dev *dev = virtio_lookup_vhost_device();
+struct vhost_dev *dev = virtio_dmabuf_lookup_vhost_device();
 if (dev == NULL) {
 payload->u64 = -EINVAL;
 break;
diff --git a/include/hw/virtio/virtio-dmabuf.h 
b/include/hw/virtio/virtio-dmabuf.h
index 73f70fb482..186a18a33b 100644
--- a/include/hw/virtio/virtio-dmabuf.h
+++ b/include/hw/virtio/virtio-dmabuf.h
@@ -28,7 +28,7 @@ typ

[PATCH v2 0/3] Virtio dmabuf improvements

2023-12-07 Thread Albert Esteve
v1: https://www.mail-archive.com/qemu-devel@nongnu.org/msg1005257.html
v1 -> v2:
  - Solved an unitialized uuid value on vhost-user source
  - Changed cleanup strategy, and traverse all objects in the
table to remove them instead.

Various improvements for the virtio-dmabuf module.
This patch includes:

- Check for ownership before allowing a vhost device
  to remove an object from the table.
- Properly cleanup shared resources if a vhost device
  object gets cleaned up.
- Rename virtio dmabuf functions to `virtio_dmabuf_*`

Albert Esteve (3):
  hw/virtio: check owner for removing objects
  hw/virtio: cleanup shared resources
  hw/virtio: rename virtio dmabuf API

 hw/display/virtio-dmabuf.c| 36 ---
 hw/virtio/vhost-user.c| 31 ++---
 hw/virtio/vhost.c |  3 ++
 include/hw/virtio/virtio-dmabuf.h | 43 ++---
 tests/unit/test-virtio-dmabuf.c   | 77 ++-
 5 files changed, 138 insertions(+), 52 deletions(-)

-- 
2.43.0




[PATCH v2 1/3] hw/virtio: check owner for removing objects

2023-12-07 Thread Albert Esteve
Shared objects lack spoofing protection.
For VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE messages
received by the vhost-user interface, any backend was
allowed to remove entries from the shared table just
by knowing the UUID. Only the owner of the entry
shall be allowed to removed their resources
from the table.

To fix that, add a check for all
*SHARED_OBJECT_REMOVE messages received.
A vhost device can only remove TYPE_VHOST_DEV
entries that are owned by them, otherwise skip
the removal, and inform the device that the entry
has not been removed in the answer.

Signed-off-by: Albert Esteve 
---
 hw/virtio/vhost-user.c | 21 +++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index f214df804b..1c3f2357be 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1611,11 +1611,27 @@ vhost_user_backend_handle_shared_object_add(struct 
vhost_dev *dev,
 }
 
 static int
-vhost_user_backend_handle_shared_object_remove(VhostUserShared *object)
+vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
+   VhostUserShared *object)
 {
 QemuUUID uuid;
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
+switch (virtio_object_type()) {
+case TYPE_VHOST_DEV:
+{
+struct vhost_dev *owner = virtio_lookup_vhost_device();
+if (owner == NULL || dev != owner) {
+/* Not allowed to remove non-owned entries */
+return 0;
+}
+break;
+}
+default:
+/* Not allowed to remove non-owned entries */
+return 0;
+}
+
 return virtio_remove_resource();
 }
 
@@ -1794,7 +1810,8 @@ static gboolean backend_read(QIOChannel *ioc, 
GIOCondition condition,
 ret = vhost_user_backend_handle_shared_object_add(dev, 
);
 break;
 case VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE:
-ret = vhost_user_backend_handle_shared_object_remove();
+ret = vhost_user_backend_handle_shared_object_remove(dev,
+ );
 break;
 case VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP:
 ret = vhost_user_backend_handle_shared_object_lookup(dev->opaque, ioc,
-- 
2.43.0




[PATCH v2 2/3] hw/virtio: cleanup shared resources

2023-12-07 Thread Albert Esteve
Ensure that we cleanup all virtio shared
resources when the vhost devices is cleaned
up (after a hot unplug, or a crash).

To do so, we add a new function to the virtio_dmabuf
API called `virtio_dmabuf_vhost_cleanup`, which
loop through the table and removes all
resources owned by the vhost device parameter.

Also, add a test to verify that the new
function in the API behaves as expected.

Signed-off-by: Albert Esteve 
---
 hw/display/virtio-dmabuf.c| 22 +
 hw/virtio/vhost.c |  3 +++
 include/hw/virtio/virtio-dmabuf.h | 10 ++
 tests/unit/test-virtio-dmabuf.c   | 33 +++
 4 files changed, 68 insertions(+)

diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
index 3dba4577ca..6688809777 100644
--- a/hw/display/virtio-dmabuf.c
+++ b/hw/display/virtio-dmabuf.c
@@ -136,6 +136,28 @@ SharedObjectType virtio_object_type(const QemuUUID *uuid)
 return vso->type;
 }
 
+static bool virtio_dmabuf_resource_is_owned(gpointer key,
+gpointer value,
+gpointer dev)
+{
+VirtioSharedObject *vso;
+
+vso = (VirtioSharedObject *) value;
+return vso->type == TYPE_VHOST_DEV && vso->value == dev;
+}
+
+int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev)
+{
+int num_removed;
+
+g_mutex_lock();
+num_removed = g_hash_table_foreach_remove(
+resource_uuids, (GHRFunc) virtio_dmabuf_resource_is_owned, dev);
+g_mutex_unlock();
+
+return num_removed;
+}
+
 void virtio_free_resources(void)
 {
 g_mutex_lock();
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 2c9ac79468..c5622eac14 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -16,6 +16,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "hw/virtio/vhost.h"
+#include "hw/virtio/virtio-dmabuf.h"
 #include "qemu/atomic.h"
 #include "qemu/range.h"
 #include "qemu/error-report.h"
@@ -1599,6 +1600,8 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
 migrate_del_blocker(>migration_blocker);
 g_free(hdev->mem);
 g_free(hdev->mem_sections);
+/* free virtio shared objects */
+virtio_dmabuf_vhost_cleanup(hdev);
 if (hdev->vhost_ops) {
 hdev->vhost_ops->vhost_backend_cleanup(hdev);
 }
diff --git a/include/hw/virtio/virtio-dmabuf.h 
b/include/hw/virtio/virtio-dmabuf.h
index 627c3b6db7..73f70fb482 100644
--- a/include/hw/virtio/virtio-dmabuf.h
+++ b/include/hw/virtio/virtio-dmabuf.h
@@ -91,6 +91,16 @@ struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID 
*uuid);
  */
 SharedObjectType virtio_object_type(const QemuUUID *uuid);
 
+/**
+ * virtio_dmabuf_vhost_cleanup() - Destroys all entries of the shared
+ * resources lookup table that are owned by the vhost backend
+ * @dev: the pointer to the vhost device that owns the entries. Data is owned
+ *   by the called of the function.
+ * 
+ * Return: the number of resource entries removed.
+ */
+int virtio_dmabuf_vhost_cleanup(struct vhost_dev *dev);
+
 /**
  * virtio_free_resources() - Destroys all keys and values of the shared
  * resources lookup table, and frees them
diff --git a/tests/unit/test-virtio-dmabuf.c b/tests/unit/test-virtio-dmabuf.c
index a45ec52f42..1c8123c2d2 100644
--- a/tests/unit/test-virtio-dmabuf.c
+++ b/tests/unit/test-virtio-dmabuf.c
@@ -103,6 +103,38 @@ static void test_add_invalid_resource(void)
 }
 }
 
+static void test_cleanup_res(void)
+{
+QemuUUID uuids[20], uuid_alt;
+struct vhost_dev *dev = g_new0(struct vhost_dev, 1);
+struct vhost_dev *dev_alt = g_new0(struct vhost_dev, 1);
+int i, num_removed;
+
+for (i = 0; i < ARRAY_SIZE(uuids); ++i) {
+qemu_uuid_generate([i]);
+virtio_add_vhost_device([i], dev);
+/* vhost device is found */
+g_assert(virtio_lookup_vhost_device([i]) != NULL);
+}
+qemu_uuid_generate(_alt);
+virtio_add_vhost_device(_alt, dev_alt);
+/* vhost device is found */
+g_assert(virtio_lookup_vhost_device(_alt) != NULL);
+/* cleanup all dev resources */
+num_removed = virtio_dmabuf_vhost_cleanup(dev);
+g_assert_cmpint(num_removed, ==, ARRAY_SIZE(uuids));
+for (i = 0; i < ARRAY_SIZE(uuids); ++i) {
+/* None of the dev resources is found after free'd */
+g_assert_cmpint(virtio_lookup_dmabuf([i]), ==, -1);
+}
+/* uuid_alt is still in the hash table */
+g_assert(virtio_lookup_vhost_device(_alt) != NULL);
+
+virtio_free_resources();
+g_free(dev);
+g_free(dev_alt);
+}
+
 static void test_free_resources(void)
 {
 QemuUUID uuids[20];
@@ -131,6 +163,7 @@ int main(int argc, char **argv)
 test_remove_invalid_resource);
 g_test_add_func("/virtio-dmabuf/add_invalid_res",
 test_add_invalid_resource);
+g_test_add_

Re: [PATCH 2/3] hw/virtio: cleanup shared resources

2023-12-07 Thread Albert Esteve
On Mon, Dec 4, 2023 at 9:00 AM Marc-André Lureau 
wrote:

> Hi
>
> On Tue, Nov 7, 2023 at 1:37 PM Albert Esteve  wrote:
> >
> > Ensure that we cleanup all virtio shared
> > resources when the vhost devices is cleaned
> > up (after a hot unplug, or a crash).
> >
> > To track all owned uuids of a device, add
> > a GSList to the vhost_dev struct. This way
> > we can avoid traversing the full table
> > for every cleanup, whether they actually
> > own any shared resource or not.
> >
> > Signed-off-by: Albert Esteve 
> > ---
> >  hw/virtio/vhost-user.c| 2 ++
> >  hw/virtio/vhost.c | 4 
> >  include/hw/virtio/vhost.h | 6 ++
> >  3 files changed, 12 insertions(+)
> >
> > diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
> > index 5fdff0241f..04848d1fa0 100644
> > --- a/hw/virtio/vhost-user.c
> > +++ b/hw/virtio/vhost-user.c
> > @@ -1598,6 +1598,7 @@ vhost_user_backend_handle_shared_object_add(struct
> vhost_dev *dev,
> >  QemuUUID uuid;
> >
> >  memcpy(uuid.data, object->uuid, sizeof(object->uuid));
> > +dev->shared_uuids = g_slist_append(dev->shared_uuids, );
>
> This will point to the stack variable.
>
> >  return virtio_add_vhost_device(, dev);
> >  }
> >
> > @@ -1623,6 +1624,7 @@
> vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
> >  }
> >
> >  memcpy(uuid.data, object->uuid, sizeof(object->uuid));
> > +dev->shared_uuids = g_slist_remove_all(dev->shared_uuids, );
> >  return virtio_remove_resource();
> >  }
> >
> > diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
> > index 9c9ae7109e..3aff94664b 100644
> > --- a/hw/virtio/vhost.c
> > +++ b/hw/virtio/vhost.c
> > @@ -16,6 +16,7 @@
> >  #include "qemu/osdep.h"
> >  #include "qapi/error.h"
> >  #include "hw/virtio/vhost.h"
> > +#include "hw/virtio/virtio-dmabuf.h"
> >  #include "qemu/atomic.h"
> >  #include "qemu/range.h"
> >  #include "qemu/error-report.h"
> > @@ -1599,6 +1600,9 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
> >  migrate_del_blocker(>migration_blocker);
> >  g_free(hdev->mem);
> >  g_free(hdev->mem_sections);
> > +/* free virtio shared objects */
> > +g_slist_foreach(hdev->shared_uuids, (GFunc)virtio_remove_resource,
> NULL);
> > +g_slist_free_full(g_steal_pointer(>shared_uuids), g_free);
>
> (and will crash here)
>
> Imho, you should just traverse the hashtable, instead of introducing
> another list.
>

Ok, I was probably doing premature optimization. I guess it should
not happen as often, or track as many resources, as to require
a separate list. I will just traverse.

Thanks!


>
> >  if (hdev->vhost_ops) {
> >  hdev->vhost_ops->vhost_backend_cleanup(hdev);
> >  }
> > diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
> > index 5e8183f64a..376bc8446d 100644
> > --- a/include/hw/virtio/vhost.h
> > +++ b/include/hw/virtio/vhost.h
> > @@ -118,6 +118,12 @@ struct vhost_dev {
> >   */
> >  uint64_t protocol_features;
> >
> > +/**
> > + * @shared_uuids: contains the UUIDs of all the exported
> > + * virtio objects owned by the vhost device.
> > + */
> > +GSList *shared_uuids;
> > +
> >  uint64_t max_queues;
> >  uint64_t backend_cap;
> >  /* @started: is the vhost device started? */
> > --
> > 2.41.0
> >
>
>
> --
> Marc-André Lureau
>
>


Re: [PATCH 1/3] hw/virtio: check owner for removing objects

2023-12-07 Thread Albert Esteve
On Mon, Dec 4, 2023 at 8:54 AM Marc-André Lureau 
wrote:

> On Tue, Nov 7, 2023 at 1:37 PM Albert Esteve  wrote:
> >
> > Shared objects lack spoofing protection.
> > For VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE messages
> > received by the vhost-user interface, any backend was
> > allowed to remove entries from the shared table just
> > by knowing the UUID. Only the owner of the entry
> > shall be allowed to removed their resources
> > from the table.
> >
> > To fix that, add a check for all
> > *SHARED_OBJECT_REMOVE messages received.
> > A vhost device can only remove TYPE_VHOST_DEV
> > entries that are owned by them, otherwise skip
> > the removal, and inform the device that the entry
> > has not been removed in the answer.
> >
> > Signed-off-by: Albert Esteve 
> > ---
> >  hw/virtio/vhost-user.c | 21 +++--
> >  1 file changed, 19 insertions(+), 2 deletions(-)
> >
> > diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
> > index 7b42ae8aae..5fdff0241f 100644
> > --- a/hw/virtio/vhost-user.c
> > +++ b/hw/virtio/vhost-user.c
> > @@ -1602,10 +1602,26 @@
> vhost_user_backend_handle_shared_object_add(struct vhost_dev *dev,
> >  }
> >
> >  static int
> > -vhost_user_backend_handle_shared_object_remove(VhostUserShared *object)
> > +vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
> > +   VhostUserShared *object)
> >  {
> >  QemuUUID uuid;
> >
> > +switch (virtio_object_type()) {
>
> ../hw/virtio/vhost-user.c:1619:13: error: ‘uuid’ may be used
> uninitialized [-Werror=maybe-uninitialized]
>  1619 | switch (virtio_object_type()) {
>   | ^
>
>
Oops I didn't notice this. Maybe I am missing the
`Werror` flag when I compile locally. I'll fix it.


> > +case TYPE_VHOST_DEV:
> > +{
> > +struct vhost_dev *owner = virtio_lookup_vhost_device();
> > +if (owner == NULL || dev != owner) {
> > +/* Not allowed to remove non-owned entries */
> > +return 0;
> > +}
> > +break;
> > +}
> > +default:
> > +/* Not allowed to remove non-owned entries */
> > +return 0;
>
> How do you remove TYPE_DMABUF entries after this patch?
>
>
TYPE_DMABUF are meant for virtio devices that run with Qemu
(i.e., not vhost). So owners will not send these messages, but
access the hash table directly.


> > +}
> > +
> >  memcpy(uuid.data, object->uuid, sizeof(object->uuid));
> >  return virtio_remove_resource();
> >  }
> > @@ -1785,7 +1801,8 @@ static gboolean backend_read(QIOChannel *ioc,
> GIOCondition condition,
> >  ret = vhost_user_backend_handle_shared_object_add(dev,
> );
> >  break;
> >  case VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE:
> > -ret =
> vhost_user_backend_handle_shared_object_remove();
> > +ret = vhost_user_backend_handle_shared_object_remove(dev,
> > +
>  );
> >  break;
> >  case VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP:
> >  ret =
> vhost_user_backend_handle_shared_object_lookup(dev->opaque, ioc,
> > --
> > 2.41.0
> >
>
>
> --
> Marc-André Lureau
>
>


Re: [PATCH 0/3] Virtio dmabuf improvements

2023-12-04 Thread Albert Esteve
On Mon, Dec 4, 2023 at 9:50 AM Michael S. Tsirkin  wrote:

> On Thu, Nov 30, 2023 at 04:49:35PM +0100, Albert Esteve wrote:
> >
> >
> >
> > On Tue, Nov 7, 2023 at 10:37 AM Albert Esteve 
> wrote:
> >
> > Various improvements for the virtio-dmabuf module.
> > This patch includes:
> >
> > - Check for ownership before allowing a vhost device
> >   to remove an object from the table.
> > - Properly cleanup shared resources if a vhost device
> >   object gets cleaned up.
> > - Rename virtio dmabuf functions to `virtio_dmabuf_*`
> >
> > Albert Esteve (3):
> >   hw/virtio: check owner for removing objects
> >   hw/virtio: cleanup shared resources
> >   hw/virtio: rename virtio dmabuf API
> >
> >  hw/display/virtio-dmabuf.c| 14 +-
> >  hw/virtio/vhost-user.c| 33 ++-
> >  hw/virtio/vhost.c |  5 
> >  include/hw/virtio/vhost.h |  6 +
> >  include/hw/virtio/virtio-dmabuf.h | 33 ---
> >  tests/unit/test-virtio-dmabuf.c   | 44
> +++
> >  6 files changed, 83 insertions(+), 52 deletions(-)
> >
> > --
> > 2.41.0
> >
> >
> >
> > Bump :)
> >
> > @Marc-André Lureau could you please take a look? You suggested the API
> > upgrades, so would be great if you could check if it is what you had in
> mind.
> >
> > Thanks!
>
> All this is post releas material, right?
>
>
Yes, it is.


Re: [PATCH 0/3] Virtio dmabuf improvements

2023-11-30 Thread Albert Esteve
On Tue, Nov 7, 2023 at 10:37 AM Albert Esteve  wrote:

> Various improvements for the virtio-dmabuf module.
> This patch includes:
>
> - Check for ownership before allowing a vhost device
>   to remove an object from the table.
> - Properly cleanup shared resources if a vhost device
>   object gets cleaned up.
> - Rename virtio dmabuf functions to `virtio_dmabuf_*`
>
> Albert Esteve (3):
>   hw/virtio: check owner for removing objects
>   hw/virtio: cleanup shared resources
>   hw/virtio: rename virtio dmabuf API
>
>  hw/display/virtio-dmabuf.c| 14 +-
>  hw/virtio/vhost-user.c| 33 ++-
>  hw/virtio/vhost.c |  5 
>  include/hw/virtio/vhost.h |  6 +
>  include/hw/virtio/virtio-dmabuf.h | 33 ---
>  tests/unit/test-virtio-dmabuf.c   | 44 +++
>  6 files changed, 83 insertions(+), 52 deletions(-)
>
> --
> 2.41.0
>
>
Bump :)

@Marc-André Lureau  could you please take a
look? You suggested the API upgrades, so would be great if you could check
if it is what you had in mind.

Thanks!


[PATCH 2/3] hw/virtio: cleanup shared resources

2023-11-07 Thread Albert Esteve
Ensure that we cleanup all virtio shared
resources when the vhost devices is cleaned
up (after a hot unplug, or a crash).

To track all owned uuids of a device, add
a GSList to the vhost_dev struct. This way
we can avoid traversing the full table
for every cleanup, whether they actually
own any shared resource or not.

Signed-off-by: Albert Esteve 
---
 hw/virtio/vhost-user.c| 2 ++
 hw/virtio/vhost.c | 4 
 include/hw/virtio/vhost.h | 6 ++
 3 files changed, 12 insertions(+)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 5fdff0241f..04848d1fa0 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1598,6 +1598,7 @@ vhost_user_backend_handle_shared_object_add(struct 
vhost_dev *dev,
 QemuUUID uuid;
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
+dev->shared_uuids = g_slist_append(dev->shared_uuids, );
 return virtio_add_vhost_device(, dev);
 }
 
@@ -1623,6 +1624,7 @@ vhost_user_backend_handle_shared_object_remove(struct 
vhost_dev *dev,
 }
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
+dev->shared_uuids = g_slist_remove_all(dev->shared_uuids, );
 return virtio_remove_resource();
 }
 
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 9c9ae7109e..3aff94664b 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -16,6 +16,7 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "hw/virtio/vhost.h"
+#include "hw/virtio/virtio-dmabuf.h"
 #include "qemu/atomic.h"
 #include "qemu/range.h"
 #include "qemu/error-report.h"
@@ -1599,6 +1600,9 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
 migrate_del_blocker(>migration_blocker);
 g_free(hdev->mem);
 g_free(hdev->mem_sections);
+/* free virtio shared objects */
+g_slist_foreach(hdev->shared_uuids, (GFunc)virtio_remove_resource, NULL);
+g_slist_free_full(g_steal_pointer(>shared_uuids), g_free);
 if (hdev->vhost_ops) {
 hdev->vhost_ops->vhost_backend_cleanup(hdev);
 }
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index 5e8183f64a..376bc8446d 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -118,6 +118,12 @@ struct vhost_dev {
  */
 uint64_t protocol_features;
 
+/**
+ * @shared_uuids: contains the UUIDs of all the exported
+ * virtio objects owned by the vhost device.
+ */
+GSList *shared_uuids;
+
 uint64_t max_queues;
 uint64_t backend_cap;
 /* @started: is the vhost device started? */
-- 
2.41.0




[PATCH 3/3] hw/virtio: rename virtio dmabuf API

2023-11-07 Thread Albert Esteve
Functions in the virtio-dmabuf module
start with 'virtio_*', which is too
generic and may not correctly identify
them as part of the virtio dmabuf API.

Rename all functions to 'virtio_dmabuf_*'
instead to avoid confusion.

Signed-off-by: Albert Esteve 
---
 hw/display/virtio-dmabuf.c| 14 +-
 hw/virtio/vhost-user.c| 14 +-
 hw/virtio/vhost.c |  3 ++-
 include/hw/virtio/virtio-dmabuf.h | 33 ---
 tests/unit/test-virtio-dmabuf.c   | 44 +++
 5 files changed, 55 insertions(+), 53 deletions(-)

diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
index 3dba4577ca..40ee046e76 100644
--- a/hw/display/virtio-dmabuf.c
+++ b/hw/display/virtio-dmabuf.c
@@ -48,7 +48,7 @@ static bool virtio_add_resource(QemuUUID *uuid, 
VirtioSharedObject *value)
 return result;
 }
 
-bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
+bool virtio_dmabuf_add(QemuUUID *uuid, int udmabuf_fd)
 {
 bool result;
 VirtioSharedObject *vso;
@@ -66,7 +66,7 @@ bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
 return result;
 }
 
-bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
+bool virtio_dmabuf_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
 {
 bool result;
 VirtioSharedObject *vso;
@@ -84,7 +84,7 @@ bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev 
*dev)
 return result;
 }
 
-bool virtio_remove_resource(const QemuUUID *uuid)
+bool virtio_dmabuf_remove_resource(const QemuUUID *uuid)
 {
 bool result;
 g_mutex_lock();
@@ -107,7 +107,7 @@ static VirtioSharedObject *get_shared_object(const QemuUUID 
*uuid)
 return (VirtioSharedObject *) lookup_res;
 }
 
-int virtio_lookup_dmabuf(const QemuUUID *uuid)
+int virtio_dmabuf_lookup(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -117,7 +117,7 @@ int virtio_lookup_dmabuf(const QemuUUID *uuid)
 return GPOINTER_TO_INT(vso->value);
 }
 
-struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
+struct vhost_dev *virtio_dmabuf_lookup_vhost_device(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -127,7 +127,7 @@ struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID 
*uuid)
 return (struct vhost_dev *) vso->value;
 }
 
-SharedObjectType virtio_object_type(const QemuUUID *uuid)
+SharedObjectType virtio_dmabuf_object_type(const QemuUUID *uuid)
 {
 VirtioSharedObject *vso = get_shared_object(uuid);
 if (vso == NULL) {
@@ -136,7 +136,7 @@ SharedObjectType virtio_object_type(const QemuUUID *uuid)
 return vso->type;
 }
 
-void virtio_free_resources(void)
+void virtio_dmabuf_free_resources(void)
 {
 g_mutex_lock();
 g_hash_table_destroy(resource_uuids);
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 04848d1fa0..47c2465081 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1599,7 +1599,7 @@ vhost_user_backend_handle_shared_object_add(struct 
vhost_dev *dev,
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
 dev->shared_uuids = g_slist_append(dev->shared_uuids, );
-return virtio_add_vhost_device(, dev);
+return virtio_dmabuf_add_vhost_device(, dev);
 }
 
 static int
@@ -1608,10 +1608,10 @@ vhost_user_backend_handle_shared_object_remove(struct 
vhost_dev *dev,
 {
 QemuUUID uuid;
 
-switch (virtio_object_type()) {
+switch (virtio_dmabuf_object_type()) {
 case TYPE_VHOST_DEV:
 {
-struct vhost_dev *owner = virtio_lookup_vhost_device();
+struct vhost_dev *owner = virtio_dmabuf_lookup_vhost_device();
 if (owner == NULL || dev != owner) {
 /* Not allowed to remove non-owned entries */
 return 0;
@@ -1625,7 +1625,7 @@ vhost_user_backend_handle_shared_object_remove(struct 
vhost_dev *dev,
 
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
 dev->shared_uuids = g_slist_remove_all(dev->shared_uuids, );
-return virtio_remove_resource();
+return virtio_dmabuf_remove_resource();
 }
 
 static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr,
@@ -1703,13 +1703,13 @@ vhost_user_backend_handle_shared_object_lookup(struct 
vhost_user *u,
 memcpy(uuid.data, payload->object.uuid, sizeof(payload->object.uuid));
 
 payload->u64 = 0;
-switch (virtio_object_type()) {
+switch (virtio_dmabuf_object_type()) {
 case TYPE_DMABUF:
-dmabuf_fd = virtio_lookup_dmabuf();
+dmabuf_fd = virtio_dmabuf_lookup();
 break;
 case TYPE_VHOST_DEV:
 {
-struct vhost_dev *dev = virtio_lookup_vhost_device();
+struct vhost_dev *dev = virtio_dmabuf_lookup_vhost_device();
 if (dev == NULL) {
 payload->u64 = -EINVAL;
 break;
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 3aff94664b..9ca2b

[PATCH 0/3] Virtio dmabuf improvements

2023-11-07 Thread Albert Esteve
Various improvements for the virtio-dmabuf module.
This patch includes:

- Check for ownership before allowing a vhost device
  to remove an object from the table.
- Properly cleanup shared resources if a vhost device
  object gets cleaned up.
- Rename virtio dmabuf functions to `virtio_dmabuf_*`

Albert Esteve (3):
  hw/virtio: check owner for removing objects
  hw/virtio: cleanup shared resources
  hw/virtio: rename virtio dmabuf API

 hw/display/virtio-dmabuf.c| 14 +-
 hw/virtio/vhost-user.c| 33 ++-
 hw/virtio/vhost.c |  5 
 include/hw/virtio/vhost.h |  6 +
 include/hw/virtio/virtio-dmabuf.h | 33 ---
 tests/unit/test-virtio-dmabuf.c   | 44 +++
 6 files changed, 83 insertions(+), 52 deletions(-)

-- 
2.41.0




[PATCH 1/3] hw/virtio: check owner for removing objects

2023-11-07 Thread Albert Esteve
Shared objects lack spoofing protection.
For VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE messages
received by the vhost-user interface, any backend was
allowed to remove entries from the shared table just
by knowing the UUID. Only the owner of the entry
shall be allowed to removed their resources
from the table.

To fix that, add a check for all
*SHARED_OBJECT_REMOVE messages received.
A vhost device can only remove TYPE_VHOST_DEV
entries that are owned by them, otherwise skip
the removal, and inform the device that the entry
has not been removed in the answer.

Signed-off-by: Albert Esteve 
---
 hw/virtio/vhost-user.c | 21 +++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 7b42ae8aae..5fdff0241f 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -1602,10 +1602,26 @@ vhost_user_backend_handle_shared_object_add(struct 
vhost_dev *dev,
 }
 
 static int
-vhost_user_backend_handle_shared_object_remove(VhostUserShared *object)
+vhost_user_backend_handle_shared_object_remove(struct vhost_dev *dev,
+   VhostUserShared *object)
 {
 QemuUUID uuid;
 
+switch (virtio_object_type()) {
+case TYPE_VHOST_DEV:
+{
+struct vhost_dev *owner = virtio_lookup_vhost_device();
+if (owner == NULL || dev != owner) {
+/* Not allowed to remove non-owned entries */
+return 0;
+}
+break;
+}
+default:
+/* Not allowed to remove non-owned entries */
+return 0;
+}
+
 memcpy(uuid.data, object->uuid, sizeof(object->uuid));
 return virtio_remove_resource();
 }
@@ -1785,7 +1801,8 @@ static gboolean backend_read(QIOChannel *ioc, 
GIOCondition condition,
 ret = vhost_user_backend_handle_shared_object_add(dev, 
);
 break;
 case VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE:
-ret = vhost_user_backend_handle_shared_object_remove();
+ret = vhost_user_backend_handle_shared_object_remove(dev,
+ );
 break;
 case VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP:
 ret = vhost_user_backend_handle_shared_object_lookup(dev->opaque, ioc,
-- 
2.41.0




Re: [PATCH v6 0/9] Fix cursor planes with virtualized drivers

2023-10-23 Thread Albert Esteve
On Mon, Oct 23, 2023 at 9:55 AM Simon Ser  wrote:

> On Monday, October 23rd, 2023 at 09:46, Albert Esteve 
> wrote:
>
> > Link to the IGT test covering this patch (already merged):
> > https://lists.freedesktop.org/archives/igt-dev/2023-July/058427.html
>
> Hmm. IGT should not be merged before the kernel, because as long as the
> kernel is not merged there might be some uAPI changes.
>

Right, but uAPI header was not updated on the IGT side. As per suggestion
of the
maintainers, I added a static variable that matches the definition on this
patch:
https://lists.freedesktop.org/archives/igt-dev/2023-August/058803.html

+/**
+ * Clients which do set cursor hotspot and treat the cursor plane
+ * like a mouse cursor should set this property.
+ */
+#define LOCAL_DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT  6


Once this patch gets upstreamed, the localized definition will be removed,
replaced by the real one.


> > Mutter patch:
> > https://lists.freedesktop.org/archives/igt-dev/2023-July/058427.html
>
> Seems like this link is same as IGT? Copy-pasta fail maybe?
>
>
Ah yes, my bad, this is the correct link:
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3337


[PATCH v6 6/9] drm/virtio: Use the hotspot properties from cursor planes

2023-10-23 Thread Albert Esteve
From: Zack Rusin 

Atomic modesetting got support for mouse hotspots via the hotspot
properties. Port the legacy kms hotspot handling to the new properties
on cursor planes.

Signed-off-by: Zack Rusin 
Reviewed-by: Gerd Hoffmann 
Cc: David Airlie 
Cc: Gurchetan Singh 
Cc: Chia-I Wu 
Cc: Daniel Vetter 
Cc: virtualizat...@lists.linux-foundation.org
Reviewed-by: Javier Martinez Canillas 
---
 drivers/gpu/drm/virtio/virtgpu_plane.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c 
b/drivers/gpu/drm/virtio/virtgpu_plane.c
index a2e045f3a0004..20de599658c1f 100644
--- a/drivers/gpu/drm/virtio/virtgpu_plane.c
+++ b/drivers/gpu/drm/virtio/virtgpu_plane.c
@@ -323,16 +323,16 @@ static void virtio_gpu_cursor_plane_update(struct 
drm_plane *plane,
DRM_DEBUG("update, handle %d, pos +%d+%d, hot %d,%d\n", handle,
  plane->state->crtc_x,
  plane->state->crtc_y,
- plane->state->fb ? plane->state->fb->hot_x : 0,
- plane->state->fb ? plane->state->fb->hot_y : 0);
+ plane->state->hotspot_x,
+ plane->state->hotspot_y);
output->cursor.hdr.type =
cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR);
output->cursor.resource_id = cpu_to_le32(handle);
if (plane->state->fb) {
output->cursor.hot_x =
-   cpu_to_le32(plane->state->fb->hot_x);
+   cpu_to_le32(plane->state->hotspot_x);
output->cursor.hot_y =
-   cpu_to_le32(plane->state->fb->hot_y);
+   cpu_to_le32(plane->state->hotspot_y);
} else {
output->cursor.hot_x = cpu_to_le32(0);
output->cursor.hot_y = cpu_to_le32(0);
-- 
2.41.0




[PATCH v6 1/9] drm: Disable the cursor plane on atomic contexts with virtualized drivers

2023-10-23 Thread Albert Esteve
From: Zack Rusin 

Cursor planes on virtualized drivers have special meaning and require
that the clients handle them in specific ways, e.g. the cursor plane
should react to the mouse movement the way a mouse cursor would be
expected to and the client is required to set hotspot properties on it
in order for the mouse events to be routed correctly.

This breaks the contract as specified by the "universal planes". Fix it
by disabling the cursor planes on virtualized drivers while adding
a foundation on top of which it's possible to special case mouse cursor
planes for clients that want it.

Disabling the cursor planes makes some kms compositors which were broken,
e.g. Weston, fallback to software cursor which works fine or at least
better than currently while having no effect on others, e.g. gnome-shell
or kwin, which put virtualized drivers on a deny-list when running in
atomic context to make them fallback to legacy kms and avoid this issue.

Signed-off-by: Zack Rusin 
Fixes: 681e7ec73044 ("drm: Allow userspace to ask for universal plane list 
(v2)")
Cc:  # v5.4+
Cc: Maarten Lankhorst 
Cc: Maxime Ripard 
Cc: Thomas Zimmermann 
Cc: David Airlie 
Cc: Daniel Vetter 
Cc: Dave Airlie 
Cc: Gerd Hoffmann 
Cc: Hans de Goede 
Cc: Gurchetan Singh 
Cc: Chia-I Wu 
Cc: dri-de...@lists.freedesktop.org
Cc: virtualizat...@lists.linux-foundation.org
Cc: spice-de...@lists.freedesktop.org
Acked-by: Pekka Paalanen 
Reviewed-by: Javier Martinez Canillas 
---
 drivers/gpu/drm/drm_plane.c  | 13 +
 drivers/gpu/drm/qxl/qxl_drv.c|  2 +-
 drivers/gpu/drm/vboxvideo/vbox_drv.c |  2 +-
 drivers/gpu/drm/virtio/virtgpu_drv.c |  2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c  |  2 +-
 include/drm/drm_drv.h|  9 +
 include/drm/drm_file.h   | 12 
 7 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 24e7998d17313..c6bbb0c209f47 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -678,6 +678,19 @@ int drm_mode_getplane_res(struct drm_device *dev, void 
*data,
!file_priv->universal_planes)
continue;
 
+   /*
+* If we're running on a virtualized driver then,
+* unless userspace advertizes support for the
+* virtualized cursor plane, disable cursor planes
+* because they'll be broken due to missing cursor
+* hotspot info.
+*/
+   if (plane->type == DRM_PLANE_TYPE_CURSOR &&
+   drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT) &&
+   file_priv->atomic &&
+   !file_priv->supports_virtualized_cursor_plane)
+   continue;
+
if (drm_lease_held(file_priv, plane->base.id)) {
if (count < plane_resp->count_planes &&
put_user(plane->base.id, plane_ptr + count))
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index b30ede1cf62d3..91930e84a9cd2 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -283,7 +283,7 @@ static const struct drm_ioctl_desc qxl_ioctls[] = {
 };
 
 static struct drm_driver qxl_driver = {
-   .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+   .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC | 
DRIVER_CURSOR_HOTSPOT,
 
.dumb_create = qxl_mode_dumb_create,
.dumb_map_offset = drm_gem_ttm_dumb_map_offset,
diff --git a/drivers/gpu/drm/vboxvideo/vbox_drv.c 
b/drivers/gpu/drm/vboxvideo/vbox_drv.c
index 4fee15c97c341..8ecd0863fad77 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_drv.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_drv.c
@@ -172,7 +172,7 @@ DEFINE_DRM_GEM_FOPS(vbox_fops);
 
 static const struct drm_driver driver = {
.driver_features =
-   DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
+   DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_CURSOR_HOTSPOT,
 
.fops = _fops,
.name = DRIVER_NAME,
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c 
b/drivers/gpu/drm/virtio/virtgpu_drv.c
index 644b8ee51009b..148f09aaf99a7 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.c
@@ -177,7 +177,7 @@ static const struct drm_driver driver = {
 * out via drm_device::driver_features:
 */
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_RENDER | 
DRIVER_ATOMIC |
-  DRIVER_SYNCOBJ | DRIVER_SYNCOBJ_TIMELINE,
+  DRIVER_SYNCOBJ | DRIVER_SYNCOBJ_TIMELINE | 
DRIVER_CURSOR_HOTSPOT,
.open = virtio_gpu_driver_open,
.postclose = virtio_gpu_driver_postclose,
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 8b24ecf60e3ec..d3e308fdfd5be 100644
--- 

[PATCH v6 0/9] Fix cursor planes with virtualized drivers

2023-10-23 Thread Albert Esteve
v6: Shift DRIVER_CURSOR_HOTSPOT flag bit to BIT(9), since BIT(8)
was already taken by DRIVER_GEM_GPUVA.

v5: Add a change with documentation from Michael, based on his discussion
with Pekka and bump the kernel version DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT
might be introduced with to 6.6.

v4: Make drm_plane_create_hotspot_properties static, rename
DRM_CLIENT_CAP_VIRTUALIZED_CURSOR_PLANE to DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT
and some minor stylistic fixes for things found by Javier and Pekka
in v3.

v3: Renames, fixes and cleanups suggested by Daniel, Simon and Pekka
after v2. There's no major changes in functionality. Please let me know
if I missed anything, it's been a while since v2.

Virtualized drivers have had a lot of issues with cursor support on top
of atomic modesetting. This set both fixes the long standing problems
with atomic kms and virtualized drivers and adds code to let userspace
use atomic kms on virtualized drivers while preserving functioning
seamless cursors between the host and guest.

The first change in the set is one that should be backported as far as
possible, likely 5.4 stable, because earlier stable kernels do not have
virtualbox driver. The change makes virtualized drivers stop exposing
a cursor plane for atomic clients, this fixes mouse cursor on all well
formed compositors which will automatically fallback to software cursor.

The rest of the changes until the last one ports the legacy hotspot code
to atomic plane properties.

Finally the last change introduces userspace API to let userspace
clients advertise the fact that they are aware of additional restrictions
placed upon the cursor plane by virtualized drivers and lets them use
atomic kms with virtualized drivers (the clients are expected to set
hotspots correctly when advertising support for virtual cursor plane).

Link to the IGT test covering this patch (already merged):
https://lists.freedesktop.org/archives/igt-dev/2023-July/058427.html

Mutter patch:
https://lists.freedesktop.org/archives/igt-dev/2023-July/058427.html

Michael Banack (1):
  drm: Introduce documentation for hotspot properties

Zack Rusin (8):
  drm: Disable the cursor plane on atomic contexts with virtualized
drivers
  drm/atomic: Add support for mouse hotspots
  drm/vmwgfx: Use the hotspot properties from cursor planes
  drm/qxl: Use the hotspot properties from cursor planes
  drm/vboxvideo: Use the hotspot properties from cursor planes
  drm/virtio: Use the hotspot properties from cursor planes
  drm: Remove legacy cursor hotspot code
  drm: Introduce DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT

 Documentation/gpu/drm-kms.rst |   6 ++
 drivers/gpu/drm/drm_atomic_state_helper.c |  14 +++
 drivers/gpu/drm/drm_atomic_uapi.c |  20 
 drivers/gpu/drm/drm_ioctl.c   |   9 ++
 drivers/gpu/drm/drm_plane.c   | 120 +-
 drivers/gpu/drm/qxl/qxl_display.c |  14 ++-
 drivers/gpu/drm/qxl/qxl_drv.c |   2 +-
 drivers/gpu/drm/vboxvideo/vbox_drv.c  |   2 +-
 drivers/gpu/drm/vboxvideo/vbox_mode.c |   4 +-
 drivers/gpu/drm/virtio/virtgpu_drv.c  |   2 +-
 drivers/gpu/drm/virtio/virtgpu_plane.c|   8 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c   |   2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c   |   9 +-
 include/drm/drm_drv.h |   9 ++
 include/drm/drm_file.h|  12 +++
 include/drm/drm_framebuffer.h |  12 ---
 include/drm/drm_plane.h   |  14 +++
 include/uapi/drm/drm.h|  25 +
 18 files changed, 245 insertions(+), 39 deletions(-)

-- 
2.41.0




[PATCH v6 9/9] drm: Introduce documentation for hotspot properties

2023-10-23 Thread Albert Esteve
From: Michael Banack 

To clarify the intent and reasoning behind the hotspot properties
introduce userspace documentation that goes over cursor handling
in para-virtualized environments.

The documentation is generic enough to not special case for any
specific hypervisor and should apply equally to all.

Signed-off-by: Zack Rusin 
---
 Documentation/gpu/drm-kms.rst |  6 
 drivers/gpu/drm/drm_plane.c   | 58 ++-
 2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
index a0c83fc481264..158cdcc9351f9 100644
--- a/Documentation/gpu/drm-kms.rst
+++ b/Documentation/gpu/drm-kms.rst
@@ -577,6 +577,12 @@ Variable Refresh Properties
 .. kernel-doc:: drivers/gpu/drm/drm_connector.c
:doc: Variable refresh properties
 
+Cursor Hotspot Properties
+---
+
+.. kernel-doc:: drivers/gpu/drm/drm_plane.c
+   :doc: hotspot properties
+
 Existing KMS Properties
 ---
 
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 1dc00ad4c33c3..f3f2eae83cca8 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -230,6 +230,61 @@ static int create_in_format_blob(struct drm_device *dev, 
struct drm_plane *plane
return 0;
 }
 
+/**
+ * DOC: hotspot properties
+ *
+ * HOTSPOT_X: property to set mouse hotspot x offset.
+ * HOTSPOT_Y: property to set mouse hotspot y offset.
+ *
+ * When the plane is being used as a cursor image to display a mouse pointer,
+ * the "hotspot" is the offset within the cursor image where mouse events
+ * are expected to go.
+ *
+ * Positive values move the hotspot from the top-left corner of the cursor
+ * plane towards the right and bottom.
+ *
+ * Most display drivers do not need this information because the
+ * hotspot is not actually connected to anything visible on screen.
+ * However, this is necessary for display drivers like the para-virtualized
+ * drivers (eg qxl, vbox, virtio, vmwgfx), that are attached to a user console
+ * with a mouse pointer.  Since these consoles are often being remoted over a
+ * network, they would otherwise have to wait to display the pointer movement 
to
+ * the user until a full network round-trip has occurred.  New mouse events 
have
+ * to be sent from the user's console, over the network to the virtual input
+ * devices, forwarded to the desktop for processing, and then the cursor 
plane's
+ * position can be updated and sent back to the user's console over the 
network.
+ * Instead, with the hotspot information, the console can anticipate the new
+ * location, and draw the mouse cursor there before the confirmation comes in.
+ * To do that correctly, the user's console must be able predict how the
+ * desktop will process mouse events, which normally requires the desktop's
+ * mouse topology information, ie where each CRTC sits in the mouse coordinate
+ * space.  This is typically sent to the para-virtualized drivers using some
+ * driver-specific method, and the driver then forwards it to the console by
+ * way of the virtual display device or hypervisor.
+ *
+ * The assumption is generally made that there is only one cursor plane being
+ * used this way at a time, and that the desktop is feeding all mouse devices
+ * into the same global pointer.  Para-virtualized drivers that require this
+ * should only be exposing a single cursor plane, or find some other way
+ * to coordinate with a userspace desktop that supports multiple pointers.
+ * If the hotspot properties are set, the cursor plane is therefore assumed to 
be
+ * used only for displaying a mouse cursor image, and the position of the 
combined
+ * cursor plane + offset can therefore be used for coordinating with input 
from a
+ * mouse device.
+ *
+ * The cursor will then be drawn either at the location of the plane in the 
CRTC
+ * console, or as a free-floating cursor plane on the user's console
+ * corresponding to their desktop mouse position.
+ *
+ * DRM clients which would like to work correctly on drivers which expose
+ * hotspot properties should advertise DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT.
+ * Setting this property on drivers which do not special case
+ * cursor planes will return EOPNOTSUPP, which can be used by userspace to
+ * gauge requirements of the hardware/drivers they're running on. Advertising
+ * DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT implies that the userspace client will 
be
+ * correctly setting the hotspot properties.
+ */
+
 /**
  * drm_plane_create_hotspot_properties - creates the mouse hotspot
  * properties and attaches them to the given cursor plane
@@ -237,7 +292,8 @@ static int create_in_format_blob(struct drm_device *dev, 
struct drm_plane *plane
  * @plane: drm cursor plane
  *
  * This function enables the mouse hotspot property on a given
- * cursor plane.
+ * cursor plane. Look at the documentation for hotspot properties
+ * to get a better understanding for what 

[PATCH v6 4/9] drm/qxl: Use the hotspot properties from cursor planes

2023-10-23 Thread Albert Esteve
From: Zack Rusin 

Atomic modesetting got support for mouse hotspots via the hotspot
properties. Port the legacy kms hotspot handling to the new properties
on cursor planes.

Signed-off-by: Zack Rusin 
Reviewed-by: Gerd Hoffmann 
Cc: Dave Airlie 
Cc: Daniel Vetter 
Cc: virtualizat...@lists.linux-foundation.org
Cc: spice-de...@lists.freedesktop.org
Reviewed-by: Javier Martinez Canillas 
---
 drivers/gpu/drm/qxl/qxl_display.c | 14 ++
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/qxl/qxl_display.c 
b/drivers/gpu/drm/qxl/qxl_display.c
index 6492a70e3c396..5d689e0d3586c 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -485,7 +485,6 @@ static int qxl_primary_atomic_check(struct drm_plane *plane,
 static int qxl_primary_apply_cursor(struct qxl_device *qdev,
struct drm_plane_state *plane_state)
 {
-   struct drm_framebuffer *fb = plane_state->fb;
struct qxl_crtc *qcrtc = to_qxl_crtc(plane_state->crtc);
struct qxl_cursor_cmd *cmd;
struct qxl_release *release;
@@ -510,8 +509,8 @@ static int qxl_primary_apply_cursor(struct qxl_device *qdev,
 
cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
cmd->type = QXL_CURSOR_SET;
-   cmd->u.set.position.x = plane_state->crtc_x + fb->hot_x;
-   cmd->u.set.position.y = plane_state->crtc_y + fb->hot_y;
+   cmd->u.set.position.x = plane_state->crtc_x + plane_state->hotspot_x;
+   cmd->u.set.position.y = plane_state->crtc_y + plane_state->hotspot_y;
 
cmd->u.set.shape = qxl_bo_physical_address(qdev, qcrtc->cursor_bo, 0);
 
@@ -531,7 +530,6 @@ static int qxl_primary_apply_cursor(struct qxl_device *qdev,
 static int qxl_primary_move_cursor(struct qxl_device *qdev,
   struct drm_plane_state *plane_state)
 {
-   struct drm_framebuffer *fb = plane_state->fb;
struct qxl_crtc *qcrtc = to_qxl_crtc(plane_state->crtc);
struct qxl_cursor_cmd *cmd;
struct qxl_release *release;
@@ -554,8 +552,8 @@ static int qxl_primary_move_cursor(struct qxl_device *qdev,
 
cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
cmd->type = QXL_CURSOR_MOVE;
-   cmd->u.position.x = plane_state->crtc_x + fb->hot_x;
-   cmd->u.position.y = plane_state->crtc_y + fb->hot_y;
+   cmd->u.position.x = plane_state->crtc_x + plane_state->hotspot_x;
+   cmd->u.position.y = plane_state->crtc_y + plane_state->hotspot_y;
qxl_release_unmap(qdev, release, >release_info);
 
qxl_release_fence_buffer_objects(release);
@@ -851,8 +849,8 @@ static int qxl_plane_prepare_fb(struct drm_plane *plane,
struct qxl_bo *old_cursor_bo = qcrtc->cursor_bo;
 
qcrtc->cursor_bo = qxl_create_cursor(qdev, user_bo,
-new_state->fb->hot_x,
-new_state->fb->hot_y);
+new_state->hotspot_x,
+new_state->hotspot_y);
qxl_free_cursor(old_cursor_bo);
}
 
-- 
2.41.0




[PATCH v6 5/9] drm/vboxvideo: Use the hotspot properties from cursor planes

2023-10-23 Thread Albert Esteve
From: Zack Rusin 

Atomic modesetting got support for mouse hotspots via the hotspot
properties. Port the legacy kms hotspot handling to the new properties
on cursor planes.

Signed-off-by: Zack Rusin 
Cc: Hans de Goede 
Cc: David Airlie 
Cc: Daniel Vetter 
Reviewed-by: Javier Martinez Canillas 
---
 drivers/gpu/drm/vboxvideo/vbox_mode.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c 
b/drivers/gpu/drm/vboxvideo/vbox_mode.c
index 341edd982cb3b..9ff3bade97957 100644
--- a/drivers/gpu/drm/vboxvideo/vbox_mode.c
+++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c
@@ -429,8 +429,8 @@ static void vbox_cursor_atomic_update(struct drm_plane 
*plane,
flags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE |
VBOX_MOUSE_POINTER_ALPHA;
hgsmi_update_pointer_shape(vbox->guest_pool, flags,
-  min_t(u32, max(fb->hot_x, 0), width),
-  min_t(u32, max(fb->hot_y, 0), height),
+  min_t(u32, max(new_state->hotspot_x, 0), 
width),
+  min_t(u32, max(new_state->hotspot_y, 0), 
height),
   width, height, vbox->cursor_data, data_size);
 
mutex_unlock(>hw_mutex);
-- 
2.41.0




[PATCH v6 3/9] drm/vmwgfx: Use the hotspot properties from cursor planes

2023-10-23 Thread Albert Esteve
From: Zack Rusin 

Atomic modesetting got support for mouse hotspots via the hotspot
properties. Port the legacy kms hotspot handling to the new properties
on cursor planes.

Signed-off-by: Zack Rusin 
Cc: Maaz Mombasawala 
Reviewed-by: Javier Martinez Canillas 
Reviewed-by: Martin Krastev 
---
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 9 ++---
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 818b7f109f538..bea0abc3d4188 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -768,13 +768,8 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane,
struct vmw_plane_state *old_vps = vmw_plane_state_to_vps(old_state);
s32 hotspot_x, hotspot_y;
 
-   hotspot_x = du->hotspot_x;
-   hotspot_y = du->hotspot_y;
-
-   if (new_state->fb) {
-   hotspot_x += new_state->fb->hot_x;
-   hotspot_y += new_state->fb->hot_y;
-   }
+   hotspot_x = du->hotspot_x + new_state->hotspot_x;
+   hotspot_y = du->hotspot_y + new_state->hotspot_y;
 
du->cursor_surface = vps->surf;
du->cursor_bo = vps->bo;
-- 
2.41.0




[PATCH v6 8/9] drm: Introduce DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT

2023-10-23 Thread Albert Esteve
From: Zack Rusin 

Virtualized drivers place additional restrictions on the cursor plane
which breaks the contract of universal planes. To allow atomic
modesettings with virtualized drivers the clients need to advertise
that they're capable of dealing with those extra restrictions.

To do that introduce DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT which
lets DRM know that the client is aware of and capable of dealing with
the extra restrictions on the virtual cursor plane.

Setting this option to true makes DRM expose the cursor plane on
virtualized drivers. The userspace is expected to set the hotspots
and handle mouse events on that plane.

Signed-off-by: Zack Rusin 
Cc: Maarten Lankhorst 
Cc: Maxime Ripard 
Cc: Thomas Zimmermann 
Cc: David Airlie 
Cc: Daniel Vetter 
Cc: dri-de...@lists.freedesktop.org
Acked-by: Pekka Paalanen 
Reviewed-by: Javier Martinez Canillas 
---
 drivers/gpu/drm/drm_ioctl.c |  9 +
 include/uapi/drm/drm.h  | 25 +
 2 files changed, 34 insertions(+)

diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index f03ffbacfe9b4..e535b58521533 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -361,6 +361,15 @@ drm_setclientcap(struct drm_device *dev, void *data, 
struct drm_file *file_priv)
return -EINVAL;
file_priv->writeback_connectors = req->value;
break;
+   case DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT:
+   if (!drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT))
+   return -EOPNOTSUPP;
+   if (!file_priv->atomic)
+   return -EINVAL;
+   if (req->value > 1)
+   return -EINVAL;
+   file_priv->supports_virtualized_cursor_plane = req->value;
+   break;
default:
return -EINVAL;
}
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 794c1d857677d..fc0c267f3f3ed 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -842,6 +842,31 @@ struct drm_get_cap {
  */
 #define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS5
 
+/**
+ * DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT
+ *
+ * Drivers for para-virtualized hardware (e.g. vmwgfx, qxl, virtio and
+ * virtualbox) have additional restrictions for cursor planes (thus
+ * making cursor planes on those drivers not truly universal,) e.g.
+ * they need cursor planes to act like one would expect from a mouse
+ * cursor and have correctly set hotspot properties.
+ * If this client cap is not set the DRM core will hide cursor plane on
+ * those virtualized drivers because not setting it implies that the
+ * client is not capable of dealing with those extra restictions.
+ * Clients which do set cursor hotspot and treat the cursor plane
+ * like a mouse cursor should set this property.
+ * The client must enable _CLIENT_CAP_ATOMIC first.
+ *
+ * Setting this property on drivers which do not special case
+ * cursor planes (i.e. non-virtualized drivers) will return
+ * EOPNOTSUPP, which can be used by userspace to gauge
+ * requirements of the hardware/drivers they're running on.
+ *
+ * This capability is always supported for atomic-capable virtualized
+ * drivers starting from kernel version 6.6.
+ */
+#define DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT6
+
 /* DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
 struct drm_set_client_cap {
__u64 capability;
-- 
2.41.0




[PATCH v6 7/9] drm: Remove legacy cursor hotspot code

2023-10-23 Thread Albert Esteve
From: Zack Rusin 

Atomic modesetting supports mouse cursor offsets via the hotspot
properties that are created on cursor planes. All drivers which
support hotspots are atomic and the legacy code has been implemented
in terms of the atomic properties as well.

Due to the above the lagacy cursor hotspot code is no longer used or
needed and can be removed.

Signed-off-by: Zack Rusin 
Cc: Maarten Lankhorst 
Cc: Maxime Ripard 
Cc: Thomas Zimmermann 
Cc: David Airlie 
Cc: Daniel Vetter 
Reviewed-by: Javier Martinez Canillas 
---
 drivers/gpu/drm/drm_plane.c   |  3 ---
 include/drm/drm_framebuffer.h | 12 
 2 files changed, 15 deletions(-)

diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index eaca367bdc7e7..1dc00ad4c33c3 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -1110,9 +1110,6 @@ static int drm_mode_cursor_universal(struct drm_crtc 
*crtc,
return PTR_ERR(fb);
}
 
-   fb->hot_x = req->hot_x;
-   fb->hot_y = req->hot_y;
-
if (plane->hotspot_x_property && plane->state)
plane->state->hotspot_x = req->hot_x;
if (plane->hotspot_y_property && plane->state)
diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h
index 0dcc07b686548..1e108c1789b1e 100644
--- a/include/drm/drm_framebuffer.h
+++ b/include/drm/drm_framebuffer.h
@@ -188,18 +188,6 @@ struct drm_framebuffer {
 * DRM_MODE_FB_MODIFIERS.
 */
int flags;
-   /**
-* @hot_x: X coordinate of the cursor hotspot. Used by the legacy cursor
-* IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR
-* universal plane.
-*/
-   int hot_x;
-   /**
-* @hot_y: Y coordinate of the cursor hotspot. Used by the legacy cursor
-* IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR
-* universal plane.
-*/
-   int hot_y;
/**
 * @filp_head: Placed on _file.fbs, protected by _file.fbs_lock.
 */
-- 
2.41.0




[PATCH v6 2/9] drm/atomic: Add support for mouse hotspots

2023-10-23 Thread Albert Esteve
From: Zack Rusin 

Atomic modesetting code lacked support for specifying mouse cursor
hotspots. The legacy kms DRM_IOCTL_MODE_CURSOR2 had support for setting
the hotspot but the functionality was not implemented in the new atomic
paths.

Due to the lack of hotspots in the atomic paths userspace compositors
completely disable atomic modesetting for drivers that require it (i.e.
all paravirtualized drivers).

This change adds hotspot properties to the atomic codepaths throughtout
the DRM core and will allow enabling atomic modesetting for virtualized
drivers in the userspace.

Signed-off-by: Zack Rusin 
Cc: Maarten Lankhorst 
Cc: Maxime Ripard 
Cc: Thomas Zimmermann 
Cc: David Airlie 
Cc: Daniel Vetter 
Reviewed-by: Javier Martinez Canillas 
---
 drivers/gpu/drm/drm_atomic_state_helper.c | 14 +++
 drivers/gpu/drm/drm_atomic_uapi.c | 20 +
 drivers/gpu/drm/drm_plane.c   | 50 +++
 include/drm/drm_plane.h   | 14 +++
 4 files changed, 98 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
b/drivers/gpu/drm/drm_atomic_state_helper.c
index 784e63d70a421..54975de44a0e3 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -275,6 +275,20 @@ void __drm_atomic_helper_plane_state_reset(struct 
drm_plane_state *plane_state,
plane_state->normalized_zpos = val;
}
}
+
+   if (plane->hotspot_x_property) {
+   if (!drm_object_property_get_default_value(>base,
+  
plane->hotspot_x_property,
+  ))
+   plane_state->hotspot_x = val;
+   }
+
+   if (plane->hotspot_y_property) {
+   if (!drm_object_property_get_default_value(>base,
+  
plane->hotspot_y_property,
+  ))
+   plane_state->hotspot_y = val;
+   }
 }
 EXPORT_SYMBOL(__drm_atomic_helper_plane_state_reset);
 
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
b/drivers/gpu/drm/drm_atomic_uapi.c
index 98d3b10c08ae1..07a7b3f18df26 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -593,6 +593,22 @@ static int drm_atomic_plane_set_property(struct drm_plane 
*plane,
} else if (plane->funcs->atomic_set_property) {
return plane->funcs->atomic_set_property(plane, state,
property, val);
+   } else if (property == plane->hotspot_x_property) {
+   if (plane->type != DRM_PLANE_TYPE_CURSOR) {
+   drm_dbg_atomic(plane->dev,
+  "[PLANE:%d:%s] is not a cursor plane: 
0x%llx\n",
+  plane->base.id, plane->name, val);
+   return -EINVAL;
+   }
+   state->hotspot_x = val;
+   } else if (property == plane->hotspot_y_property) {
+   if (plane->type != DRM_PLANE_TYPE_CURSOR) {
+   drm_dbg_atomic(plane->dev,
+  "[PLANE:%d:%s] is not a cursor plane: 
0x%llx\n",
+  plane->base.id, plane->name, val);
+   return -EINVAL;
+   }
+   state->hotspot_y = val;
} else {
drm_dbg_atomic(plane->dev,
   "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n",
@@ -653,6 +669,10 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
*val = state->scaling_filter;
} else if (plane->funcs->atomic_get_property) {
return plane->funcs->atomic_get_property(plane, state, 
property, val);
+   } else if (property == plane->hotspot_x_property) {
+   *val = state->hotspot_x;
+   } else if (property == plane->hotspot_y_property) {
+   *val = state->hotspot_y;
} else {
drm_dbg_atomic(dev,
   "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n",
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index c6bbb0c209f47..eaca367bdc7e7 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -230,6 +230,47 @@ static int create_in_format_blob(struct drm_device *dev, 
struct drm_plane *plane
return 0;
 }
 
+/**
+ * drm_plane_create_hotspot_properties - creates the mouse hotspot
+ * properties and attaches them to the given cursor plane
+ *
+ * @plane: drm cursor plane
+ *
+ * This function enables the mouse hotspot property on a given
+ * cursor plane.
+ *
+ * RETURNS:
+ * Zero for success or -errno
+ */
+static int drm_plane_create_hotspot_properties(struct drm_plane *plane)
+{
+   struct drm_property *prop_x;
+   struct drm_property *prop_y;

Re: [PATCH] vhost-user: Fix protocol feature bit conflict

2023-10-17 Thread Albert Esteve
On Tue, Oct 17, 2023 at 12:57 PM Stefan Hajnoczi  wrote:

> On Tue, 17 Oct 2023 at 04:26, Albert Esteve  wrote:
> >
> > Hi!
> >
> > Thanks for the patch, and sorry for not noticing the flag had already
> been assigned. The patch looks good to me!
>
> Hi Albert,
> I looked at the shared object code for the first time:
> - There are memory leaks in virtio_add_dmabuf() and
> virtio_add_vhost_device() when the UUID was added previously.
>

There is a patch already for fixing the leak:
https://patchew.org/QEMU/c61c13f9a0c67dec473bdbfc8789c29ef26c900b.1696624734.git.quic._5fmathb...@quicinc.com/


> - The hash table is global and there is no spoofing protection, so
> vhost-user devices can hijack known UUIDs. Is it possible to associate
> a vhost_dev owner with each shared object and only allow the owner to
> remove it?
>

True, it is unprotected from another backend to remove an entry without
ownership.
It sounds like a nice addition, I will post a patch. Thanks!


> - Is there cleanup code that removes shared objects from the hash
> table when a vhost_dev is destroyed? Otherwise TYPE_VHOST_DEV shared
> objects are leaked and their stale vhost_dev pointers could be
> dereferenced.
>

There is not. In a first thought, I assumed that the backends will be in
charge
of cleaning their entries from the shared hash table when they are destroyed
(prematurely or no). I will look into occurrences of vhost_dev getting
destroyed
that may need explicit handling of the leftover entries.


> - virtio-dmabuf.h API naming suggests this is a core VirtIODevice API:
> virtio_free_resources(), virtio_add_vhost_device(), etc rather than an
> API for VirtioSharedObject. Can the names be made more specific:
> virtio_dmabuf_*() or virtio_shobj_*() so it's clear these APIs are
> related to the dmabufs/shared objects?
>

Improving the names with what you suggested sounds good to me.
I guess I'll go with virtio_dmabuf_*, for consistency with the file
name. But `shobj` would be ok too.


>
> Thanks,
> Stefan
>
>


Re: [PATCH] hw/display: fix memleak from virtio_add_resource

2023-10-17 Thread Albert Esteve
On Fri, Oct 6, 2023 at 10:41 PM Matheus Tavares Bernardino <
quic_mathb...@quicinc.com> wrote:

> When the given uuid is already present in the hash table,
> virtio_add_resource() does not add the passed VirtioSharedObject. In
> this case, free it in the callers to avoid leaking memory. This fixed
> the following `make check` error, when built with --enable-sanitizers:
>
>   4/166 qemu:unit / test-virtio-dmabuf   ERROR 1.51s   exit status 1
>
>   ==7716==ERROR: LeakSanitizer: detected memory leaks
>   Direct leak of 320 byte(s) in 20 object(s) allocated from:
>   #0 0x7f6fc16e3808 in __interceptor_malloc
> ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:144
>   #1 0x7f6fc1503e98 in g_malloc
> (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x57e98)
>   #2 0x564d63cafb6b in test_add_invalid_resource
> ../tests/unit/test-virtio-dmabuf.c:100
>   #3 0x7f6fc152659d  (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x7a59d)
>   SUMMARY: AddressSanitizer: 320 byte(s) leaked in 20 allocation(s).
>
> The changes at virtio_add_resource() itself are not strictly necessary
> for the memleak fix, but they make it more obvious that, on an error
> return, the passed object is not added to the hash.
>
> Signed-off-by: Matheus Tavares Bernardino 
> ---
>  hw/display/virtio-dmabuf.c | 12 ++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
> index 4a8e430f3d..3dba4577ca 100644
> --- a/hw/display/virtio-dmabuf.c
> +++ b/hw/display/virtio-dmabuf.c
> @@ -29,7 +29,7 @@ static int uuid_equal_func(const void *lhv, const void
> *rhv)
>
>  static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value)
>  {
> -bool result = false;
> +bool result = true;
>
>  g_mutex_lock();
>  if (resource_uuids == NULL) {
> @@ -39,7 +39,9 @@ static bool virtio_add_resource(QemuUUID *uuid,
> VirtioSharedObject *value)
> g_free);
>  }
>  if (g_hash_table_lookup(resource_uuids, uuid) == NULL) {
> -result = g_hash_table_insert(resource_uuids, uuid, value);
> +g_hash_table_insert(resource_uuids, uuid, value);
> +} else {
> +result = false;
>  }
>  g_mutex_unlock();
>
> @@ -57,6 +59,9 @@ bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
>  vso->type = TYPE_DMABUF;
>  vso->value = GINT_TO_POINTER(udmabuf_fd);
>  result = virtio_add_resource(uuid, vso);
> +if (!result) {
> +g_free(vso);
> +}
>
>  return result;
>  }
> @@ -72,6 +77,9 @@ bool virtio_add_vhost_device(QemuUUID *uuid, struct
> vhost_dev *dev)
>  vso->type = TYPE_VHOST_DEV;
>  vso->value = dev;
>  result = virtio_add_resource(uuid, vso);
> +if (!result) {
> +g_free(vso);
> +}
>
>  return result;
>  }
> --
> 2.37.2
>
>
Thanks!

Reviewed-by: Albert Esteve 


Re: [PATCH] vhost-user: Fix protocol feature bit conflict

2023-10-17 Thread Albert Esteve
Hi!

Thanks for the patch, and sorry for not noticing the flag had already been
assigned. The patch looks good to me!

BR,
Albert

On Tue, Oct 17, 2023 at 9:54 AM Viresh Kumar 
wrote:

> On 17-10-23, 09:51, Hanna Czenczek wrote:
> > Not that I’m really opposed to that, but I don’t see the problem with
> just
> > doing that in the same work that makes qemu actually use this flag,
> exactly
> > because it’s just a -1/+1 change.
> >
> > I can send a v2, but should I do the same for libvhost-user and define
> the
> > flag there?  Do I have to add a patch to do the same for F_STATUS, which
> so
> > far only got a placeholder comment?
>
> Sure, that's fine too.
>
> --
> viresh
>
>


Re: [PATCH] hw/virtio/vhost: check nvqs at dev_start

2023-10-02 Thread Albert Esteve
Ah I see, I wanted to move the fail check as early as possible, and went a
bit too far ahead, before initialisation.

But is ok, it needs its own value either way. What about returning -EFAULT?
Or maybe -EINVAL? I think they would fit for this error.
And then I can use `VHOST_OPS_DEBUG` to make it consistent and print the
error number.

On Mon, Oct 2, 2023 at 11:27 AM Michael S. Tsirkin  wrote:

> On Fri, Sep 01, 2023 at 02:23:23PM +0200, Albert Esteve wrote:
> > While this is not expected to happen, it could still
> > be that a vhost_dev did not set its nvqs member.
> >
> > Since `vhost_dev_start` access the device's vqs array
> > later without checking its size, it would cause a
> > Segmentation fault when nvqs is 0.
> >
> > To avoid this `rare` case and made the code safer,
> > add a clause that ensures nvqs has been set, and
> > warn the user if it has not.
> >
> > Signed-off-by: Albert Esteve 
> > ---
> >  hw/virtio/vhost.c | 6 ++
> >  1 file changed, 6 insertions(+)
> >
> > diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
> > index e2f6ffb446..78805fe5b7 100644
> > --- a/hw/virtio/vhost.c
> > +++ b/hw/virtio/vhost.c
> > @@ -1935,6 +1935,11 @@ int vhost_dev_start(struct vhost_dev *hdev,
> VirtIODevice *vdev, bool vrings)
> >  hdev->started = true;
> >  hdev->vdev = vdev;
> >
> > +if (!hdev->nvqs) {
> > +error_report("device nvqs not set");
> > +goto fail_nvqs;
> > +}
> > +
> >  r = vhost_dev_set_features(hdev, hdev->log_enabled);
> >  if (r < 0) {
> >  goto fail_features;
> > @@ -2028,6 +2033,7 @@ fail_mem:
> >  if (vhost_dev_has_iommu(hdev)) {
> >  memory_listener_unregister(>iommu_listener);
> >  }
> > +fail_nvqs:
> >  fail_features:
> >  vdev->vhost_started = false;
> >  hdev->started = false;
>
> What do we want to return in this case?
> ATM the value we return (r) will be uninitialized.
>
> > --
> > 2.41.0
>
>


[PATCH v9 0/4] Virtio shared dma-buf

2023-10-02 Thread Albert Esteve
v1 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg00598.html
v2 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg04530.html
v3 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg06126.html
v4 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-06/msg05174.html
v5 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-08/msg00255.html
v6 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg00987.html
v7 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01190.html
v8 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg02284.html
v8 -> v9:
- Remove EOF whitespace in util/uuid.c

This patch covers the required steps to add support for virtio cross-device 
resource sharing[1],
which support is already available in the kernel.

The main usecase will be sharing dma buffers from virtio-gpu devices (as the 
exporter
-see VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID in [2]), to virtio-video (under 
discussion)
devices (as the buffer-user or importer). Therefore, even though virtio specs 
talk about
resources or objects[3], this patch adds the infrastructure with dma-bufs in 
mind.
Note that virtio specs let the devices themselves define what a vitio object is.

These are the main parts that are covered in the patch:

- Add hash function to uuid module
- Shared resources table, to hold all resources that can be shared in the host 
and their assigned UUID,
  or pointers to the backend holding the resource
- Internal shared table API for virtio devices to add, lookup and remove 
resources
- Unit test to verify the API
- New messages to the vhost-user protocol to allow backend to interact with the 
shared
  table API through the control socket
- New vhost-user feature bit to enable shared objects feature

Applies cleanly to 36e9aab3c569d4c9ad780473596e18479838d1aa

[1] - https://lwn.net/Articles/828988/
[2] - 
https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-3730006
[3] - 
https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-10500011

Albert Esteve (4):
  util/uuid: add a hash function
  hw/display: introduce virtio-dmabuf
  vhost-user: add shared_object msg
  libvhost-user: handle shared_object msg

 MAINTAINERS   |   7 +
 docs/interop/vhost-user.rst   |  57 
 hw/display/meson.build|   1 +
 hw/display/virtio-dmabuf.c| 138 ++
 hw/virtio/vhost-user.c| 168 --
 include/hw/virtio/vhost-backend.h |   3 +
 include/hw/virtio/virtio-dmabuf.h | 100 +
 include/qemu/uuid.h   |   2 +
 subprojects/libvhost-user/libvhost-user.c | 120 
 subprojects/libvhost-user/libvhost-user.h |  55 ++-
 tests/unit/meson.build|   1 +
 tests/unit/test-uuid.c|  27 
 tests/unit/test-virtio-dmabuf.c   | 137 ++
 util/uuid.c   |  14 ++
 14 files changed, 817 insertions(+), 13 deletions(-)
 create mode 100644 hw/display/virtio-dmabuf.c
 create mode 100644 include/hw/virtio/virtio-dmabuf.h
 create mode 100644 tests/unit/test-virtio-dmabuf.c

-- 
2.41.0




[PATCH v9 3/4] vhost-user: add shared_object msg

2023-10-02 Thread Albert Esteve
Add three new vhost-user protocol
`VHOST_USER_BACKEND_SHARED_OBJECT_* messages`.
These new messages are sent from vhost-user
back-ends to interact with the virtio-dmabuf
table in order to add or remove themselves as
virtio exporters, or lookup for virtio dma-buf
shared objects.

The action taken in the front-end depends
on the type stored in the virtio shared
object hash table.

When the table holds a pointer to a vhost
backend for a given UUID, the front-end sends
a VHOST_USER_GET_SHARED_OBJECT to the
backend holding the shared object.

The messages can only be sent after successfully
negotiating a new VHOST_USER_PROTOCOL_F_SHARED_OBJECT
vhost-user protocol feature bit.

Finally, refactor code to send response message so
that all common parts both for the common REPLY_ACK
case, and other data responses, can call it and
avoid code repetition.

Signed-off-by: Albert Esteve 
---
 docs/interop/vhost-user.rst   |  57 ++
 hw/virtio/vhost-user.c| 168 +++---
 include/hw/virtio/vhost-backend.h |   3 +
 3 files changed, 216 insertions(+), 12 deletions(-)

diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index 5a070adbc1..415bb47a19 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -1440,6 +1440,18 @@ Front-end message types
   query the back-end for its device status as defined in the Virtio
   specification.
 
+``VHOST_USER_GET_SHARED_OBJECT``
+  :id: 41
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: dmabuf fd
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, and the UUID is found
+  in the exporters cache, this message is submitted by the front-end
+  to retrieve a given dma-buf fd from a given back-end, determined by
+  the requested UUID. Back-end will reply passing the fd when the operation
+  is successful, or no fd otherwise.
 
 Back-end message types
 --
@@ -1528,6 +1540,51 @@ is sent by the front-end.
 
   The state.num field is currently reserved and must be set to 0.
 
+``VHOST_USER_BACKEND_SHARED_OBJECT_ADD``
+  :id: 6
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: N/A
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backends to add themselves as exporters to the virtio shared lookup
+  table. The back-end device gets associated with a UUID in the shared table.
+  The back-end is responsible of keeping its own table with exported dma-buf 
fds.
+  When another back-end tries to import the resource associated with the UUID,
+  it will send a message to the front-end, which will act as a proxy to the
+  exporter back-end. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and
+  the back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must
+  respond with zero when operation is successfully completed, or non-zero
+  otherwise.
+
+``VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE``
+  :id: 7
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: N/A
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backend to remove themselves from to the virtio-dmabuf shared
+  table API. The shared table will remove the back-end device associated with
+  the UUID. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and the
+  back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond
+  with zero when operation is successfully completed, or non-zero otherwise.
+
+``VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP``
+  :id: 8
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: dmabuf fd and ``u64``
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backends to retrieve a given dma-buf fd from the virtio-dmabuf
+  shared table given a UUID. Frontend will reply passing the fd and a zero
+  when the operation is successful, or non-zero otherwise. Note that if the
+  operation fails, no fd is sent to the backend.
+
 .. _reply_ack:
 
 VHOST_USER_PROTOCOL_F_REPLY_ACK
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 8dcf049d42..08ab256613 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -10,6 +10,7 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "hw/virtio/virtio-dmabuf.h"
 #include "hw/virtio/vhost.h"
 #include "hw/virtio/virtio-crypto.h"
 #include "hw/virtio/vhost-user.h"
@@ -21,6 +22,7 @@
 #include "sysemu/kvm.h"
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
+#include "qemu/uuid.h"
 #include 

[PATCH v9 4/4] libvhost-user: handle shared_object msg

2023-10-02 Thread Albert Esteve
In the libvhost-user library we need to
handle VHOST_USER_GET_SHARED_OBJECT requests,
and add helper functions to allow sending messages
to interact with the virtio shared objects
hash table.

Signed-off-by: Albert Esteve 
---
 subprojects/libvhost-user/libvhost-user.c | 120 ++
 subprojects/libvhost-user/libvhost-user.h |  55 +-
 2 files changed, 174 insertions(+), 1 deletion(-)

diff --git a/subprojects/libvhost-user/libvhost-user.c 
b/subprojects/libvhost-user/libvhost-user.c
index 0469a50101..676e57a468 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -161,6 +161,7 @@ vu_request_to_string(unsigned int req)
 REQ(VHOST_USER_GET_MAX_MEM_SLOTS),
 REQ(VHOST_USER_ADD_MEM_REG),
 REQ(VHOST_USER_REM_MEM_REG),
+REQ(VHOST_USER_GET_SHARED_OBJECT),
 REQ(VHOST_USER_MAX),
 };
 #undef REQ
@@ -900,6 +901,24 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
 return false;
 }
 
+static bool
+vu_get_shared_object(VuDev *dev, VhostUserMsg *vmsg)
+{
+int fd_num = 0;
+int dmabuf_fd = -1;
+if (dev->iface->get_shared_object) {
+dmabuf_fd = dev->iface->get_shared_object(
+dev, >payload.object.uuid[0]);
+}
+if (dmabuf_fd != -1) {
+DPRINT("dmabuf_fd found for requested UUID\n");
+vmsg->fds[fd_num++] = dmabuf_fd;
+}
+vmsg->fd_num = fd_num;
+
+return true;
+}
+
 static bool
 vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
 {
@@ -1403,6 +1422,105 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq 
*vq, int fd,
 return vu_process_message_reply(dev, );
 }
 
+bool
+vu_lookup_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN],
+int *dmabuf_fd)
+{
+bool result = false;
+VhostUserMsg msg_reply;
+VhostUserMsg msg = {
+.request = VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP,
+.size = sizeof(msg.payload.object),
+.flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK,
+};
+
+memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN);
+
+if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) {
+return false;
+}
+
+pthread_mutex_lock(>backend_mutex);
+if (!vu_message_write(dev, dev->backend_fd, )) {
+goto out;
+}
+
+if (!vu_message_read_default(dev, dev->backend_fd, _reply)) {
+goto out;
+}
+
+if (msg_reply.request != msg.request) {
+DPRINT("Received unexpected msg type. Expected %d, received %d",
+   msg.request, msg_reply.request);
+goto out;
+}
+
+if (msg_reply.fd_num != 1) {
+DPRINT("Received unexpected number of fds. Expected 1, received %d",
+   msg_reply.fd_num);
+goto out;
+}
+
+*dmabuf_fd = msg_reply.fds[0];
+result = *dmabuf_fd > 0 && msg_reply.payload.u64 == 0;
+out:
+pthread_mutex_unlock(>backend_mutex);
+
+return result;
+}
+
+static bool
+vu_send_message(VuDev *dev, VhostUserMsg *vmsg)
+{
+bool result = false;
+pthread_mutex_lock(>backend_mutex);
+if (!vu_message_write(dev, dev->backend_fd, vmsg)) {
+goto out;
+}
+
+result = true;
+out:
+pthread_mutex_unlock(>backend_mutex);
+
+return result;
+}
+
+bool
+vu_add_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN])
+{
+VhostUserMsg msg = {
+.request = VHOST_USER_BACKEND_SHARED_OBJECT_ADD,
+.size = sizeof(msg.payload.object),
+.flags = VHOST_USER_VERSION,
+};
+
+memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN);
+
+if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) {
+return false;
+}
+
+return vu_send_message(dev, );
+}
+
+bool
+vu_rm_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN])
+{
+VhostUserMsg msg = {
+.request = VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE,
+.size = sizeof(msg.payload.object),
+.flags = VHOST_USER_VERSION,
+};
+
+memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN);
+
+if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) {
+return false;
+}
+
+return vu_send_message(dev, );
+}
+
 static bool
 vu_set_vring_call_exec(VuDev *dev, VhostUserMsg *vmsg)
 {
@@ -1943,6 +2061,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
 return vu_add_mem_reg(dev, vmsg);
 case VHOST_USER_REM_MEM_REG:
 return vu_rem_mem_reg(dev, vmsg);
+case VHOST_USER_GET_SHARED_OBJECT:
+return vu_get_shared_object(dev, vmsg);
 default:
 vmsg_close_fds(vmsg);
 vu_panic(dev, "Unhandled request: %d", vmsg->request);
diff --git a/subprojects/libvhost-user/libvhost-user.h 
b/subprojects/libvhost-user/libvhost-user.h
index 708370c5f5..b36a42a7ca 100644
--- a/subprojects/libv

[PATCH v9 1/4] util/uuid: add a hash function

2023-10-02 Thread Albert Esteve
Add hash function to uuid module using the
djb2 hash algorithm.

Add a couple simple unit tests for the hash
function, checking collisions for similar UUIDs.

Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Albert Esteve 
---
 include/qemu/uuid.h|  2 ++
 tests/unit/test-uuid.c | 27 +++
 util/uuid.c| 14 ++
 3 files changed, 43 insertions(+)

diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h
index dc40ee1fc9..e24a1099e4 100644
--- a/include/qemu/uuid.h
+++ b/include/qemu/uuid.h
@@ -96,4 +96,6 @@ int qemu_uuid_parse(const char *str, QemuUUID *uuid);
 
 QemuUUID qemu_uuid_bswap(QemuUUID uuid);
 
+uint32_t qemu_uuid_hash(const void *uuid);
+
 #endif
diff --git a/tests/unit/test-uuid.c b/tests/unit/test-uuid.c
index c111de5fc1..aedc125ae9 100644
--- a/tests/unit/test-uuid.c
+++ b/tests/unit/test-uuid.c
@@ -171,6 +171,32 @@ static void test_uuid_unparse_strdup(void)
 }
 }
 
+static void test_uuid_hash(void)
+{
+QemuUUID uuid;
+int i;
+
+for (i = 0; i < 100; i++) {
+qemu_uuid_generate();
+/* Obtain the UUID hash */
+uint32_t hash_a = qemu_uuid_hash();
+int data_idx = g_random_int_range(0, 15);
+/* Change a single random byte of the UUID */
+if (uuid.data[data_idx] < 0xFF) {
+uuid.data[data_idx]++;
+} else {
+uuid.data[data_idx]--;
+}
+/* Obtain the UUID hash again */
+uint32_t hash_b = qemu_uuid_hash();
+/*
+ * Both hashes shall be different (avoid collision)
+ * for any change in the UUID fields
+ */
+g_assert_cmpint(hash_a, !=, hash_b);
+}
+}
+
 int main(int argc, char **argv)
 {
 g_test_init(, , NULL);
@@ -179,6 +205,7 @@ int main(int argc, char **argv)
 g_test_add_func("/uuid/parse", test_uuid_parse);
 g_test_add_func("/uuid/unparse", test_uuid_unparse);
 g_test_add_func("/uuid/unparse_strdup", test_uuid_unparse_strdup);
+g_test_add_func("/uuid/hash", test_uuid_hash);
 
 return g_test_run();
 }
diff --git a/util/uuid.c b/util/uuid.c
index b1108dde78..d71aa79e5e 100644
--- a/util/uuid.c
+++ b/util/uuid.c
@@ -116,3 +116,17 @@ QemuUUID qemu_uuid_bswap(QemuUUID uuid)
 bswap16s(_high_and_version);
 return uuid;
 }
+
+/* djb2 hash algorithm */
+uint32_t qemu_uuid_hash(const void *uuid)
+{
+QemuUUID *qid = (QemuUUID *) uuid;
+uint32_t h = 5381;
+int i;
+
+for (i = 0; i < ARRAY_SIZE(qid->data); i++) {
+h = (h << 5) + h + qid->data[i];
+}
+
+return h;
+}
-- 
2.41.0




[PATCH v9 2/4] hw/display: introduce virtio-dmabuf

2023-10-02 Thread Albert Esteve
This API manages objects (in this iteration,
dmabuf fds) that can be shared along different
virtio devices, associated to a UUID.

The API allows the different devices to add,
remove and/or retrieve the objects by simply
invoking the public functions that reside in the
virtio-dmabuf file.

For vhost backends, the API stores the pointer
to the backend holding the object.

Suggested-by: Gerd Hoffmann 
Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Albert Esteve 
---
 MAINTAINERS   |   7 ++
 hw/display/meson.build|   1 +
 hw/display/virtio-dmabuf.c| 138 ++
 include/hw/virtio/virtio-dmabuf.h | 100 ++
 tests/unit/meson.build|   1 +
 tests/unit/test-virtio-dmabuf.c   | 137 +
 6 files changed, 384 insertions(+)
 create mode 100644 hw/display/virtio-dmabuf.c
 create mode 100644 include/hw/virtio/virtio-dmabuf.h
 create mode 100644 tests/unit/test-virtio-dmabuf.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 355b1960ce..5e27ce3ceb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2154,6 +2154,13 @@ T: git https://gitlab.com/cohuck/qemu.git s390-next
 T: git https://github.com/borntraeger/qemu.git s390-next
 L: qemu-s3...@nongnu.org
 
+virtio-dmabuf
+M: Albert Esteve 
+S: Supported
+F: hw/display/virtio-dmabuf.c
+F: include/hw/virtio/virtio-dmabuf.h
+F: tests/unit/test-virtio-dmabuf.c
+
 virtiofs
 M: Stefan Hajnoczi 
 S: Supported
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 413ba4ab24..05619c6968 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -37,6 +37,7 @@ system_ss.add(when: 'CONFIG_MACFB', if_true: files('macfb.c'))
 system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c'))
 
 system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c'))
+system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c'))
 
 if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or
 config_all_devices.has_key('CONFIG_VGA_PCI') or
diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
new file mode 100644
index 00..4a8e430f3d
--- /dev/null
+++ b/hw/display/virtio-dmabuf.c
@@ -0,0 +1,138 @@
+/*
+ * Virtio Shared dma-buf
+ *
+ * Copyright Red Hat, Inc. 2023
+ *
+ * Authors:
+ * Albert Esteve 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/virtio/virtio-dmabuf.h"
+
+
+static GMutex lock;
+static GHashTable *resource_uuids;
+
+/*
+ * uuid_equal_func: wrapper for UUID is_equal function to
+ * satisfy g_hash_table_new expected parameters signatures.
+ */
+static int uuid_equal_func(const void *lhv, const void *rhv)
+{
+return qemu_uuid_is_equal(lhv, rhv);
+}
+
+static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value)
+{
+bool result = false;
+
+g_mutex_lock();
+if (resource_uuids == NULL) {
+resource_uuids = g_hash_table_new_full(qemu_uuid_hash,
+   uuid_equal_func,
+   NULL,
+   g_free);
+}
+if (g_hash_table_lookup(resource_uuids, uuid) == NULL) {
+result = g_hash_table_insert(resource_uuids, uuid, value);
+}
+g_mutex_unlock();
+
+return result;
+}
+
+bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
+{
+bool result;
+VirtioSharedObject *vso;
+if (udmabuf_fd < 0) {
+return false;
+}
+vso = g_new(VirtioSharedObject, 1);
+vso->type = TYPE_DMABUF;
+vso->value = GINT_TO_POINTER(udmabuf_fd);
+result = virtio_add_resource(uuid, vso);
+
+return result;
+}
+
+bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
+{
+bool result;
+VirtioSharedObject *vso;
+if (dev == NULL) {
+return false;
+}
+vso = g_new(VirtioSharedObject, 1);
+vso->type = TYPE_VHOST_DEV;
+vso->value = dev;
+result = virtio_add_resource(uuid, vso);
+
+return result;
+}
+
+bool virtio_remove_resource(const QemuUUID *uuid)
+{
+bool result;
+g_mutex_lock();
+result = g_hash_table_remove(resource_uuids, uuid);
+g_mutex_unlock();
+
+return result;
+}
+
+static VirtioSharedObject *get_shared_object(const QemuUUID *uuid)
+{
+gpointer lookup_res = NULL;
+
+g_mutex_lock();
+if (resource_uuids != NULL) {
+lookup_res = g_hash_table_lookup(resource_uuids, uuid);
+}
+g_mutex_unlock();
+
+return (VirtioSharedObject *) lookup_res;
+}
+
+int virtio_lookup_dmabuf(const QemuUUID *uuid)
+{
+VirtioSharedObject *vso = get_shared_object(uuid);
+if (vso == NULL) {
+return -1;
+}
+assert(vso->type == TYPE_DMABUF);
+return GPOINTER_TO_INT(vso->value);
+}
+
+struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
+{
+Vi

Re: [PATCH v8 1/4] util/uuid: add a hash function

2023-10-02 Thread Albert Esteve
On Sun, Oct 1, 2023 at 10:15 PM Michael S. Tsirkin  wrote:

> On Fri, Sep 08, 2023 at 05:47:40PM +0200, Albert Esteve wrote:
> > Add hash function to uuid module using the
> > djb2 hash algorithm.
> >
> > Add a couple simple unit tests for the hash
> > function, checking collisions for similar UUIDs.
> >
> > Reviewed-by: Philippe Mathieu-Daudé 
> > Signed-off-by: Albert Esteve 
> > ---
> >  include/qemu/uuid.h|  2 ++
> >  tests/unit/test-uuid.c | 27 +++
> >  util/uuid.c| 15 +++
> >  3 files changed, 44 insertions(+)
> >
> > diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h
> > index dc40ee1fc9..e24a1099e4 100644
> > --- a/include/qemu/uuid.h
> > +++ b/include/qemu/uuid.h
> > @@ -96,4 +96,6 @@ int qemu_uuid_parse(const char *str, QemuUUID *uuid);
> >
> >  QemuUUID qemu_uuid_bswap(QemuUUID uuid);
> >
> > +uint32_t qemu_uuid_hash(const void *uuid);
> > +
> >  #endif
> > diff --git a/tests/unit/test-uuid.c b/tests/unit/test-uuid.c
> > index c111de5fc1..aedc125ae9 100644
> > --- a/tests/unit/test-uuid.c
> > +++ b/tests/unit/test-uuid.c
> > @@ -171,6 +171,32 @@ static void test_uuid_unparse_strdup(void)
> >  }
> >  }
> >
> > +static void test_uuid_hash(void)
> > +{
> > +QemuUUID uuid;
> > +int i;
> > +
> > +for (i = 0; i < 100; i++) {
> > +qemu_uuid_generate();
> > +/* Obtain the UUID hash */
> > +uint32_t hash_a = qemu_uuid_hash();
> > +int data_idx = g_random_int_range(0, 15);
> > +/* Change a single random byte of the UUID */
> > +if (uuid.data[data_idx] < 0xFF) {
> > +uuid.data[data_idx]++;
> > +} else {
> > +uuid.data[data_idx]--;
> > +}
> > +/* Obtain the UUID hash again */
> > +uint32_t hash_b = qemu_uuid_hash();
> > +/*
> > + * Both hashes shall be different (avoid collision)
> > + * for any change in the UUID fields
> > + */
> > +g_assert_cmpint(hash_a, !=, hash_b);
> > +}
> > +}
> > +
> >  int main(int argc, char **argv)
> >  {
> >  g_test_init(, , NULL);
> > @@ -179,6 +205,7 @@ int main(int argc, char **argv)
> >  g_test_add_func("/uuid/parse", test_uuid_parse);
> >  g_test_add_func("/uuid/unparse", test_uuid_unparse);
> >  g_test_add_func("/uuid/unparse_strdup", test_uuid_unparse_strdup);
> > +g_test_add_func("/uuid/hash", test_uuid_hash);
> >
> >  return g_test_run();
> >  }
> > diff --git a/util/uuid.c b/util/uuid.c
> > index b1108dde78..b366961bc6 100644
> > --- a/util/uuid.c
> > +++ b/util/uuid.c
> > @@ -116,3 +116,18 @@ QemuUUID qemu_uuid_bswap(QemuUUID uuid)
> >  bswap16s(_high_and_version);
> >  return uuid;
> >  }
> > +
> > +/* djb2 hash algorithm */
> > +uint32_t qemu_uuid_hash(const void *uuid)
> > +{
> > +QemuUUID *qid = (QemuUUID *) uuid;
> > +uint32_t h = 5381;
> > +int i;
> > +
> > +for (i = 0; i < ARRAY_SIZE(qid->data); i++) {
> > +h = (h << 5) + h + qid->data[i];
> > +}
> > +
> > +return h;
> > +}
> > +
>
> whitespace error:
>
> .git/rebase-apply/patch:85: new blank line at EOF.
> +
> warning: 1 line adds whitespace errors.
>

Ok, I will send a new revision.


>
>
>
>
> > --
> > 2.41.0
>
>


Re: [QEMU PATCH v4 10/13] virtio-gpu: Resource UUID

2023-09-15 Thread Albert Esteve
On Thu, Sep 14, 2023 at 6:56 PM Akihiko Odaki 
wrote:

> On 2023/09/14 17:29, Albert Esteve wrote:
> >
> >
> > On Thu, Sep 14, 2023 at 9:17 AM Akihiko Odaki  > <mailto:akihiko.od...@daynix.com>> wrote:
> >
> > On 2023/09/13 23:18, Albert Esteve wrote:
> >  >
> >  >
> >  > On Wed, Sep 13, 2023 at 3:43 PM Akihiko Odaki
> > mailto:akihiko.od...@daynix.com>
> >  > <mailto:akihiko.od...@daynix.com
> >     <mailto:akihiko.od...@daynix.com>>> wrote:
> >  >
> >  > On 2023/09/13 21:58, Albert Esteve wrote:
> >  >  >
> >  >  >
> >  >  > On Wed, Sep 13, 2023 at 2:22 PM Akihiko Odaki
> >  > mailto:akihiko.od...@daynix.com>
> > <mailto:akihiko.od...@daynix.com <mailto:akihiko.od...@daynix.com>>
> >  >  > <mailto:akihiko.od...@daynix.com
> > <mailto:akihiko.od...@daynix.com>
> >  > <mailto:akihiko.od...@daynix.com
> > <mailto:akihiko.od...@daynix.com>>>> wrote:
> >  >  >
> >  >  > On 2023/09/13 20:34, Albert Esteve wrote:
> >  >  >  >
> >  >  >  >
> >  >  >  > On Wed, Sep 13, 2023 at 12:34 PM Akihiko Odaki
> >  >  >  > <mailto:akihiko.od...@daynix.com> <mailto:akihiko.od...@daynix.com
> > <mailto:akihiko.od...@daynix.com>>
> >  > <mailto:akihiko.od...@daynix.com
> > <mailto:akihiko.od...@daynix.com> <mailto:akihiko.od...@daynix.com
> > <mailto:akihiko.od...@daynix.com>>>
> >  >  >  > <mailto:akihiko.od...@daynix.com
> > <mailto:akihiko.od...@daynix.com>
> >  > <mailto:akihiko.od...@daynix.com
> > <mailto:akihiko.od...@daynix.com>>
> >  >  > <mailto:akihiko.od...@daynix.com
> > <mailto:akihiko.od...@daynix.com>
> >  > <mailto:akihiko.od...@daynix.com
> > <mailto:akihiko.od...@daynix.com>>>>> wrote:
> >  >  >  >
> >  >  >  > On 2023/09/13 16:55, Albert Esteve wrote:
> >  >  >  >  > Hi Antonio,
> >  >  >  >  >
> >  >  >  >  > If I'm not mistaken, this patch is related
> with:
> >  >  >  >  >
> >  >  >  >
> >  >  >
> >  >
> > https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
> > <https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
> >
> >  >
> >   <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>>
> >  >  >
> >  >
> >   <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html> <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>>>
> >  >  >  >
> >  >  >
> >  >
> >   <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html> <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>> <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html> <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>>>>
> >  >  >  >  >
> >  >  >  >
> >  >  >
> >  >
> >   <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html> <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>> <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
&g

Re: [QEMU PATCH v4 10/13] virtio-gpu: Resource UUID

2023-09-14 Thread Albert Esteve
On Thu, Sep 14, 2023 at 9:17 AM Akihiko Odaki 
wrote:

> On 2023/09/13 23:18, Albert Esteve wrote:
> >
> >
> > On Wed, Sep 13, 2023 at 3:43 PM Akihiko Odaki  > <mailto:akihiko.od...@daynix.com>> wrote:
> >
> > On 2023/09/13 21:58, Albert Esteve wrote:
> >  >
> >  >
> >  > On Wed, Sep 13, 2023 at 2:22 PM Akihiko Odaki
> > mailto:akihiko.od...@daynix.com>
> >  > <mailto:akihiko.od...@daynix.com
> >     <mailto:akihiko.od...@daynix.com>>> wrote:
> >  >
> >  > On 2023/09/13 20:34, Albert Esteve wrote:
> >  >  >
> >  >  >
> >  >  > On Wed, Sep 13, 2023 at 12:34 PM Akihiko Odaki
> >  > mailto:akihiko.od...@daynix.com>
> > <mailto:akihiko.od...@daynix.com <mailto:akihiko.od...@daynix.com>>
> >  >  > <mailto:akihiko.od...@daynix.com
> > <mailto:akihiko.od...@daynix.com>
> >  > <mailto:akihiko.od...@daynix.com
> > <mailto:akihiko.od...@daynix.com>>>> wrote:
> >  >  >
> >  >  > On 2023/09/13 16:55, Albert Esteve wrote:
> >  >  >  > Hi Antonio,
> >  >  >  >
> >  >  >  > If I'm not mistaken, this patch is related with:
> >  >  >  >
> >  >  >
> >  >
> > https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
> > <https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
> >
> >  >
> >   <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>>
> >  >  >
> >  >
> >   <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html> <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>>>
> >  >  >  >
> >  >  >
> >  >
> >   <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html> <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>>
> >  >  >
> >  >
> >   <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html> <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>>>>
> >  >  >  > IMHO, ideally, virtio-gpu and vhost-user-gpu both,
> > would
> >  > use the
> >  >  >  > infrastructure from the patch I linked to store the
> >  >  >  > virtio objects, so that they can be later shared
> with
> >  > other devices.
> >  >  >
> >  >  > I don't think such sharing is possible because the
> > resources are
> >  >  > identified by IDs that are local to the device. That
> also
> >  > complicates
> >  >  > migration.
> >  >  >
> >  >  > Regards,
> >  >  > Akihiko Odaki
> >  >  >
> >  >  > Hi Akihiko,
> >  >  >
> >  >  > As far as I understand, the feature to export
> > dma-bufs from the
> >  >  > virtgpu was introduced as part of the virtio cross-device
> > sharing
> >  >  > proposal [1]. Thus, it shall be posible. When
> > virtgpu ASSING_UUID,
> >  >  > it exports and identifies the dmabuf resource, so that
> > when the
> >  > dmabuf gets
> >  >  > shared inside the guest (e.g., with virtio-video), we can
> > use the
> >  > assigned
> >  >  > UUID to find the dmabuf in the host (using the patch that I
> >  > linked above),
> >  >  > and import it.
> >  >  >
> >  >  > [1] - https://lwn.net/Articl

Re: [QEMU PATCH v4 10/13] virtio-gpu: Resource UUID

2023-09-13 Thread Albert Esteve
On Wed, Sep 13, 2023 at 4:18 PM Albert Esteve  wrote:

>
>
> On Wed, Sep 13, 2023 at 3:43 PM Akihiko Odaki 
> wrote:
>
>> On 2023/09/13 21:58, Albert Esteve wrote:
>> >
>> >
>> > On Wed, Sep 13, 2023 at 2:22 PM Akihiko Odaki > > <mailto:akihiko.od...@daynix.com>> wrote:
>> >
>> > On 2023/09/13 20:34, Albert Esteve wrote:
>> >  >
>> >  >
>> >  > On Wed, Sep 13, 2023 at 12:34 PM Akihiko Odaki
>> > mailto:akihiko.od...@daynix.com>
>> >  > <mailto:akihiko.od...@daynix.com
>> > <mailto:akihiko.od...@daynix.com>>> wrote:
>> >  >
>> >  > On 2023/09/13 16:55, Albert Esteve wrote:
>> >  >  > Hi Antonio,
>> >  >  >
>> >  >  > If I'm not mistaken, this patch is related with:
>> >  >  >
>> >  >
>> > https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
>> > <
>> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>
>> >  >
>> >   <
>> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
>> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>>
>> >  >  >
>> >  >
>> >   <
>> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
>> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>
>> >  >
>> >   <
>> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
>> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>>>
>> >  >  > IMHO, ideally, virtio-gpu and vhost-user-gpu both, would
>> > use the
>> >  >  > infrastructure from the patch I linked to store the
>> >  >  > virtio objects, so that they can be later shared with
>> > other devices.
>> >  >
>> >  > I don't think such sharing is possible because the resources
>> are
>> >  > identified by IDs that are local to the device. That also
>> > complicates
>> >  > migration.
>> >  >
>> >  > Regards,
>> >  > Akihiko Odaki
>> >  >
>> >  > Hi Akihiko,
>> >  >
>> >  > As far as I understand, the feature to export dma-bufs from the
>> >  > virtgpu was introduced as part of the virtio cross-device sharing
>> >  > proposal [1]. Thus, it shall be posible. When
>> virtgpu ASSING_UUID,
>> >  > it exports and identifies the dmabuf resource, so that when the
>> > dmabuf gets
>> >  > shared inside the guest (e.g., with virtio-video), we can use the
>> > assigned
>> >  > UUID to find the dmabuf in the host (using the patch that I
>> > linked above),
>> >  > and import it.
>> >  >
>> >  > [1] - https://lwn.net/Articles/828988/
>> > <https://lwn.net/Articles/828988/> <
>> https://lwn.net/Articles/828988/
>> > <https://lwn.net/Articles/828988/>>
>> >
>> > The problem is that virtio-gpu can have other kind of resources like
>> > pixman and OpenGL textures and manage them and DMA-BUFs with unified
>> > resource ID.
>> >
>> >
>> > I see.
>> >
>> >
>> > So you cannot change:
>> > g_hash_table_insert(g->resource_uuids,
>> > GUINT_TO_POINTER(assign.resource_id), uuid);
>> > by:
>> > virtio_add_dmabuf(uuid, assign.resource_id);
>> >
>> > assign.resource_id is not DMA-BUF file descriptor, and the
>> underlying
>> > resource my not be DMA-BUF at first place.
>> >
>> >
>> > I didn't really look into the patch in-depth, so the code was intended
>> > to give an idea of how the implementation would look like with
>> > the cross-device patch API. Indeed, it is not the resource_id,
>> > (I just took a brief look at the virtio specificacion 1.2), but the
>> > underlying
>> > resource what we want to use here.
>> >
>> >
>> > Also, since this lives in the common code that is not used only by
>> > virtio-gpu-gl but also virtio-gpu, which supports migration, we also
>> > need to t

Re: [QEMU PATCH v4 10/13] virtio-gpu: Resource UUID

2023-09-13 Thread Albert Esteve
On Wed, Sep 13, 2023 at 3:43 PM Akihiko Odaki 
wrote:

> On 2023/09/13 21:58, Albert Esteve wrote:
> >
> >
> > On Wed, Sep 13, 2023 at 2:22 PM Akihiko Odaki  > <mailto:akihiko.od...@daynix.com>> wrote:
> >
> > On 2023/09/13 20:34, Albert Esteve wrote:
> >  >
> >  >
> >  > On Wed, Sep 13, 2023 at 12:34 PM Akihiko Odaki
> > mailto:akihiko.od...@daynix.com>
> >  > <mailto:akihiko.od...@daynix.com
> >     <mailto:akihiko.od...@daynix.com>>> wrote:
> >  >
> >  > On 2023/09/13 16:55, Albert Esteve wrote:
> >  >  > Hi Antonio,
> >  >  >
> >  >  > If I'm not mistaken, this patch is related with:
> >  >  >
> >  >
> > https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
> > <https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
> >
> >  >
> >   <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>>
> >  >  >
> >  >
> >   <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>
> >  >
> >   <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html <
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>>>
> >  >  > IMHO, ideally, virtio-gpu and vhost-user-gpu both, would
> > use the
> >  >  > infrastructure from the patch I linked to store the
> >  >  > virtio objects, so that they can be later shared with
> > other devices.
> >  >
> >  > I don't think such sharing is possible because the resources
> are
> >  > identified by IDs that are local to the device. That also
> > complicates
> >  > migration.
> >  >
> >  > Regards,
> >  > Akihiko Odaki
> >  >
> >  > Hi Akihiko,
> >  >
> >  > As far as I understand, the feature to export dma-bufs from the
> >  > virtgpu was introduced as part of the virtio cross-device sharing
> >  > proposal [1]. Thus, it shall be posible. When virtgpu ASSING_UUID,
> >  > it exports and identifies the dmabuf resource, so that when the
> > dmabuf gets
> >  > shared inside the guest (e.g., with virtio-video), we can use the
> > assigned
> >  > UUID to find the dmabuf in the host (using the patch that I
> > linked above),
> >  > and import it.
> >  >
> >  > [1] - https://lwn.net/Articles/828988/
> > <https://lwn.net/Articles/828988/> <https://lwn.net/Articles/828988/
> > <https://lwn.net/Articles/828988/>>
> >
> > The problem is that virtio-gpu can have other kind of resources like
> > pixman and OpenGL textures and manage them and DMA-BUFs with unified
> > resource ID.
> >
> >
> > I see.
> >
> >
> > So you cannot change:
> > g_hash_table_insert(g->resource_uuids,
> > GUINT_TO_POINTER(assign.resource_id), uuid);
> > by:
> > virtio_add_dmabuf(uuid, assign.resource_id);
> >
> > assign.resource_id is not DMA-BUF file descriptor, and the underlying
> > resource my not be DMA-BUF at first place.
> >
> >
> > I didn't really look into the patch in-depth, so the code was intended
> > to give an idea of how the implementation would look like with
> > the cross-device patch API. Indeed, it is not the resource_id,
> > (I just took a brief look at the virtio specificacion 1.2), but the
> > underlying
> > resource what we want to use here.
> >
> >
> > Also, since this lives in the common code that is not used only by
> > virtio-gpu-gl but also virtio-gpu, which supports migration, we also
> > need to take care of that. It is not a problem for DMA-BUF as
> > DMA-BUF is
> > not migratable anyway, but the situation is different in this case.
> >
> > Implementing cross-device sharing is certainly a possibility, but
> that
> > requires more than dealing with DMA-BUFs.
> >
> >
> > So, if I understood correctly, dmabufs are just a subset of the resources
> > that the gpu manages, or can assign UUIDs to. I am not sure why
> > the v

Re: [QEMU PATCH v4 10/13] virtio-gpu: Resource UUID

2023-09-13 Thread Albert Esteve
On Wed, Sep 13, 2023 at 2:22 PM Akihiko Odaki 
wrote:

> On 2023/09/13 20:34, Albert Esteve wrote:
> >
> >
> > On Wed, Sep 13, 2023 at 12:34 PM Akihiko Odaki  > <mailto:akihiko.od...@daynix.com>> wrote:
> >
> > On 2023/09/13 16:55, Albert Esteve wrote:
> >  > Hi Antonio,
> >  >
> >  > If I'm not mistaken, this patch is related with:
> >  >
> > https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
> > <https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
> >
> >  >
> > <https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
> > <https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
> >>
> >  > IMHO, ideally, virtio-gpu and vhost-user-gpu both, would use the
> >  > infrastructure from the patch I linked to store the
> >  > virtio objects, so that they can be later shared with other
> devices.
> >
> > I don't think such sharing is possible because the resources are
> > identified by IDs that are local to the device. That also complicates
> > migration.
> >
> > Regards,
> > Akihiko Odaki
> >
> > Hi Akihiko,
> >
> > As far as I understand, the feature to export dma-bufs from the
> > virtgpu was introduced as part of the virtio cross-device sharing
> > proposal [1]. Thus, it shall be posible. When virtgpu ASSING_UUID,
> > it exports and identifies the dmabuf resource, so that when the dmabuf
> gets
> > shared inside the guest (e.g., with virtio-video), we can use the
> assigned
> > UUID to find the dmabuf in the host (using the patch that I linked
> above),
> > and import it.
> >
> > [1] - https://lwn.net/Articles/828988/ <https://lwn.net/Articles/828988/
> >
>
> The problem is that virtio-gpu can have other kind of resources like
> pixman and OpenGL textures and manage them and DMA-BUFs with unified
> resource ID.
>

I see.


>
> So you cannot change:
> g_hash_table_insert(g->resource_uuids,
> GUINT_TO_POINTER(assign.resource_id), uuid);
> by:
> virtio_add_dmabuf(uuid, assign.resource_id);
>
> assign.resource_id is not DMA-BUF file descriptor, and the underlying
> resource my not be DMA-BUF at first place.
>

I didn't really look into the patch in-depth, so the code was intended
to give an idea of how the implementation would look like with
the cross-device patch API. Indeed, it is not the resource_id,
(I just took a brief look at the virtio specificacion 1.2), but the
underlying
resource what we want to use here.


>
> Also, since this lives in the common code that is not used only by
> virtio-gpu-gl but also virtio-gpu, which supports migration, we also
> need to take care of that. It is not a problem for DMA-BUF as DMA-BUF is
> not migratable anyway, but the situation is different in this case.
>
> Implementing cross-device sharing is certainly a possibility, but that
> requires more than dealing with DMA-BUFs.
>
>
So, if I understood correctly, dmabufs are just a subset of the resources
that the gpu manages, or can assign UUIDs to. I am not sure why
the virt gpu driver would want to send a ASSIGN_UUID for anything
that is not a dmabuf (are we sure it does?), but I am not super familiarized
with virtgpu to begin with.
But I see that internally, the GPU specs relate a UUID with a resource_id,
so we still need both tables:
- one to relate UUID with resource_id to be able to locate the underlying
resource
- the table that holds the dmabuf with the UUID for cross-device sharing

With that in mind, sounds to me that the support for cross-device sharing
could
be added on top of this patch, once
https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01850.html
lands.

I hope that makes sense.
Regards,
Albert


Re: [QEMU PATCH v4 10/13] virtio-gpu: Resource UUID

2023-09-13 Thread Albert Esteve
On Wed, Sep 13, 2023 at 12:34 PM Akihiko Odaki 
wrote:

> On 2023/09/13 16:55, Albert Esteve wrote:
> > Hi Antonio,
> >
> > If I'm not mistaken, this patch is related with:
> > https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
> > <https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html>
> > IMHO, ideally, virtio-gpu and vhost-user-gpu both, would use the
> > infrastructure from the patch I linked to store the
> > virtio objects, so that they can be later shared with other devices.
>
> I don't think such sharing is possible because the resources are
> identified by IDs that are local to the device. That also complicates
> migration.
>
> Regards,
> Akihiko Odaki
>
> Hi Akihiko,

As far as I understand, the feature to export dma-bufs from the
virtgpu was introduced as part of the virtio cross-device sharing
proposal [1]. Thus, it shall be posible. When virtgpu ASSING_UUID,
it exports and identifies the dmabuf resource, so that when the dmabuf gets
shared inside the guest (e.g., with virtio-video), we can use the assigned
UUID to find the dmabuf in the host (using the patch that I linked above),
and import it.

[1] - https://lwn.net/Articles/828988/


Re: [QEMU PATCH v4 10/13] virtio-gpu: Resource UUID

2023-09-13 Thread Albert Esteve
Hi Antonio,

If I'm not mistaken, this patch is related with:
https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01853.html
IMHO, ideally, virtio-gpu and vhost-user-gpu both, would use the
infrastructure from the patch I linked to store the
virtio objects, so that they can be later shared with other devices.

Which, in terms of code, would mean changing:
g_hash_table_insert(g->resource_uuids,
GUINT_TO_POINTER(assign.resource_id), uuid);
by:
virtio_add_dmabuf(uuid, assign.resource_id);

...and simplify part of the infrastructure.

Let me know what you think.

Regard,
Albert


Re: [PATCH v2 2/2] ui: add precondition for dpy_get_ui_info()

2023-09-12 Thread Albert Esteve
On Tue, Sep 12, 2023 at 8:28 AM  wrote:

> From: Marc-André Lureau 
>
> Ensure that it only get called when dpy_ui_info_supported(). The
> function should always return a result. There should be a non-null
> console or active_console.
>
> Modify the argument to be const as well.
>
> Signed-off-by: Marc-André Lureau 
> ---
>  include/ui/console.h | 2 +-
>  ui/console.c | 4 +++-
>  2 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/include/ui/console.h b/include/ui/console.h
> index 031e5d5194..08c0f0dc70 100644
> --- a/include/ui/console.h
> +++ b/include/ui/console.h
> @@ -329,7 +329,7 @@ void
> update_displaychangelistener(DisplayChangeListener *dcl,
>uint64_t interval);
>  void unregister_displaychangelistener(DisplayChangeListener *dcl);
>
> -bool dpy_ui_info_supported(QemuConsole *con);
> +bool dpy_ui_info_supported(const QemuConsole *con);
>  const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con);
>  int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay);
>
> diff --git a/ui/console.c b/ui/console.c
> index 0fbec4d0bd..1c710a6d5e 100644
> --- a/ui/console.c
> +++ b/ui/console.c
> @@ -803,7 +803,7 @@ static void dpy_set_ui_info_timer(void *opaque)
>  con->hw_ops->ui_info(con->hw, head, >ui_info);
>  }
>
> -bool dpy_ui_info_supported(QemuConsole *con)
> +bool dpy_ui_info_supported(const QemuConsole *con)
>  {
>  if (con == NULL) {
>  con = active_console;
> @@ -817,6 +817,8 @@ bool dpy_ui_info_supported(QemuConsole *con)
>
>  const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
>  {
> +assert(dpy_ui_info_supported(con));
> +
>

I wonder if it would be better to avoid the assertion and return NULL
if not supported, and let the caller handle (logging an error for example).

But there are many other similar assertions in this file, so it is probably
good as it is...

Reviewed-by: Albert Esteve 


>  if (con == NULL) {
>  con = active_console;
>  }
> --
> 2.41.0
>
>


Re: [PATCH v2 1/2] ui: fix crash when there are no active_console

2023-09-12 Thread Albert Esteve
On Tue, Sep 12, 2023 at 8:28 AM  wrote:

> From: Marc-André Lureau 
>
> Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
> 0x55888630 in dpy_ui_info_supported (con=0x0) at
> ../ui/console.c:812
> 812 return con->hw_ops->ui_info != NULL;
> (gdb) bt
> #0  0x55888630 in dpy_ui_info_supported (con=0x0) at
> ../ui/console.c:812
> #1  0x558a44b1 in protocol_client_msg (vs=0x578c76c0,
> data=0x581e93f0 , len=24) at ../ui/vnc.c:2585
> #2  0x558a19ac in vnc_client_read (vs=0x578c76c0) at
> ../ui/vnc.c:1607
> #3  0x558a1ac2 in vnc_client_io (ioc=0x581eb0e0,
> condition=G_IO_IN, opaque=0x578c76c0) at ../ui/vnc.c:1635
>
> Fixes:
> https://issues.redhat.com/browse/RHEL-2600
>
> Signed-off-by: Marc-André Lureau 
> ---
>  ui/console.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/ui/console.c b/ui/console.c
> index 90ae4be602..0fbec4d0bd 100644
> --- a/ui/console.c
> +++ b/ui/console.c
> @@ -808,6 +808,9 @@ bool dpy_ui_info_supported(QemuConsole *con)
>  if (con == NULL) {
>  con = active_console;
>  }
> +if (con == NULL) {
> +    return false;
> +}
>
>  return con->hw_ops->ui_info != NULL;
>  }
> --
> 2.41.0
>
> Reviewed-by: Albert Esteve 


Re: [PATCH] ui: fix crash when there are no active_console

2023-09-11 Thread Albert Esteve
On Mon, Sep 11, 2023 at 4:42 PM Albert Esteve  wrote:

>
>
> On Mon, Sep 11, 2023 at 4:08 PM  wrote:
>
>> From: Marc-André Lureau 
>>
>> Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
>> 0x55888630 in dpy_ui_info_supported (con=0x0) at
>> ../ui/console.c:812
>> 812 return con->hw_ops->ui_info != NULL;
>> (gdb) bt
>> #0  0x55888630 in dpy_ui_info_supported (con=0x0) at
>> ../ui/console.c:812
>> #1  0x558a44b1 in protocol_client_msg (vs=0x578c76c0,
>> data=0x581e93f0 , len=24) at ../ui/vnc.c:2585
>> #2  0x558a19ac in vnc_client_read (vs=0x578c76c0) at
>> ../ui/vnc.c:1607
>> #3  0x558a1ac2 in vnc_client_io (ioc=0x581eb0e0,
>> condition=G_IO_IN, opaque=0x578c76c0) at ../ui/vnc.c:1635
>>
>> Fixes:
>> https://issues.redhat.com/browse/RHEL-2600
>>
>> Signed-off-by: Marc-André Lureau 
>> ---
>>  ui/console.c | 25 +
>>  1 file changed, 25 insertions(+)
>>
>> diff --git a/ui/console.c b/ui/console.c
>> index 90ae4be602..0f31ecece6 100644
>> --- a/ui/console.c
>> +++ b/ui/console.c
>> @@ -808,6 +808,9 @@ bool dpy_ui_info_supported(QemuConsole *con)
>>  if (con == NULL) {
>>  con = active_console;
>>  }
>> +if (con == NULL) {
>> +return false;
>> +}
>>
>>  return con->hw_ops->ui_info != NULL;
>>  }
>> @@ -817,6 +820,9 @@ const QemuUIInfo *dpy_get_ui_info(const QemuConsole
>> *con)
>>  if (con == NULL) {
>>  con = active_console;
>>  }
>> +if (con == NULL) {
>> +return NULL;
>> +}
>>
>>  return >ui_info;
>>  }
>> @@ -826,6 +832,9 @@ int dpy_set_ui_info(QemuConsole *con, QemuUIInfo
>> *info, bool delay)
>>  if (con == NULL) {
>>  con = active_console;
>>  }
>> +if (con == NULL) {
>> +return -1;
>> +}
>>
>>  if (!dpy_ui_info_supported(con)) {
>>  return -1;
>> @@ -1401,6 +1410,10 @@ QEMUCursor *qemu_console_get_cursor(QemuConsole
>> *con)
>>  if (con == NULL) {
>>  con = active_console;
>>  }
>> +if (con == NULL) {
>> +return NULL;
>> +}
>> +
>>  return QEMU_IS_GRAPHIC_CONSOLE(con) ?
>> QEMU_GRAPHIC_CONSOLE(con)->cursor : NULL;
>>  }
>>
>> @@ -1414,6 +1427,10 @@ bool qemu_console_is_graphic(QemuConsole *con)
>>  if (con == NULL) {
>>  con = active_console;
>>  }
>> +if (con == NULL) {
>> +return false;
>> +}
>> +
>>
>
I had miss this one before:
```
return QEMU_IS_GRAPHIC_CONSOLE(con);
```

Regards,
Albert


>  return con && QEMU_IS_GRAPHIC_CONSOLE(con);
>>  }
>>
>> @@ -1422,6 +1439,10 @@ bool qemu_console_is_fixedsize(QemuConsole *con)
>>  if (con == NULL) {
>>  con = active_console;
>>  }
>> +if (con == NULL) {
>> +return false;
>> +}
>> +
>>
>
> The "con" initialization condition is already checked in the line below
> (now unnecessarily).
> If the if block is preferred for consistency with other functions, we
> could remove the con check from
> the condition below:
> ```
> return QEMU_IS_GRAPHIC_CONSOLE(con) || QEMU_IS_FIXED_TEXT_CONSOLE(con);
> ```
>
>
>>  return con && (QEMU_IS_GRAPHIC_CONSOLE(con) ||
>> QEMU_IS_FIXED_TEXT_CONSOLE(con));
>>  }
>>
>> @@ -1493,6 +1514,10 @@ int qemu_console_get_index(QemuConsole *con)
>>  if (con == NULL) {
>>  con = active_console;
>>  }
>> +if (con == NULL) {
>> +return -1;
>> +}
>> +
>>
>
> Same as before, here we could simply "return con->index;"
>
>
>>  return con ? con->index : -1;
>
>  }
>>
>> --
>> 2.41.0
>>
>>
>>


Re: [PATCH] ui: fix crash when there are no active_console

2023-09-11 Thread Albert Esteve
On Mon, Sep 11, 2023 at 4:08 PM  wrote:

> From: Marc-André Lureau 
>
> Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
> 0x55888630 in dpy_ui_info_supported (con=0x0) at
> ../ui/console.c:812
> 812 return con->hw_ops->ui_info != NULL;
> (gdb) bt
> #0  0x55888630 in dpy_ui_info_supported (con=0x0) at
> ../ui/console.c:812
> #1  0x558a44b1 in protocol_client_msg (vs=0x578c76c0,
> data=0x581e93f0 , len=24) at ../ui/vnc.c:2585
> #2  0x558a19ac in vnc_client_read (vs=0x578c76c0) at
> ../ui/vnc.c:1607
> #3  0x558a1ac2 in vnc_client_io (ioc=0x581eb0e0,
> condition=G_IO_IN, opaque=0x578c76c0) at ../ui/vnc.c:1635
>
> Fixes:
> https://issues.redhat.com/browse/RHEL-2600
>
> Signed-off-by: Marc-André Lureau 
> ---
>  ui/console.c | 25 +
>  1 file changed, 25 insertions(+)
>
> diff --git a/ui/console.c b/ui/console.c
> index 90ae4be602..0f31ecece6 100644
> --- a/ui/console.c
> +++ b/ui/console.c
> @@ -808,6 +808,9 @@ bool dpy_ui_info_supported(QemuConsole *con)
>  if (con == NULL) {
>  con = active_console;
>  }
> +if (con == NULL) {
> +return false;
> +}
>
>  return con->hw_ops->ui_info != NULL;
>  }
> @@ -817,6 +820,9 @@ const QemuUIInfo *dpy_get_ui_info(const QemuConsole
> *con)
>  if (con == NULL) {
>  con = active_console;
>  }
> +if (con == NULL) {
> +return NULL;
> +}
>
>  return >ui_info;
>  }
> @@ -826,6 +832,9 @@ int dpy_set_ui_info(QemuConsole *con, QemuUIInfo
> *info, bool delay)
>  if (con == NULL) {
>  con = active_console;
>  }
> +if (con == NULL) {
> +return -1;
> +}
>
>  if (!dpy_ui_info_supported(con)) {
>  return -1;
> @@ -1401,6 +1410,10 @@ QEMUCursor *qemu_console_get_cursor(QemuConsole
> *con)
>  if (con == NULL) {
>  con = active_console;
>  }
> +if (con == NULL) {
> +return NULL;
> +}
> +
>  return QEMU_IS_GRAPHIC_CONSOLE(con) ?
> QEMU_GRAPHIC_CONSOLE(con)->cursor : NULL;
>  }
>
> @@ -1414,6 +1427,10 @@ bool qemu_console_is_graphic(QemuConsole *con)
>  if (con == NULL) {
>  con = active_console;
>  }
> +if (con == NULL) {
> +return false;
> +}
> +
>  return con && QEMU_IS_GRAPHIC_CONSOLE(con);
>  }
>
> @@ -1422,6 +1439,10 @@ bool qemu_console_is_fixedsize(QemuConsole *con)
>  if (con == NULL) {
>  con = active_console;
>  }
> +if (con == NULL) {
> +return false;
> +}
> +
>

The "con" initialization condition is already checked in the line below
(now unnecessarily).
If the if block is preferred for consistency with other functions, we could
remove the con check from
the condition below:
```
return QEMU_IS_GRAPHIC_CONSOLE(con) || QEMU_IS_FIXED_TEXT_CONSOLE(con);
```


>  return con && (QEMU_IS_GRAPHIC_CONSOLE(con) ||
> QEMU_IS_FIXED_TEXT_CONSOLE(con));
>  }
>
> @@ -1493,6 +1514,10 @@ int qemu_console_get_index(QemuConsole *con)
>  if (con == NULL) {
>  con = active_console;
>  }
> +if (con == NULL) {
> +return -1;
> +}
> +
>

Same as before, here we could simply "return con->index;"


>  return con ? con->index : -1;

 }
>
> --
> 2.41.0
>
>
>


Re: [PATCH v8 0/4] Virtio shared dma-buf

2023-09-11 Thread Albert Esteve
On Fri, Sep 8, 2023 at 5:55 PM Philippe Mathieu-Daudé 
wrote:

> On 8/9/23 17:47, Albert Esteve wrote:
> > v1 link ->
> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg00598.html
> > v2 link ->
> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg04530.html
> > v3 link ->
> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg06126.html
> > v4 link ->
> https://lists.gnu.org/archive/html/qemu-devel/2023-06/msg05174.html
> > v5 link ->
> https://lists.gnu.org/archive/html/qemu-devel/2023-08/msg00255.html
> > v6 link ->
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg00987.html
> > v7 link ->
> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01190.html
> > v7 -> v8:
> > - Move "qemu/osdep.h" include to the virtio-dmabuf source file.
> > - Remove duplicated glib include.
> > - Change the title of commits to better reflect the path to the change
>
> Thank Albert you for the various respin with review comment addressed.
>
>
Hi Philippe,

Thank you for taking the time to review!


> Michael, no other comment on my side.
>
> Regards,
>
> Phil.
>
> > This patch covers the required steps to add support for virtio
> cross-device resource sharing[1],
> > which support is already available in the kernel.
>
> > Albert Esteve (4):
> >util/uuid: add a hash function
> >hw/display: introduce virtio-dmabuf
> >vhost-user: add shared_object msg
> >libvhost-user: handle shared_object msg
>
>


[PATCH v8 4/4] libvhost-user: handle shared_object msg

2023-09-08 Thread Albert Esteve
In the libvhost-user library we need to
handle VHOST_USER_GET_SHARED_OBJECT requests,
and add helper functions to allow sending messages
to interact with the virtio shared objects
hash table.

Signed-off-by: Albert Esteve 
---
 subprojects/libvhost-user/libvhost-user.c | 120 ++
 subprojects/libvhost-user/libvhost-user.h |  55 +-
 2 files changed, 174 insertions(+), 1 deletion(-)

diff --git a/subprojects/libvhost-user/libvhost-user.c 
b/subprojects/libvhost-user/libvhost-user.c
index 0469a50101..676e57a468 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -161,6 +161,7 @@ vu_request_to_string(unsigned int req)
 REQ(VHOST_USER_GET_MAX_MEM_SLOTS),
 REQ(VHOST_USER_ADD_MEM_REG),
 REQ(VHOST_USER_REM_MEM_REG),
+REQ(VHOST_USER_GET_SHARED_OBJECT),
 REQ(VHOST_USER_MAX),
 };
 #undef REQ
@@ -900,6 +901,24 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
 return false;
 }
 
+static bool
+vu_get_shared_object(VuDev *dev, VhostUserMsg *vmsg)
+{
+int fd_num = 0;
+int dmabuf_fd = -1;
+if (dev->iface->get_shared_object) {
+dmabuf_fd = dev->iface->get_shared_object(
+dev, >payload.object.uuid[0]);
+}
+if (dmabuf_fd != -1) {
+DPRINT("dmabuf_fd found for requested UUID\n");
+vmsg->fds[fd_num++] = dmabuf_fd;
+}
+vmsg->fd_num = fd_num;
+
+return true;
+}
+
 static bool
 vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
 {
@@ -1403,6 +1422,105 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq 
*vq, int fd,
 return vu_process_message_reply(dev, );
 }
 
+bool
+vu_lookup_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN],
+int *dmabuf_fd)
+{
+bool result = false;
+VhostUserMsg msg_reply;
+VhostUserMsg msg = {
+.request = VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP,
+.size = sizeof(msg.payload.object),
+.flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK,
+};
+
+memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN);
+
+if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) {
+return false;
+}
+
+pthread_mutex_lock(>backend_mutex);
+if (!vu_message_write(dev, dev->backend_fd, )) {
+goto out;
+}
+
+if (!vu_message_read_default(dev, dev->backend_fd, _reply)) {
+goto out;
+}
+
+if (msg_reply.request != msg.request) {
+DPRINT("Received unexpected msg type. Expected %d, received %d",
+   msg.request, msg_reply.request);
+goto out;
+}
+
+if (msg_reply.fd_num != 1) {
+DPRINT("Received unexpected number of fds. Expected 1, received %d",
+   msg_reply.fd_num);
+goto out;
+}
+
+*dmabuf_fd = msg_reply.fds[0];
+result = *dmabuf_fd > 0 && msg_reply.payload.u64 == 0;
+out:
+pthread_mutex_unlock(>backend_mutex);
+
+return result;
+}
+
+static bool
+vu_send_message(VuDev *dev, VhostUserMsg *vmsg)
+{
+bool result = false;
+pthread_mutex_lock(>backend_mutex);
+if (!vu_message_write(dev, dev->backend_fd, vmsg)) {
+goto out;
+}
+
+result = true;
+out:
+pthread_mutex_unlock(>backend_mutex);
+
+return result;
+}
+
+bool
+vu_add_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN])
+{
+VhostUserMsg msg = {
+.request = VHOST_USER_BACKEND_SHARED_OBJECT_ADD,
+.size = sizeof(msg.payload.object),
+.flags = VHOST_USER_VERSION,
+};
+
+memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN);
+
+if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) {
+return false;
+}
+
+return vu_send_message(dev, );
+}
+
+bool
+vu_rm_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN])
+{
+VhostUserMsg msg = {
+.request = VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE,
+.size = sizeof(msg.payload.object),
+.flags = VHOST_USER_VERSION,
+};
+
+memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN);
+
+if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) {
+return false;
+}
+
+return vu_send_message(dev, );
+}
+
 static bool
 vu_set_vring_call_exec(VuDev *dev, VhostUserMsg *vmsg)
 {
@@ -1943,6 +2061,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
 return vu_add_mem_reg(dev, vmsg);
 case VHOST_USER_REM_MEM_REG:
 return vu_rem_mem_reg(dev, vmsg);
+case VHOST_USER_GET_SHARED_OBJECT:
+return vu_get_shared_object(dev, vmsg);
 default:
 vmsg_close_fds(vmsg);
 vu_panic(dev, "Unhandled request: %d", vmsg->request);
diff --git a/subprojects/libvhost-user/libvhost-user.h 
b/subprojects/libvhost-user/libvhost-user.h
index 708370c5f5..b36a42a7ca 100644
--- a/subprojects/libv

[PATCH v8 1/4] util/uuid: add a hash function

2023-09-08 Thread Albert Esteve
Add hash function to uuid module using the
djb2 hash algorithm.

Add a couple simple unit tests for the hash
function, checking collisions for similar UUIDs.

Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Albert Esteve 
---
 include/qemu/uuid.h|  2 ++
 tests/unit/test-uuid.c | 27 +++
 util/uuid.c| 15 +++
 3 files changed, 44 insertions(+)

diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h
index dc40ee1fc9..e24a1099e4 100644
--- a/include/qemu/uuid.h
+++ b/include/qemu/uuid.h
@@ -96,4 +96,6 @@ int qemu_uuid_parse(const char *str, QemuUUID *uuid);
 
 QemuUUID qemu_uuid_bswap(QemuUUID uuid);
 
+uint32_t qemu_uuid_hash(const void *uuid);
+
 #endif
diff --git a/tests/unit/test-uuid.c b/tests/unit/test-uuid.c
index c111de5fc1..aedc125ae9 100644
--- a/tests/unit/test-uuid.c
+++ b/tests/unit/test-uuid.c
@@ -171,6 +171,32 @@ static void test_uuid_unparse_strdup(void)
 }
 }
 
+static void test_uuid_hash(void)
+{
+QemuUUID uuid;
+int i;
+
+for (i = 0; i < 100; i++) {
+qemu_uuid_generate();
+/* Obtain the UUID hash */
+uint32_t hash_a = qemu_uuid_hash();
+int data_idx = g_random_int_range(0, 15);
+/* Change a single random byte of the UUID */
+if (uuid.data[data_idx] < 0xFF) {
+uuid.data[data_idx]++;
+} else {
+uuid.data[data_idx]--;
+}
+/* Obtain the UUID hash again */
+uint32_t hash_b = qemu_uuid_hash();
+/*
+ * Both hashes shall be different (avoid collision)
+ * for any change in the UUID fields
+ */
+g_assert_cmpint(hash_a, !=, hash_b);
+}
+}
+
 int main(int argc, char **argv)
 {
 g_test_init(, , NULL);
@@ -179,6 +205,7 @@ int main(int argc, char **argv)
 g_test_add_func("/uuid/parse", test_uuid_parse);
 g_test_add_func("/uuid/unparse", test_uuid_unparse);
 g_test_add_func("/uuid/unparse_strdup", test_uuid_unparse_strdup);
+g_test_add_func("/uuid/hash", test_uuid_hash);
 
 return g_test_run();
 }
diff --git a/util/uuid.c b/util/uuid.c
index b1108dde78..b366961bc6 100644
--- a/util/uuid.c
+++ b/util/uuid.c
@@ -116,3 +116,18 @@ QemuUUID qemu_uuid_bswap(QemuUUID uuid)
 bswap16s(_high_and_version);
 return uuid;
 }
+
+/* djb2 hash algorithm */
+uint32_t qemu_uuid_hash(const void *uuid)
+{
+QemuUUID *qid = (QemuUUID *) uuid;
+uint32_t h = 5381;
+int i;
+
+for (i = 0; i < ARRAY_SIZE(qid->data); i++) {
+h = (h << 5) + h + qid->data[i];
+}
+
+return h;
+}
+
-- 
2.41.0




[PATCH v8 2/4] hw/display: introduce virtio-dmabuf

2023-09-08 Thread Albert Esteve
This API manages objects (in this iteration,
dmabuf fds) that can be shared along different
virtio devices, associated to a UUID.

The API allows the different devices to add,
remove and/or retrieve the objects by simply
invoking the public functions that reside in the
virtio-dmabuf file.

For vhost backends, the API stores the pointer
to the backend holding the object.

Suggested-by: Gerd Hoffmann 
Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Albert Esteve 
---
 MAINTAINERS   |   7 ++
 hw/display/meson.build|   1 +
 hw/display/virtio-dmabuf.c| 138 ++
 include/hw/virtio/virtio-dmabuf.h | 100 ++
 tests/unit/meson.build|   1 +
 tests/unit/test-virtio-dmabuf.c   | 137 +
 6 files changed, 384 insertions(+)
 create mode 100644 hw/display/virtio-dmabuf.c
 create mode 100644 include/hw/virtio/virtio-dmabuf.h
 create mode 100644 tests/unit/test-virtio-dmabuf.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b471973e1e..42700fb5aa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2150,6 +2150,13 @@ T: git https://gitlab.com/cohuck/qemu.git s390-next
 T: git https://github.com/borntraeger/qemu.git s390-next
 L: qemu-s3...@nongnu.org
 
+virtio-dmabuf
+M: Albert Esteve 
+S: Supported
+F: hw/display/virtio-dmabuf.c
+F: include/hw/virtio/virtio-dmabuf.h
+F: tests/unit/test-virtio-dmabuf.c
+
 virtiofs
 M: Stefan Hajnoczi 
 S: Supported
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 413ba4ab24..05619c6968 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -37,6 +37,7 @@ system_ss.add(when: 'CONFIG_MACFB', if_true: files('macfb.c'))
 system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c'))
 
 system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c'))
+system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c'))
 
 if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or
 config_all_devices.has_key('CONFIG_VGA_PCI') or
diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
new file mode 100644
index 00..4a8e430f3d
--- /dev/null
+++ b/hw/display/virtio-dmabuf.c
@@ -0,0 +1,138 @@
+/*
+ * Virtio Shared dma-buf
+ *
+ * Copyright Red Hat, Inc. 2023
+ *
+ * Authors:
+ * Albert Esteve 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/virtio/virtio-dmabuf.h"
+
+
+static GMutex lock;
+static GHashTable *resource_uuids;
+
+/*
+ * uuid_equal_func: wrapper for UUID is_equal function to
+ * satisfy g_hash_table_new expected parameters signatures.
+ */
+static int uuid_equal_func(const void *lhv, const void *rhv)
+{
+return qemu_uuid_is_equal(lhv, rhv);
+}
+
+static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value)
+{
+bool result = false;
+
+g_mutex_lock();
+if (resource_uuids == NULL) {
+resource_uuids = g_hash_table_new_full(qemu_uuid_hash,
+   uuid_equal_func,
+   NULL,
+   g_free);
+}
+if (g_hash_table_lookup(resource_uuids, uuid) == NULL) {
+result = g_hash_table_insert(resource_uuids, uuid, value);
+}
+g_mutex_unlock();
+
+return result;
+}
+
+bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
+{
+bool result;
+VirtioSharedObject *vso;
+if (udmabuf_fd < 0) {
+return false;
+}
+vso = g_new(VirtioSharedObject, 1);
+vso->type = TYPE_DMABUF;
+vso->value = GINT_TO_POINTER(udmabuf_fd);
+result = virtio_add_resource(uuid, vso);
+
+return result;
+}
+
+bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
+{
+bool result;
+VirtioSharedObject *vso;
+if (dev == NULL) {
+return false;
+}
+vso = g_new(VirtioSharedObject, 1);
+vso->type = TYPE_VHOST_DEV;
+vso->value = dev;
+result = virtio_add_resource(uuid, vso);
+
+return result;
+}
+
+bool virtio_remove_resource(const QemuUUID *uuid)
+{
+bool result;
+g_mutex_lock();
+result = g_hash_table_remove(resource_uuids, uuid);
+g_mutex_unlock();
+
+return result;
+}
+
+static VirtioSharedObject *get_shared_object(const QemuUUID *uuid)
+{
+gpointer lookup_res = NULL;
+
+g_mutex_lock();
+if (resource_uuids != NULL) {
+lookup_res = g_hash_table_lookup(resource_uuids, uuid);
+}
+g_mutex_unlock();
+
+return (VirtioSharedObject *) lookup_res;
+}
+
+int virtio_lookup_dmabuf(const QemuUUID *uuid)
+{
+VirtioSharedObject *vso = get_shared_object(uuid);
+if (vso == NULL) {
+return -1;
+}
+assert(vso->type == TYPE_DMABUF);
+return GPOINTER_TO_INT(vso->value);
+}
+
+struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
+{
+Vi

[PATCH v8 0/4] Virtio shared dma-buf

2023-09-08 Thread Albert Esteve
v1 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg00598.html
v2 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg04530.html
v3 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg06126.html
v4 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-06/msg05174.html
v5 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-08/msg00255.html
v6 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg00987.html
v7 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg01190.html
v7 -> v8:
- Move "qemu/osdep.h" include to the virtio-dmabuf source file.
- Remove duplicated glib include.
- Change the title of commits to better reflect the path to the change

This patch covers the required steps to add support for virtio cross-device 
resource sharing[1],
which support is already available in the kernel.

The main usecase will be sharing dma buffers from virtio-gpu devices (as the 
exporter
-see VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID in [2]), to virtio-video (under 
discussion)
devices (as the buffer-user or importer). Therefore, even though virtio specs 
talk about
resources or objects[3], this patch adds the infrastructure with dma-bufs in 
mind.
Note that virtio specs let the devices themselves define what a vitio object is.

These are the main parts that are covered in the patch:

- Add hash function to uuid module
- Shared resources table, to hold all resources that can be shared in the host 
and their assigned UUID,
  or pointers to the backend holding the resource
- Internal shared table API for virtio devices to add, lookup and remove 
resources
- Unit test to verify the API
- New messages to the vhost-user protocol to allow backend to interact with the 
shared
  table API through the control socket
- New vhost-user feature bit to enable shared objects feature

Applies cleanly to 03a3a62fbd0aa5227e978eef3c67d3978aec9e5f

[1] - https://lwn.net/Articles/828988/
[2] - 
https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-3730006
[3] - 
https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-10500011

Albert Esteve (4):
  util/uuid: add a hash function
  hw/display: introduce virtio-dmabuf
  vhost-user: add shared_object msg
  libvhost-user: handle shared_object msg

 MAINTAINERS   |   7 +
 docs/interop/vhost-user.rst   |  57 
 hw/display/meson.build|   1 +
 hw/display/virtio-dmabuf.c| 138 ++
 hw/virtio/vhost-user.c| 168 --
 include/hw/virtio/vhost-backend.h |   3 +
 include/hw/virtio/virtio-dmabuf.h | 100 +
 include/qemu/uuid.h   |   2 +
 subprojects/libvhost-user/libvhost-user.c | 120 
 subprojects/libvhost-user/libvhost-user.h |  55 ++-
 tests/unit/meson.build|   1 +
 tests/unit/test-uuid.c|  27 
 tests/unit/test-virtio-dmabuf.c   | 137 ++
 util/uuid.c   |  15 ++
 14 files changed, 818 insertions(+), 13 deletions(-)
 create mode 100644 hw/display/virtio-dmabuf.c
 create mode 100644 include/hw/virtio/virtio-dmabuf.h
 create mode 100644 tests/unit/test-virtio-dmabuf.c

-- 
2.41.0




[PATCH v8 3/4] vhost-user: add shared_object msg

2023-09-08 Thread Albert Esteve
Add three new vhost-user protocol
`VHOST_USER_BACKEND_SHARED_OBJECT_* messages`.
These new messages are sent from vhost-user
back-ends to interact with the virtio-dmabuf
table in order to add or remove themselves as
virtio exporters, or lookup for virtio dma-buf
shared objects.

The action taken in the front-end depends
on the type stored in the virtio shared
object hash table.

When the table holds a pointer to a vhost
backend for a given UUID, the front-end sends
a VHOST_USER_GET_SHARED_OBJECT to the
backend holding the shared object.

The messages can only be sent after successfully
negotiating a new VHOST_USER_PROTOCOL_F_SHARED_OBJECT
vhost-user protocol feature bit.

Finally, refactor code to send response message so
that all common parts both for the common REPLY_ACK
case, and other data responses, can call it and
avoid code repetition.

Signed-off-by: Albert Esteve 
---
 docs/interop/vhost-user.rst   |  57 ++
 hw/virtio/vhost-user.c| 168 +++---
 include/hw/virtio/vhost-backend.h |   3 +
 3 files changed, 216 insertions(+), 12 deletions(-)

diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index 5a070adbc1..415bb47a19 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -1440,6 +1440,18 @@ Front-end message types
   query the back-end for its device status as defined in the Virtio
   specification.
 
+``VHOST_USER_GET_SHARED_OBJECT``
+  :id: 41
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: dmabuf fd
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, and the UUID is found
+  in the exporters cache, this message is submitted by the front-end
+  to retrieve a given dma-buf fd from a given back-end, determined by
+  the requested UUID. Back-end will reply passing the fd when the operation
+  is successful, or no fd otherwise.
 
 Back-end message types
 --
@@ -1528,6 +1540,51 @@ is sent by the front-end.
 
   The state.num field is currently reserved and must be set to 0.
 
+``VHOST_USER_BACKEND_SHARED_OBJECT_ADD``
+  :id: 6
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: N/A
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backends to add themselves as exporters to the virtio shared lookup
+  table. The back-end device gets associated with a UUID in the shared table.
+  The back-end is responsible of keeping its own table with exported dma-buf 
fds.
+  When another back-end tries to import the resource associated with the UUID,
+  it will send a message to the front-end, which will act as a proxy to the
+  exporter back-end. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and
+  the back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must
+  respond with zero when operation is successfully completed, or non-zero
+  otherwise.
+
+``VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE``
+  :id: 7
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: N/A
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backend to remove themselves from to the virtio-dmabuf shared
+  table API. The shared table will remove the back-end device associated with
+  the UUID. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and the
+  back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond
+  with zero when operation is successfully completed, or non-zero otherwise.
+
+``VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP``
+  :id: 8
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: dmabuf fd and ``u64``
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backends to retrieve a given dma-buf fd from the virtio-dmabuf
+  shared table given a UUID. Frontend will reply passing the fd and a zero
+  when the operation is successful, or non-zero otherwise. Note that if the
+  operation fails, no fd is sent to the backend.
+
 .. _reply_ack:
 
 VHOST_USER_PROTOCOL_F_REPLY_ACK
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 8dcf049d42..08ab256613 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -10,6 +10,7 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "hw/virtio/virtio-dmabuf.h"
 #include "hw/virtio/vhost.h"
 #include "hw/virtio/virtio-crypto.h"
 #include "hw/virtio/vhost-user.h"
@@ -21,6 +22,7 @@
 #include "sysemu/kvm.h"
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
+#include "qemu/uuid.h"
 #include 

Re: [PATCH v7 2/4] virtio-dmabuf: introduce virtio-dmabuf

2023-09-07 Thread Albert Esteve
On Thu, Sep 7, 2023 at 10:19 AM Philippe Mathieu-Daudé 
wrote:

> On 7/9/23 09:43, Albert Esteve wrote:
> > This API manages objects (in this iteration,
> > dmabuf fds) that can be shared along different
> > virtio devices, associated to a UUID.
> >
> > The API allows the different devices to add,
> > remove and/or retrieve the objects by simply
> > invoking the public functions that reside in the
> > virtio-dmabuf file.
> >
> > For vhost backends, the API stores the pointer
> > to the backend holding the object.
> >
> > Suggested-by: Gerd Hoffmann 
> > Signed-off-by: Albert Esteve 
> > ---
> >   MAINTAINERS   |   7 ++
> >   hw/display/meson.build|   1 +
> >   hw/display/virtio-dmabuf.c| 136 +
> >   include/hw/virtio/virtio-dmabuf.h | 103 ++
> >   tests/unit/meson.build|   1 +
> >   tests/unit/test-virtio-dmabuf.c   | 137 ++
> >   6 files changed, 385 insertions(+)
> >   create mode 100644 hw/display/virtio-dmabuf.c
> >   create mode 100644 include/hw/virtio/virtio-dmabuf.h
> >   create mode 100644 tests/unit/test-virtio-dmabuf.c
>
>
> > diff --git a/include/hw/virtio/virtio-dmabuf.h
> b/include/hw/virtio/virtio-dmabuf.h
> > new file mode 100644
> > index 00..202eec5868
> > --- /dev/null
> > +++ b/include/hw/virtio/virtio-dmabuf.h
> > @@ -0,0 +1,103 @@
> > +/*
> > + * Virtio Shared dma-buf
> > + *
> > + * Copyright Red Hat, Inc. 2023
> > + *
> > + * Authors:
> > + * Albert Esteve 
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2.
> > + * See the COPYING file in the top-level directory.
> > + */
> > +
> > +#ifndef VIRTIO_DMABUF_H
> > +#define VIRTIO_DMABUF_H
> > +
> > +#include "qemu/osdep.h"
>
> See https://www.qemu.org/docs/master/devel/style.html#include-directives
>
>Do not include “qemu/osdep.h” from header files since the .c
>file will have already included it.
>
> > +#include 
>
> This one is also included via "qemu/osdep.h" -> "glib-compat.h"
>
> > +#include "qemu/uuid.h"
> > +#include "vhost.h"
> > +
> > +typedef enum SharedObjectType {
> > +TYPE_INVALID = 0,
> > +TYPE_DMABUF,
> > +TYPE_VHOST_DEV,
> > +} SharedObjectType;
> > +
> > +typedef struct VirtioSharedObject {
> > +SharedObjectType type;
> > +gpointer value;
> > +} VirtioSharedObject;
>
> Since this need a repost, better use "hw/display: Introduce
> virtio-dmabuf" as patch subject (and "util/uuid" prefix for the previous
> patch).
>
> Otherwise LGTM, so with these changes:
>
> Reviewed-by: Philippe Mathieu-Daudé 
>
>
Thanks a lot! I'll do it for the next review.
Any other comment on the other commits?


[PATCH v7 3/4] vhost-user: add shared_object msg

2023-09-07 Thread Albert Esteve
Add three new vhost-user protocol
`VHOST_USER_BACKEND_SHARED_OBJECT_* messages`.
These new messages are sent from vhost-user
back-ends to interact with the virtio-dmabuf
table in order to add or remove themselves as
virtio exporters, or lookup for virtio dma-buf
shared objects.

The action taken in the front-end depends
on the type stored in the virtio shared
object hash table.

When the table holds a pointer to a vhost
backend for a given UUID, the front-end sends
a VHOST_USER_GET_SHARED_OBJECT to the
backend holding the shared object.

The messages can only be sent after successfully
negotiating a new VHOST_USER_PROTOCOL_F_SHARED_OBJECT
vhost-user protocol feature bit.

Finally, refactor code to send response message so
that all common parts both for the common REPLY_ACK
case, and other data responses, can call it and
avoid code repetition.

Signed-off-by: Albert Esteve 
---
 docs/interop/vhost-user.rst   |  57 ++
 hw/virtio/vhost-user.c| 168 +++---
 include/hw/virtio/vhost-backend.h |   3 +
 3 files changed, 216 insertions(+), 12 deletions(-)

diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index 5a070adbc1..415bb47a19 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -1440,6 +1440,18 @@ Front-end message types
   query the back-end for its device status as defined in the Virtio
   specification.
 
+``VHOST_USER_GET_SHARED_OBJECT``
+  :id: 41
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: dmabuf fd
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, and the UUID is found
+  in the exporters cache, this message is submitted by the front-end
+  to retrieve a given dma-buf fd from a given back-end, determined by
+  the requested UUID. Back-end will reply passing the fd when the operation
+  is successful, or no fd otherwise.
 
 Back-end message types
 --
@@ -1528,6 +1540,51 @@ is sent by the front-end.
 
   The state.num field is currently reserved and must be set to 0.
 
+``VHOST_USER_BACKEND_SHARED_OBJECT_ADD``
+  :id: 6
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: N/A
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backends to add themselves as exporters to the virtio shared lookup
+  table. The back-end device gets associated with a UUID in the shared table.
+  The back-end is responsible of keeping its own table with exported dma-buf 
fds.
+  When another back-end tries to import the resource associated with the UUID,
+  it will send a message to the front-end, which will act as a proxy to the
+  exporter back-end. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and
+  the back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must
+  respond with zero when operation is successfully completed, or non-zero
+  otherwise.
+
+``VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE``
+  :id: 7
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: N/A
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backend to remove themselves from to the virtio-dmabuf shared
+  table API. The shared table will remove the back-end device associated with
+  the UUID. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and the
+  back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond
+  with zero when operation is successfully completed, or non-zero otherwise.
+
+``VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP``
+  :id: 8
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: dmabuf fd and ``u64``
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backends to retrieve a given dma-buf fd from the virtio-dmabuf
+  shared table given a UUID. Frontend will reply passing the fd and a zero
+  when the operation is successful, or non-zero otherwise. Note that if the
+  operation fails, no fd is sent to the backend.
+
 .. _reply_ack:
 
 VHOST_USER_PROTOCOL_F_REPLY_ACK
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 8dcf049d42..08ab256613 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -10,6 +10,7 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "hw/virtio/virtio-dmabuf.h"
 #include "hw/virtio/vhost.h"
 #include "hw/virtio/virtio-crypto.h"
 #include "hw/virtio/vhost-user.h"
@@ -21,6 +22,7 @@
 #include "sysemu/kvm.h"
 #include "qemu/error-report.h"
 #include "qemu/main-loop.h"
+#include "qemu/uuid.h"
 #include 

[PATCH v7 2/4] virtio-dmabuf: introduce virtio-dmabuf

2023-09-07 Thread Albert Esteve
This API manages objects (in this iteration,
dmabuf fds) that can be shared along different
virtio devices, associated to a UUID.

The API allows the different devices to add,
remove and/or retrieve the objects by simply
invoking the public functions that reside in the
virtio-dmabuf file.

For vhost backends, the API stores the pointer
to the backend holding the object.

Suggested-by: Gerd Hoffmann 
Signed-off-by: Albert Esteve 
---
 MAINTAINERS   |   7 ++
 hw/display/meson.build|   1 +
 hw/display/virtio-dmabuf.c| 136 +
 include/hw/virtio/virtio-dmabuf.h | 103 ++
 tests/unit/meson.build|   1 +
 tests/unit/test-virtio-dmabuf.c   | 137 ++
 6 files changed, 385 insertions(+)
 create mode 100644 hw/display/virtio-dmabuf.c
 create mode 100644 include/hw/virtio/virtio-dmabuf.h
 create mode 100644 tests/unit/test-virtio-dmabuf.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3b29568ed4..fb0f7b823f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2150,6 +2150,13 @@ T: git https://gitlab.com/cohuck/qemu.git s390-next
 T: git https://github.com/borntraeger/qemu.git s390-next
 L: qemu-s3...@nongnu.org
 
+virtio-dmabuf
+M: Albert Esteve 
+S: Supported
+F: hw/display/virtio-dmabuf.c
+F: include/hw/virtio/virtio-dmabuf.h
+F: tests/unit/test-virtio-dmabuf.c
+
 virtiofs
 M: Stefan Hajnoczi 
 S: Supported
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 413ba4ab24..05619c6968 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -37,6 +37,7 @@ system_ss.add(when: 'CONFIG_MACFB', if_true: files('macfb.c'))
 system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c'))
 
 system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c'))
+system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c'))
 
 if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or
 config_all_devices.has_key('CONFIG_VGA_PCI') or
diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
new file mode 100644
index 00..7e7a536c4d
--- /dev/null
+++ b/hw/display/virtio-dmabuf.c
@@ -0,0 +1,136 @@
+/*
+ * Virtio Shared dma-buf
+ *
+ * Copyright Red Hat, Inc. 2023
+ *
+ * Authors:
+ * Albert Esteve 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw/virtio/virtio-dmabuf.h"
+
+
+static GMutex lock;
+static GHashTable *resource_uuids;
+
+/*
+ * uuid_equal_func: wrapper for UUID is_equal function to
+ * satisfy g_hash_table_new expected parameters signatures.
+ */
+static int uuid_equal_func(const void *lhv, const void *rhv)
+{
+return qemu_uuid_is_equal(lhv, rhv);
+}
+
+static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value)
+{
+bool result = false;
+
+g_mutex_lock();
+if (resource_uuids == NULL) {
+resource_uuids = g_hash_table_new_full(qemu_uuid_hash,
+   uuid_equal_func,
+   NULL,
+   g_free);
+}
+if (g_hash_table_lookup(resource_uuids, uuid) == NULL) {
+result = g_hash_table_insert(resource_uuids, uuid, value);
+}
+g_mutex_unlock();
+
+return result;
+}
+
+bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
+{
+bool result;
+VirtioSharedObject *vso;
+if (udmabuf_fd < 0) {
+return false;
+}
+vso = g_new(VirtioSharedObject, 1);
+vso->type = TYPE_DMABUF;
+vso->value = GINT_TO_POINTER(udmabuf_fd);
+result = virtio_add_resource(uuid, vso);
+
+return result;
+}
+
+bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
+{
+bool result;
+VirtioSharedObject *vso;
+if (dev == NULL) {
+return false;
+}
+vso = g_new(VirtioSharedObject, 1);
+vso->type = TYPE_VHOST_DEV;
+vso->value = dev;
+result = virtio_add_resource(uuid, vso);
+
+return result;
+}
+
+bool virtio_remove_resource(const QemuUUID *uuid)
+{
+bool result;
+g_mutex_lock();
+result = g_hash_table_remove(resource_uuids, uuid);
+g_mutex_unlock();
+
+return result;
+}
+
+static VirtioSharedObject *get_shared_object(const QemuUUID *uuid)
+{
+gpointer lookup_res = NULL;
+
+g_mutex_lock();
+if (resource_uuids != NULL) {
+lookup_res = g_hash_table_lookup(resource_uuids, uuid);
+}
+g_mutex_unlock();
+
+return (VirtioSharedObject *) lookup_res;
+}
+
+int virtio_lookup_dmabuf(const QemuUUID *uuid)
+{
+VirtioSharedObject *vso = get_shared_object(uuid);
+if (vso == NULL) {
+return -1;
+}
+assert(vso->type == TYPE_DMABUF);
+return GPOINTER_TO_INT(vso->value);
+}
+
+struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
+{
+VirtioSharedObject *vso = get_shared_object(uuid);
+if (vso 

[PATCH v7 1/4] uuid: add a hash function

2023-09-07 Thread Albert Esteve
Add hash function to uuid module using the
djb2 hash algorithm.

Add a couple simple unit tests for the hash
function, checking collisions for similar UUIDs.

Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Albert Esteve 
---
 include/qemu/uuid.h|  2 ++
 tests/unit/test-uuid.c | 27 +++
 util/uuid.c| 15 +++
 3 files changed, 44 insertions(+)

diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h
index dc40ee1fc9..e24a1099e4 100644
--- a/include/qemu/uuid.h
+++ b/include/qemu/uuid.h
@@ -96,4 +96,6 @@ int qemu_uuid_parse(const char *str, QemuUUID *uuid);
 
 QemuUUID qemu_uuid_bswap(QemuUUID uuid);
 
+uint32_t qemu_uuid_hash(const void *uuid);
+
 #endif
diff --git a/tests/unit/test-uuid.c b/tests/unit/test-uuid.c
index c111de5fc1..aedc125ae9 100644
--- a/tests/unit/test-uuid.c
+++ b/tests/unit/test-uuid.c
@@ -171,6 +171,32 @@ static void test_uuid_unparse_strdup(void)
 }
 }
 
+static void test_uuid_hash(void)
+{
+QemuUUID uuid;
+int i;
+
+for (i = 0; i < 100; i++) {
+qemu_uuid_generate();
+/* Obtain the UUID hash */
+uint32_t hash_a = qemu_uuid_hash();
+int data_idx = g_random_int_range(0, 15);
+/* Change a single random byte of the UUID */
+if (uuid.data[data_idx] < 0xFF) {
+uuid.data[data_idx]++;
+} else {
+uuid.data[data_idx]--;
+}
+/* Obtain the UUID hash again */
+uint32_t hash_b = qemu_uuid_hash();
+/*
+ * Both hashes shall be different (avoid collision)
+ * for any change in the UUID fields
+ */
+g_assert_cmpint(hash_a, !=, hash_b);
+}
+}
+
 int main(int argc, char **argv)
 {
 g_test_init(, , NULL);
@@ -179,6 +205,7 @@ int main(int argc, char **argv)
 g_test_add_func("/uuid/parse", test_uuid_parse);
 g_test_add_func("/uuid/unparse", test_uuid_unparse);
 g_test_add_func("/uuid/unparse_strdup", test_uuid_unparse_strdup);
+g_test_add_func("/uuid/hash", test_uuid_hash);
 
 return g_test_run();
 }
diff --git a/util/uuid.c b/util/uuid.c
index b1108dde78..b366961bc6 100644
--- a/util/uuid.c
+++ b/util/uuid.c
@@ -116,3 +116,18 @@ QemuUUID qemu_uuid_bswap(QemuUUID uuid)
 bswap16s(_high_and_version);
 return uuid;
 }
+
+/* djb2 hash algorithm */
+uint32_t qemu_uuid_hash(const void *uuid)
+{
+QemuUUID *qid = (QemuUUID *) uuid;
+uint32_t h = 5381;
+int i;
+
+for (i = 0; i < ARRAY_SIZE(qid->data); i++) {
+h = (h << 5) + h + qid->data[i];
+}
+
+return h;
+}
+
-- 
2.41.0




[PATCH v7 4/4] libvhost-user: handle shared_object msg

2023-09-07 Thread Albert Esteve
In the libvhost-user library we need to
handle VHOST_USER_GET_SHARED_OBJECT requests,
and add helper functions to allow sending messages
to interact with the virtio shared objects
hash table.

Signed-off-by: Albert Esteve 
---
 subprojects/libvhost-user/libvhost-user.c | 120 ++
 subprojects/libvhost-user/libvhost-user.h |  55 +-
 2 files changed, 174 insertions(+), 1 deletion(-)

diff --git a/subprojects/libvhost-user/libvhost-user.c 
b/subprojects/libvhost-user/libvhost-user.c
index 0469a50101..676e57a468 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -161,6 +161,7 @@ vu_request_to_string(unsigned int req)
 REQ(VHOST_USER_GET_MAX_MEM_SLOTS),
 REQ(VHOST_USER_ADD_MEM_REG),
 REQ(VHOST_USER_REM_MEM_REG),
+REQ(VHOST_USER_GET_SHARED_OBJECT),
 REQ(VHOST_USER_MAX),
 };
 #undef REQ
@@ -900,6 +901,24 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
 return false;
 }
 
+static bool
+vu_get_shared_object(VuDev *dev, VhostUserMsg *vmsg)
+{
+int fd_num = 0;
+int dmabuf_fd = -1;
+if (dev->iface->get_shared_object) {
+dmabuf_fd = dev->iface->get_shared_object(
+dev, >payload.object.uuid[0]);
+}
+if (dmabuf_fd != -1) {
+DPRINT("dmabuf_fd found for requested UUID\n");
+vmsg->fds[fd_num++] = dmabuf_fd;
+}
+vmsg->fd_num = fd_num;
+
+return true;
+}
+
 static bool
 vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
 {
@@ -1403,6 +1422,105 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq 
*vq, int fd,
 return vu_process_message_reply(dev, );
 }
 
+bool
+vu_lookup_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN],
+int *dmabuf_fd)
+{
+bool result = false;
+VhostUserMsg msg_reply;
+VhostUserMsg msg = {
+.request = VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP,
+.size = sizeof(msg.payload.object),
+.flags = VHOST_USER_VERSION | VHOST_USER_NEED_REPLY_MASK,
+};
+
+memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN);
+
+if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) {
+return false;
+}
+
+pthread_mutex_lock(>backend_mutex);
+if (!vu_message_write(dev, dev->backend_fd, )) {
+goto out;
+}
+
+if (!vu_message_read_default(dev, dev->backend_fd, _reply)) {
+goto out;
+}
+
+if (msg_reply.request != msg.request) {
+DPRINT("Received unexpected msg type. Expected %d, received %d",
+   msg.request, msg_reply.request);
+goto out;
+}
+
+if (msg_reply.fd_num != 1) {
+DPRINT("Received unexpected number of fds. Expected 1, received %d",
+   msg_reply.fd_num);
+goto out;
+}
+
+*dmabuf_fd = msg_reply.fds[0];
+result = *dmabuf_fd > 0 && msg_reply.payload.u64 == 0;
+out:
+pthread_mutex_unlock(>backend_mutex);
+
+return result;
+}
+
+static bool
+vu_send_message(VuDev *dev, VhostUserMsg *vmsg)
+{
+bool result = false;
+pthread_mutex_lock(>backend_mutex);
+if (!vu_message_write(dev, dev->backend_fd, vmsg)) {
+goto out;
+}
+
+result = true;
+out:
+pthread_mutex_unlock(>backend_mutex);
+
+return result;
+}
+
+bool
+vu_add_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN])
+{
+VhostUserMsg msg = {
+.request = VHOST_USER_BACKEND_SHARED_OBJECT_ADD,
+.size = sizeof(msg.payload.object),
+.flags = VHOST_USER_VERSION,
+};
+
+memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN);
+
+if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) {
+return false;
+}
+
+return vu_send_message(dev, );
+}
+
+bool
+vu_rm_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN])
+{
+VhostUserMsg msg = {
+.request = VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE,
+.size = sizeof(msg.payload.object),
+.flags = VHOST_USER_VERSION,
+};
+
+memcpy(msg.payload.object.uuid, uuid, sizeof(uuid[0]) * UUID_LEN);
+
+if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHARED_OBJECT)) {
+return false;
+}
+
+return vu_send_message(dev, );
+}
+
 static bool
 vu_set_vring_call_exec(VuDev *dev, VhostUserMsg *vmsg)
 {
@@ -1943,6 +2061,8 @@ vu_process_message(VuDev *dev, VhostUserMsg *vmsg)
 return vu_add_mem_reg(dev, vmsg);
 case VHOST_USER_REM_MEM_REG:
 return vu_rem_mem_reg(dev, vmsg);
+case VHOST_USER_GET_SHARED_OBJECT:
+return vu_get_shared_object(dev, vmsg);
 default:
 vmsg_close_fds(vmsg);
 vu_panic(dev, "Unhandled request: %d", vmsg->request);
diff --git a/subprojects/libvhost-user/libvhost-user.h 
b/subprojects/libvhost-user/libvhost-user.h
index 708370c5f5..b36a42a7ca 100644
--- a/subprojects/libv

[PATCH v7 0/4] Virtio shared dma-buf

2023-09-07 Thread Albert Esteve
v1 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg00598.html
v2 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg04530.html
v3 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg06126.html
v4 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-06/msg05174.html
v5 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-08/msg00255.html
v6 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg00987.html
v6 -> v7:
- Small refactor of a couple of virtio-dmabuf.c functions
- Add Error propagation for vhost_user_send_resp function
- Split last commit for vhost-user and libvhost-user

This patch covers the required steps to add support for virtio cross-device 
resource sharing[1],
which support is already available in the kernel.

The main usecase will be sharing dma buffers from virtio-gpu devices (as the 
exporter
-see VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID in [2]), to virtio-video (under 
discussion)
devices (as the buffer-user or importer). Therefore, even though virtio specs 
talk about
resources or objects[3], this patch adds the infrastructure with dma-bufs in 
mind.
Note that virtio specs let the devices themselves define what a vitio object is.

These are the main parts that are covered in the patch:

- Add hash function to uuid module
- Shared resources table, to hold all resources that can be shared in the host 
and their assigned UUID,
  or pointers to the backend holding the resource
- Internal shared table API for virtio devices to add, lookup and remove 
resources
- Unit test to verify the API
- New messages to the vhost-user protocol to allow backend to interact with the 
shared
  table API through the control socket
- New vhost-user feature bit to enable shared objects feature

Applies cleanly to c152379422a204109f34ca2b43ecc538c7d738ae

[1] - https://lwn.net/Articles/828988/
[2] - 
https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-3730006
[3] - 
https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-10500011

Albert Esteve (4):
  uuid: add a hash function
  virtio-dmabuf: introduce virtio-dmabuf
  vhost-user: add shared_object msg
  libvhost-user: handle shared_object msg

 MAINTAINERS   |   7 +
 docs/interop/vhost-user.rst   |  57 
 hw/display/meson.build|   1 +
 hw/display/virtio-dmabuf.c| 136 ++
 hw/virtio/vhost-user.c| 168 --
 include/hw/virtio/vhost-backend.h |   3 +
 include/hw/virtio/virtio-dmabuf.h | 103 +
 include/qemu/uuid.h   |   2 +
 subprojects/libvhost-user/libvhost-user.c | 120 
 subprojects/libvhost-user/libvhost-user.h |  55 ++-
 tests/unit/meson.build|   1 +
 tests/unit/test-uuid.c|  27 
 tests/unit/test-virtio-dmabuf.c   | 137 ++
 util/uuid.c   |  15 ++
 14 files changed, 819 insertions(+), 13 deletions(-)
 create mode 100644 hw/display/virtio-dmabuf.c
 create mode 100644 include/hw/virtio/virtio-dmabuf.h
 create mode 100644 tests/unit/test-virtio-dmabuf.c

-- 
2.41.0




Re: [PATCH v6 3/3] vhost-user: add shared_object msg

2023-09-06 Thread Albert Esteve
On Wed, Sep 6, 2023 at 6:01 PM Albert Esteve  wrote:

>
>
> On Wed, Sep 6, 2023 at 4:43 PM Philippe Mathieu-Daudé 
> wrote:
>
>> On 6/9/23 16:33, Albert Esteve wrote:
>>
>> > I note you  ignored my comment regarding adding a 'Error **'
>> argument in
>> > the previous version:
>> >
>> https://lore.kernel.org/qemu-devel/911eef0c-d04f-2fcf-e78b-2475cd7af...@linaro.org/
>> <
>> https://lore.kernel.org/qemu-devel/911eef0c-d04f-2fcf-e78b-2475cd7af...@linaro.org/
>> >
>> >
>> > Sorry I missed those comments somehow :/
>>
>> Ah, I see.
>>
>> > I'll check them and resend.
>>
>> You can also object to them, explaining why this isn't really
>> useful, if you think so. But first read the big comment in
>> include/qapi/error.h.
>>
>>
> Sure, I understand. So far I tend to trust the judgement of the more
> experienced
> Qemu developers over my own, but if I wouldn't agree with what is
> suggested I would object :)
> So:
> - Regarding the two functions with the same, seems to be solved with the
> squash before,
>   and it was probably causing the compile error to begin with, so one less
> thing to worry about!
> - Regarding splitting the commit, sure, no problem. I'll ensure they do
> compile separately.
> - Regarding the error, I read the long comment in the error file and
> checked surrounding code. I think
>   you are right and will be better propagating the error.
>

But I think I will omit the Error propagation for
`vhost_user_backend_handle_shared_object_lookup`.
In this function returning an error code does not necessarily mean that we
should log an error.
So if we pass the local_err from the backend_read function to the handler,
we cannot be sure
when we should actually print the log.
`vhost_backend_handle_iotlb_msg` has the same issue and does not propagate
the error either,
relies solely on `error_report` calls.

Therefore, I will propagate it for `vhost_user_send_resp` and
`vhost_user_backend_send_dmabuf_fd` only.


>
> And I think I would address all your comments with that! Thanks for the
> feedback!
>
>
>> Thanks,
>>
>> Phil.
>>
>>


Re: [PATCH v6 3/3] vhost-user: add shared_object msg

2023-09-06 Thread Albert Esteve
On Wed, Sep 6, 2023 at 4:43 PM Philippe Mathieu-Daudé 
wrote:

> On 6/9/23 16:33, Albert Esteve wrote:
>
> > I note you  ignored my comment regarding adding a 'Error **'
> argument in
> > the previous version:
> >
> https://lore.kernel.org/qemu-devel/911eef0c-d04f-2fcf-e78b-2475cd7af...@linaro.org/
> <
> https://lore.kernel.org/qemu-devel/911eef0c-d04f-2fcf-e78b-2475cd7af...@linaro.org/
> >
> >
> > Sorry I missed those comments somehow :/
>
> Ah, I see.
>
> > I'll check them and resend.
>
> You can also object to them, explaining why this isn't really
> useful, if you think so. But first read the big comment in
> include/qapi/error.h.
>
>
Sure, I understand. So far I tend to trust the judgement of the more
experienced
Qemu developers over my own, but if I wouldn't agree with what is suggested
I would object :)
So:
- Regarding the two functions with the same, seems to be solved with the
squash before,
  and it was probably causing the compile error to begin with, so one less
thing to worry about!
- Regarding splitting the commit, sure, no problem. I'll ensure they do
compile separately.
- Regarding the error, I read the long comment in the error file and
checked surrounding code. I think
  you are right and will be better propagating the error.

And I think I would address all your comments with that! Thanks for the
feedback!


> Thanks,
>
> Phil.
>
>


Re: [PATCH v6 2/3] virtio-dmabuf: introduce virtio-dmabuf

2023-09-06 Thread Albert Esteve
On Wed, Sep 6, 2023 at 4:21 PM Philippe Mathieu-Daudé 
wrote:

> On 6/9/23 13:15, Albert Esteve wrote:
> > This API manages objects (in this iteration,
> > dmabuf fds) that can be shared along different
> > virtio devices, associated to a UUID.
> >
> > The API allows the different devices to add,
> > remove and/or retrieve the objects by simply
> > invoking the public functions that reside in the
> > virtio-dmabuf file.
> >
> > For vhost backends, the API stores the pointer
> > to the backend holding the object.
> >
> > Suggested-by: Gerd Hoffmann 
> > Signed-off-by: Albert Esteve 
> > ---
> >   MAINTAINERS   |   7 ++
> >   hw/display/meson.build|   1 +
> >   hw/display/virtio-dmabuf.c| 134 +
> >   include/hw/virtio/virtio-dmabuf.h | 103 ++
> >   tests/unit/meson.build|   1 +
> >   tests/unit/test-virtio-dmabuf.c   | 137 ++
> >   6 files changed, 383 insertions(+)
> >   create mode 100644 hw/display/virtio-dmabuf.c
> >   create mode 100644 include/hw/virtio/virtio-dmabuf.h
> >   create mode 100644 tests/unit/test-virtio-dmabuf.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 3b29568ed4..fb0f7b823f 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -2150,6 +2150,13 @@ T: git https://gitlab.com/cohuck/qemu.git
> s390-next
> >   T: git https://github.com/borntraeger/qemu.git s390-next
> >   L: qemu-s3...@nongnu.org
> >
> > +virtio-dmabuf
> > +M: Albert Esteve 
> > +S: Supported
> > +F: hw/display/virtio-dmabuf.c
> > +F: include/hw/virtio/virtio-dmabuf.h
> > +F: tests/unit/test-virtio-dmabuf.c
> > +
> >   virtiofs
> >   M: Stefan Hajnoczi 
> >   S: Supported
> > diff --git a/hw/display/meson.build b/hw/display/meson.build
> > index 413ba4ab24..05619c6968 100644
> > --- a/hw/display/meson.build
> > +++ b/hw/display/meson.build
> > @@ -37,6 +37,7 @@ system_ss.add(when: 'CONFIG_MACFB', if_true:
> files('macfb.c'))
> >   system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c'))
> >
> >   system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c'))
> > +system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c'))
> >
> >   if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or
> >   config_all_devices.has_key('CONFIG_VGA_PCI') or
> > diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
> > new file mode 100644
> > index 00..268ffe81ec
> > --- /dev/null
> > +++ b/hw/display/virtio-dmabuf.c
> > @@ -0,0 +1,134 @@
> > +/*
> > + * Virtio Shared dma-buf
> > + *
> > + * Copyright Red Hat, Inc. 2023
> > + *
> > + * Authors:
> > + * Albert Esteve 
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> > + * See the COPYING file in the top-level directory.
> > + */
> > +
> > +#include "hw/virtio/virtio-dmabuf.h"
> > +
> > +
> > +static GMutex lock;
> > +static GHashTable *resource_uuids;
> > +
> > +/*
> > + * uuid_equal_func: wrapper for UUID is_equal function to
> > + * satisfy g_hash_table_new expected parameters signatures.
> > + */
> > +static int uuid_equal_func(const void *lhv, const void *rhv)
> > +{
> > +return qemu_uuid_is_equal(lhv, rhv);
> > +}
> > +
> > +static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject
> *value)
> > +{
> > +bool result;
> > +g_mutex_lock();
> > +if (resource_uuids == NULL) {
> > +resource_uuids = g_hash_table_new_full(
> > +qemu_uuid_hash, uuid_equal_func, NULL, g_free);
> > +}
> > +if (g_hash_table_lookup(resource_uuids, uuid) != NULL) {
> > +g_mutex_unlock();
> > +return false;
> > +}
> > +result = g_hash_table_insert(resource_uuids, uuid, value);
> > +g_mutex_unlock();
> > +
> > +return result;
> > +}
>
> Alternatively same logic, but simpler / safer:
>
> static bool virtio_add_resource(...)
> {
>  bool result = false;
>
>  g_mutex_lock();
>  if (resource_uuids == NULL) {
>  resource_uuids = g_hash_table_new_full(qemu_uuid_hash,
> uuid_equal_func,
> NULL,
> g_free);
>  }
>  if (g_hash_table_lookup(reso

Re: [PATCH v6 3/3] vhost-user: add shared_object msg

2023-09-06 Thread Albert Esteve
On Wed, Sep 6, 2023 at 4:27 PM Philippe Mathieu-Daudé 
wrote:

> Hi Albert,
>
> On 6/9/23 13:15, Albert Esteve wrote:
> > Add three new vhost-user protocol
> > `VHOST_USER_BACKEND_SHARED_OBJECT_* messages`.
> > These new messages are sent from vhost-user
> > back-ends to interact with the virtio-dmabuf
> > table in order to add or remove themselves as
> > virtio exporters, or lookup for virtio dma-buf
> > shared objects.
> >
> > The action taken in the front-end depends
> > on the type stored in the virtio shared
> > object hash table.
> >
> > When the table holds a pointer to a vhost
> > backend for a given UUID, the front-end sends
> > a VHOST_USER_GET_SHARED_OBJECT to the
> > backend holding the shared object.
> >
> > In the libvhost-user library we need to add
> > helper functions to allow sending messages to
> > interact with the virtio shared objects
> > hash table.
> >
> > The messages can only be sent after successfully
> > negotiating a new VHOST_USER_PROTOCOL_F_SHARED_OBJECT
> > vhost-user protocol feature bit.
> >
> > Finally, refactor code to send response message so
> > that all common parts both for the common REPLY_ACK
> > case, and other data responses, can call it and
> > avoid code repetition.
> >
> > Signed-off-by: Albert Esteve 
> > ---
> >   docs/interop/vhost-user.rst   |  57 +++
> >   hw/virtio/vhost-user.c| 174 --
> >   include/hw/virtio/vhost-backend.h |   3 +
> >   subprojects/libvhost-user/libvhost-user.c | 118 +++
> >   subprojects/libvhost-user/libvhost-user.h |  55 ++-
> >   5 files changed, 393 insertions(+), 14 deletions(-)
>
> Almost 400 lines of changes is too much for me to review in a
> single patch. Looking at the names, can't we split virtio VS
> libvhost-user?
>

Ack.


>
> > +static bool vhost_user_send_resp(QIOChannel *ioc, VhostUserHeader *hdr,
> > + VhostUserPayload *payload)
> > +{
> > +Error *local_err = NULL;
> > +struct iovec iov[] = {
> > +{ .iov_base = hdr,  .iov_len = VHOST_USER_HDR_SIZE },
> > +{ .iov_base = payload,  .iov_len = hdr->size },
> > +};
> > +
> > +hdr->flags &= ~VHOST_USER_NEED_REPLY_MASK;
> > +hdr->flags |= VHOST_USER_REPLY_MASK;
> > +
> > +if (qio_channel_writev_all(ioc, iov, ARRAY_SIZE(iov), _err)) {
> > +error_report_err(local_err);
> > +return false;
> > +}
> > +
> > +return true;
> > +}
>
> I note you  ignored my comment regarding adding a 'Error **' argument in
> the previous version:
>
> https://lore.kernel.org/qemu-devel/911eef0c-d04f-2fcf-e78b-2475cd7af...@linaro.org/
>
> Sorry I missed those comments somehow :/
I'll check them and resend.

BR,
Albert


Re: [PATCH v6 2/3] virtio-dmabuf: introduce virtio-dmabuf

2023-09-06 Thread Albert Esteve
On Wed, Sep 6, 2023 at 1:15 PM Albert Esteve  wrote:

> This API manages objects (in this iteration,
> dmabuf fds) that can be shared along different
> virtio devices, associated to a UUID.
>
> The API allows the different devices to add,
> remove and/or retrieve the objects by simply
> invoking the public functions that reside in the
> virtio-dmabuf file.
>
> For vhost backends, the API stores the pointer
> to the backend holding the object.
>
> Suggested-by: Gerd Hoffmann 
> Signed-off-by: Albert Esteve 
> ---
>  MAINTAINERS   |   7 ++
>  hw/display/meson.build|   1 +
>  hw/display/virtio-dmabuf.c| 134 +
>  include/hw/virtio/virtio-dmabuf.h | 103 ++
>  tests/unit/meson.build|   1 +
>  tests/unit/test-virtio-dmabuf.c   | 137 ++
>  6 files changed, 383 insertions(+)
>  create mode 100644 hw/display/virtio-dmabuf.c
>  create mode 100644 include/hw/virtio/virtio-dmabuf.h
>  create mode 100644 tests/unit/test-virtio-dmabuf.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3b29568ed4..fb0f7b823f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2150,6 +2150,13 @@ T: git https://gitlab.com/cohuck/qemu.git s390-next
>  T: git https://github.com/borntraeger/qemu.git s390-next
>  L: qemu-s3...@nongnu.org
>
> +virtio-dmabuf
> +M: Albert Esteve 
> +S: Supported
> +F: hw/display/virtio-dmabuf.c
> +F: include/hw/virtio/virtio-dmabuf.h
> +F: tests/unit/test-virtio-dmabuf.c
> +
>  virtiofs
>  M: Stefan Hajnoczi 
>  S: Supported
> diff --git a/hw/display/meson.build b/hw/display/meson.build
> index 413ba4ab24..05619c6968 100644
> --- a/hw/display/meson.build
> +++ b/hw/display/meson.build
> @@ -37,6 +37,7 @@ system_ss.add(when: 'CONFIG_MACFB', if_true:
> files('macfb.c'))
>  system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c'))
>
>  system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c'))
> +system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c'))
>
>  if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or
>  config_all_devices.has_key('CONFIG_VGA_PCI') or
> diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
> new file mode 100644
> index 00..268ffe81ec
> --- /dev/null
> +++ b/hw/display/virtio-dmabuf.c
> @@ -0,0 +1,134 @@
> +/*
> + * Virtio Shared dma-buf
> + *
> + * Copyright Red Hat, Inc. 2023
> + *
> + * Authors:
> + * Albert Esteve 
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include "hw/virtio/virtio-dmabuf.h"
> +
> +
> +static GMutex lock;
> +static GHashTable *resource_uuids;
> +
> +/*
> + * uuid_equal_func: wrapper for UUID is_equal function to
> + * satisfy g_hash_table_new expected parameters signatures.
> + */
> +static int uuid_equal_func(const void *lhv, const void *rhv)
> +{
> +return qemu_uuid_is_equal(lhv, rhv);
> +}
> +
> +static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value)
> +{
> +bool result;
> +g_mutex_lock();
> +if (resource_uuids == NULL) {
> +resource_uuids = g_hash_table_new_full(
> +qemu_uuid_hash, uuid_equal_func, NULL, g_free);
> +}
> +if (g_hash_table_lookup(resource_uuids, uuid) != NULL) {
> +g_mutex_unlock();
> +return false;
> +}
> +result = g_hash_table_insert(resource_uuids, uuid, value);
> +g_mutex_unlock();
> +
> +return result;
> +}
> +
> +bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
> +{
> +bool result;
> +VirtioSharedObject *vso;
> +if (udmabuf_fd < 0) {
> +return false;
> +}
> +vso = g_new(VirtioSharedObject, 1);
> +vso->type = TYPE_DMABUF;
> +vso->value = GINT_TO_POINTER(udmabuf_fd);
> +result = virtio_add_resource(uuid, vso);
> +
> +return result;
>

Just realized that the result variable is not required anymore
with the last change.

Not sure if it is worth sending a new review for this...
I can take it into account for a follow-up refactor for the next
update I make on the file. Or just send a separate trivial patch.


> +}
> +
> +bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
> +{
> +bool result;
> +VirtioSharedObject *vso;
> +if (dev == NULL) {
> +return false;
> +}
> +vso = g_new(VirtioSharedObject, 1);
> +vso->type = TYPE_VHOST_DEV;
> +vso->value = dev;
> +result = virtio_add_resource(uuid, vso);
> +
> +return result;
&g

[PATCH v6 0/3] Virtio shared dma-buf

2023-09-06 Thread Albert Esteve
v1 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg00598.html
v2 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg04530.html
v3 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg06126.html
v4 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-06/msg05174.html
v5 link -> https://lists.gnu.org/archive/html/qemu-devel/2023-08/msg00255.html
v5 -> v6:
- Unified shared table API mutex usage
- Typedef VirtioSharedObject struct
- Squashed refactor commit to fix compilation issue on patch#3

This patch covers the required steps to add support for virtio cross-device 
resource sharing[1],
which support is already available in the kernel.

The main usecase will be sharing dma buffers from virtio-gpu devices (as the 
exporter
-see VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID in [2]), to virtio-video (under 
discussion)
devices (as the buffer-user or importer). Therefore, even though virtio specs 
talk about
resources or objects[3], this patch adds the infrastructure with dma-bufs in 
mind.
Note that virtio specs let the devices themselves define what a vitio object is.

These are the main parts that are covered in the patch:

- Add hash function to uuid module
- Shared resources table, to hold all resources that can be shared in the host 
and their assigned UUID,
  or pointers to the backend holding the resource
- Internal shared table API for virtio devices to add, lookup and remove 
resources
- Unit test to verify the API
- New messages to the vhost-user protocol to allow backend to interact with the 
shared
  table API through the control socket
- New vhost-user feature bit to enable shared objects feature

Applies cleanly to 2d8fbcb1eecd8d39171f457e583428758321d69d

[1] - https://lwn.net/Articles/828988/
[2] - 
https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-3730006
[3] - 
https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-10500011

Albert Esteve (3):
  uuid: add a hash function
  virtio-dmabuf: introduce virtio-dmabuf
  vhost-user: add shared_object msg

 MAINTAINERS   |   7 +
 docs/interop/vhost-user.rst   |  57 +++
 hw/display/meson.build|   1 +
 hw/display/virtio-dmabuf.c| 134 +
 hw/virtio/vhost-user.c| 174 --
 include/hw/virtio/vhost-backend.h |   3 +
 include/hw/virtio/virtio-dmabuf.h | 103 +
 include/qemu/uuid.h   |   2 +
 subprojects/libvhost-user/libvhost-user.c | 118 +++
 subprojects/libvhost-user/libvhost-user.h |  55 ++-
 tests/unit/meson.build|   1 +
 tests/unit/test-uuid.c|  27 
 tests/unit/test-virtio-dmabuf.c   | 137 +
 util/uuid.c   |  15 ++
 14 files changed, 820 insertions(+), 14 deletions(-)
 create mode 100644 hw/display/virtio-dmabuf.c
 create mode 100644 include/hw/virtio/virtio-dmabuf.h
 create mode 100644 tests/unit/test-virtio-dmabuf.c

-- 
2.41.0




[PATCH v6 1/3] uuid: add a hash function

2023-09-06 Thread Albert Esteve
Add hash function to uuid module using the
djb2 hash algorithm.

Add a couple simple unit tests for the hash
function, checking collisions for similar UUIDs.

Reviewed-by: Philippe Mathieu-Daudé 
Signed-off-by: Albert Esteve 
---
 include/qemu/uuid.h|  2 ++
 tests/unit/test-uuid.c | 27 +++
 util/uuid.c| 15 +++
 3 files changed, 44 insertions(+)

diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h
index dc40ee1fc9..e24a1099e4 100644
--- a/include/qemu/uuid.h
+++ b/include/qemu/uuid.h
@@ -96,4 +96,6 @@ int qemu_uuid_parse(const char *str, QemuUUID *uuid);
 
 QemuUUID qemu_uuid_bswap(QemuUUID uuid);
 
+uint32_t qemu_uuid_hash(const void *uuid);
+
 #endif
diff --git a/tests/unit/test-uuid.c b/tests/unit/test-uuid.c
index c111de5fc1..aedc125ae9 100644
--- a/tests/unit/test-uuid.c
+++ b/tests/unit/test-uuid.c
@@ -171,6 +171,32 @@ static void test_uuid_unparse_strdup(void)
 }
 }
 
+static void test_uuid_hash(void)
+{
+QemuUUID uuid;
+int i;
+
+for (i = 0; i < 100; i++) {
+qemu_uuid_generate();
+/* Obtain the UUID hash */
+uint32_t hash_a = qemu_uuid_hash();
+int data_idx = g_random_int_range(0, 15);
+/* Change a single random byte of the UUID */
+if (uuid.data[data_idx] < 0xFF) {
+uuid.data[data_idx]++;
+} else {
+uuid.data[data_idx]--;
+}
+/* Obtain the UUID hash again */
+uint32_t hash_b = qemu_uuid_hash();
+/*
+ * Both hashes shall be different (avoid collision)
+ * for any change in the UUID fields
+ */
+g_assert_cmpint(hash_a, !=, hash_b);
+}
+}
+
 int main(int argc, char **argv)
 {
 g_test_init(, , NULL);
@@ -179,6 +205,7 @@ int main(int argc, char **argv)
 g_test_add_func("/uuid/parse", test_uuid_parse);
 g_test_add_func("/uuid/unparse", test_uuid_unparse);
 g_test_add_func("/uuid/unparse_strdup", test_uuid_unparse_strdup);
+g_test_add_func("/uuid/hash", test_uuid_hash);
 
 return g_test_run();
 }
diff --git a/util/uuid.c b/util/uuid.c
index b1108dde78..b366961bc6 100644
--- a/util/uuid.c
+++ b/util/uuid.c
@@ -116,3 +116,18 @@ QemuUUID qemu_uuid_bswap(QemuUUID uuid)
 bswap16s(_high_and_version);
 return uuid;
 }
+
+/* djb2 hash algorithm */
+uint32_t qemu_uuid_hash(const void *uuid)
+{
+QemuUUID *qid = (QemuUUID *) uuid;
+uint32_t h = 5381;
+int i;
+
+for (i = 0; i < ARRAY_SIZE(qid->data); i++) {
+h = (h << 5) + h + qid->data[i];
+}
+
+return h;
+}
+
-- 
2.41.0




[PATCH v6 2/3] virtio-dmabuf: introduce virtio-dmabuf

2023-09-06 Thread Albert Esteve
This API manages objects (in this iteration,
dmabuf fds) that can be shared along different
virtio devices, associated to a UUID.

The API allows the different devices to add,
remove and/or retrieve the objects by simply
invoking the public functions that reside in the
virtio-dmabuf file.

For vhost backends, the API stores the pointer
to the backend holding the object.

Suggested-by: Gerd Hoffmann 
Signed-off-by: Albert Esteve 
---
 MAINTAINERS   |   7 ++
 hw/display/meson.build|   1 +
 hw/display/virtio-dmabuf.c| 134 +
 include/hw/virtio/virtio-dmabuf.h | 103 ++
 tests/unit/meson.build|   1 +
 tests/unit/test-virtio-dmabuf.c   | 137 ++
 6 files changed, 383 insertions(+)
 create mode 100644 hw/display/virtio-dmabuf.c
 create mode 100644 include/hw/virtio/virtio-dmabuf.h
 create mode 100644 tests/unit/test-virtio-dmabuf.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3b29568ed4..fb0f7b823f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2150,6 +2150,13 @@ T: git https://gitlab.com/cohuck/qemu.git s390-next
 T: git https://github.com/borntraeger/qemu.git s390-next
 L: qemu-s3...@nongnu.org
 
+virtio-dmabuf
+M: Albert Esteve 
+S: Supported
+F: hw/display/virtio-dmabuf.c
+F: include/hw/virtio/virtio-dmabuf.h
+F: tests/unit/test-virtio-dmabuf.c
+
 virtiofs
 M: Stefan Hajnoczi 
 S: Supported
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 413ba4ab24..05619c6968 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -37,6 +37,7 @@ system_ss.add(when: 'CONFIG_MACFB', if_true: files('macfb.c'))
 system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c'))
 
 system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c'))
+system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c'))
 
 if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or
 config_all_devices.has_key('CONFIG_VGA_PCI') or
diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
new file mode 100644
index 00..268ffe81ec
--- /dev/null
+++ b/hw/display/virtio-dmabuf.c
@@ -0,0 +1,134 @@
+/*
+ * Virtio Shared dma-buf
+ *
+ * Copyright Red Hat, Inc. 2023
+ *
+ * Authors:
+ * Albert Esteve 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw/virtio/virtio-dmabuf.h"
+
+
+static GMutex lock;
+static GHashTable *resource_uuids;
+
+/*
+ * uuid_equal_func: wrapper for UUID is_equal function to
+ * satisfy g_hash_table_new expected parameters signatures.
+ */
+static int uuid_equal_func(const void *lhv, const void *rhv)
+{
+return qemu_uuid_is_equal(lhv, rhv);
+}
+
+static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value)
+{
+bool result;
+g_mutex_lock();
+if (resource_uuids == NULL) {
+resource_uuids = g_hash_table_new_full(
+qemu_uuid_hash, uuid_equal_func, NULL, g_free);
+}
+if (g_hash_table_lookup(resource_uuids, uuid) != NULL) {
+g_mutex_unlock();
+return false;
+}
+result = g_hash_table_insert(resource_uuids, uuid, value);
+g_mutex_unlock();
+
+return result;
+}
+
+bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
+{
+bool result;
+VirtioSharedObject *vso;
+if (udmabuf_fd < 0) {
+return false;
+}
+vso = g_new(VirtioSharedObject, 1);
+vso->type = TYPE_DMABUF;
+vso->value = GINT_TO_POINTER(udmabuf_fd);
+result = virtio_add_resource(uuid, vso);
+
+return result;
+}
+
+bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
+{
+bool result;
+VirtioSharedObject *vso;
+if (dev == NULL) {
+return false;
+}
+vso = g_new(VirtioSharedObject, 1);
+vso->type = TYPE_VHOST_DEV;
+vso->value = dev;
+result = virtio_add_resource(uuid, vso);
+
+return result;
+}
+
+bool virtio_remove_resource(const QemuUUID *uuid)
+{
+bool result;
+g_mutex_lock();
+result = g_hash_table_remove(resource_uuids, uuid);
+g_mutex_unlock();
+
+return result;
+}
+
+static VirtioSharedObject *get_shared_object(const QemuUUID *uuid)
+{
+g_mutex_lock();
+if (resource_uuids == NULL) {
+g_mutex_unlock();
+return NULL;
+}
+gpointer lookup_res = g_hash_table_lookup(resource_uuids, uuid);
+g_mutex_unlock();
+return (VirtioSharedObject*) lookup_res;
+}
+
+int virtio_lookup_dmabuf(const QemuUUID *uuid)
+{
+VirtioSharedObject *vso = get_shared_object(uuid);
+if (vso == NULL) {
+return -1;
+}
+assert(vso->type == TYPE_DMABUF);
+return GPOINTER_TO_INT(vso->value);
+}
+
+struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
+{
+VirtioSharedObject *vso = get_shared_object(uuid);
+if (vso == NULL) {
+return NULL;
+}
+assert(vso->type == TYPE_VHOST_DEV);
+ 

[PATCH v6 3/3] vhost-user: add shared_object msg

2023-09-06 Thread Albert Esteve
Add three new vhost-user protocol
`VHOST_USER_BACKEND_SHARED_OBJECT_* messages`.
These new messages are sent from vhost-user
back-ends to interact with the virtio-dmabuf
table in order to add or remove themselves as
virtio exporters, or lookup for virtio dma-buf
shared objects.

The action taken in the front-end depends
on the type stored in the virtio shared
object hash table.

When the table holds a pointer to a vhost
backend for a given UUID, the front-end sends
a VHOST_USER_GET_SHARED_OBJECT to the
backend holding the shared object.

In the libvhost-user library we need to add
helper functions to allow sending messages to
interact with the virtio shared objects
hash table.

The messages can only be sent after successfully
negotiating a new VHOST_USER_PROTOCOL_F_SHARED_OBJECT
vhost-user protocol feature bit.

Finally, refactor code to send response message so
that all common parts both for the common REPLY_ACK
case, and other data responses, can call it and
avoid code repetition.

Signed-off-by: Albert Esteve 
---
 docs/interop/vhost-user.rst   |  57 +++
 hw/virtio/vhost-user.c| 174 --
 include/hw/virtio/vhost-backend.h |   3 +
 subprojects/libvhost-user/libvhost-user.c | 118 +++
 subprojects/libvhost-user/libvhost-user.h |  55 ++-
 5 files changed, 393 insertions(+), 14 deletions(-)

diff --git a/docs/interop/vhost-user.rst b/docs/interop/vhost-user.rst
index 5a070adbc1..415bb47a19 100644
--- a/docs/interop/vhost-user.rst
+++ b/docs/interop/vhost-user.rst
@@ -1440,6 +1440,18 @@ Front-end message types
   query the back-end for its device status as defined in the Virtio
   specification.
 
+``VHOST_USER_GET_SHARED_OBJECT``
+  :id: 41
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: dmabuf fd
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, and the UUID is found
+  in the exporters cache, this message is submitted by the front-end
+  to retrieve a given dma-buf fd from a given back-end, determined by
+  the requested UUID. Back-end will reply passing the fd when the operation
+  is successful, or no fd otherwise.
 
 Back-end message types
 --
@@ -1528,6 +1540,51 @@ is sent by the front-end.
 
   The state.num field is currently reserved and must be set to 0.
 
+``VHOST_USER_BACKEND_SHARED_OBJECT_ADD``
+  :id: 6
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: N/A
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backends to add themselves as exporters to the virtio shared lookup
+  table. The back-end device gets associated with a UUID in the shared table.
+  The back-end is responsible of keeping its own table with exported dma-buf 
fds.
+  When another back-end tries to import the resource associated with the UUID,
+  it will send a message to the front-end, which will act as a proxy to the
+  exporter back-end. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and
+  the back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must
+  respond with zero when operation is successfully completed, or non-zero
+  otherwise.
+
+``VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE``
+  :id: 7
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: N/A
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backend to remove themselves from to the virtio-dmabuf shared
+  table API. The shared table will remove the back-end device associated with
+  the UUID. If ``VHOST_USER_PROTOCOL_F_REPLY_ACK`` is negotiated, and the
+  back-end sets the ``VHOST_USER_NEED_REPLY`` flag, the front-end must respond
+  with zero when operation is successfully completed, or non-zero otherwise.
+
+``VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP``
+  :id: 8
+  :equivalent ioctl: N/A
+  :request payload: ``struct VhostUserShared``
+  :reply payload: dmabuf fd and ``u64``
+
+  When the ``VHOST_USER_PROTOCOL_F_SHARED_OBJECT`` protocol
+  feature has been successfully negotiated, this message can be submitted
+  by the backends to retrieve a given dma-buf fd from the virtio-dmabuf
+  shared table given a UUID. Frontend will reply passing the fd and a zero
+  when the operation is successful, or non-zero otherwise. Note that if the
+  operation fails, no fd is sent to the backend.
+
 .. _reply_ack:
 
 VHOST_USER_PROTOCOL_F_REPLY_ACK
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 8dcf049d42..28fa0ace42 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -10,6 +10,7 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "hw/virtio/virtio-dmabuf.h"
 #include "hw/virtio/vhost.h"
 #include &

Re: [PATCH v5 0/4] Virtio shared dma-buf

2023-09-06 Thread Albert Esteve
On Wed, Sep 6, 2023 at 8:13 AM Philippe Mathieu-Daudé 
wrote:

> Hi Michael,
>
> On 5/9/23 22:45, Michael S. Tsirkin wrote:
> > I was hoping for some acks from Gerd or anyone else with a clue
> > about graphics, but as that doesn't seem to happen I'll merge.
> > Thanks!
>
> I made few late comments. Patch #3 doesn't build (thus
> break git-bisections). I also have some concern about locking.
> I'd rather see a v6, do you mind dropping v5 from your queue?
>
> Thanks,
>
> Phil.
>

I have the v6 ready. I will wait for Michael response and post it,
to ensure that I do not step on his toes.
Thank you both!


>
> > On Mon, Aug 21, 2023 at 02:37:56PM +0200, Albert Esteve wrote:
> >> Hi all,
> >>
> >> A little bump for this patch, sorry for the extra noise.
> >>
> >> Regards,
> >> Albert
>
>


Re: [PATCH v5 2/4] virtio-dmabuf: introduce virtio-dmabuf

2023-09-06 Thread Albert Esteve
On Wed, Sep 6, 2023 at 9:42 AM Albert Esteve  wrote:

>
>
> On Wed, Sep 6, 2023 at 7:56 AM Philippe Mathieu-Daudé 
> wrote:
>
>> Hi Albert,
>>
>> On 2/8/23 11:08, Albert Esteve wrote:
>> > This API manages objects (in this iteration,
>> > dmabuf fds) that can be shared along different
>> > virtio devices, associated to a UUID.
>> >
>> > The API allows the different devices to add,
>> > remove and/or retrieve the objects by simply
>> > invoking the public functions that reside in the
>> > virtio-dmabuf file.
>> >
>> > For vhost backends, the API stores the pointer
>> > to the backend holding the object.
>> >
>> > Suggested-by: Gerd Hoffmann 
>> > Signed-off-by: Albert Esteve 
>> > ---
>> >   MAINTAINERS   |   7 ++
>> >   hw/display/meson.build|   1 +
>> >   hw/display/virtio-dmabuf.c| 136 +
>> >   include/hw/virtio/virtio-dmabuf.h | 103 ++
>> >   tests/unit/meson.build|   1 +
>> >   tests/unit/test-virtio-dmabuf.c   | 137 ++
>> >   6 files changed, 385 insertions(+)
>> >   create mode 100644 hw/display/virtio-dmabuf.c
>> >   create mode 100644 include/hw/virtio/virtio-dmabuf.h
>> >   create mode 100644 tests/unit/test-virtio-dmabuf.c
>> >
>> > diff --git a/MAINTAINERS b/MAINTAINERS
>> > index 12e59b6b27..cd8487785a 100644
>> > --- a/MAINTAINERS
>> > +++ b/MAINTAINERS
>> > @@ -2158,6 +2158,13 @@ T: git https://gitlab.com/cohuck/qemu.git
>> s390-next
>> >   T: git https://github.com/borntraeger/qemu.git s390-next
>> >   L: qemu-s3...@nongnu.org
>> >
>> > +virtio-dmabuf
>> > +M: Albert Esteve 
>> > +S: Supported
>> > +F: hw/display/virtio-dmabuf.c
>> > +F: include/hw/virtio/virtio-dmabuf.h
>> > +F: tests/unit/test-virtio-dmabuf.c
>> > +
>> >   virtiofs
>> >   M: Stefan Hajnoczi 
>> >   S: Supported
>> > diff --git a/hw/display/meson.build b/hw/display/meson.build
>> > index 413ba4ab24..05619c6968 100644
>> > --- a/hw/display/meson.build
>> > +++ b/hw/display/meson.build
>> > @@ -37,6 +37,7 @@ system_ss.add(when: 'CONFIG_MACFB', if_true:
>> files('macfb.c'))
>> >   system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c'))
>> >
>> >   system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c'))
>> > +system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c'))
>> >
>> >   if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or
>> >   config_all_devices.has_key('CONFIG_VGA_PCI') or
>> > diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
>> > new file mode 100644
>> > index 00..e852c71ba9
>> > --- /dev/null
>> > +++ b/hw/display/virtio-dmabuf.c
>> > @@ -0,0 +1,136 @@
>> > +/*
>> > + * Virtio Shared dma-buf
>> > + *
>> > + * Copyright Red Hat, Inc. 2023
>> > + *
>> > + * Authors:
>> > + * Albert Esteve 
>> > + *
>> > + * This work is licensed under the terms of the GNU GPL, version 2 or
>> later.
>> > + * See the COPYING file in the top-level directory.
>> > + */
>> > +
>> > +#include "hw/virtio/virtio-dmabuf.h"
>> > +
>> > +
>> > +static GMutex lock;
>> > +static GHashTable *resource_uuids;
>> > +
>> > +/*
>> > + * uuid_equal_func: wrapper for UUID is_equal function to
>> > + * satisfy g_hash_table_new expected parameters signatures.
>> > + */
>> > +static int uuid_equal_func(const void *lhv, const void *rhv)
>> > +{
>> > +return qemu_uuid_is_equal(lhv, rhv);
>> > +}
>> > +
>> > +static bool virtio_add_resource(QemuUUID *uuid, struct
>> VirtioSharedObject *value)
>>
>> Per QEMU coding style we use typedefs, so "VirtioSharedObject" here.
>>
>> > +{
>> > +if (resource_uuids == NULL) {
>> > +resource_uuids = g_hash_table_new_full(
>> > +qemu_uuid_hash, uuid_equal_func, NULL, g_free);
>> > +}
>> > +if (g_hash_table_lookup(resource_uuids, uuid) != NULL) {
>> > +return false;
>> > +}
>> > +
>> > +return g_hash_table_insert(resource_uuids, uuid, value);
>>
>> Hmm shouldn't this function take the lock

Re: [PATCH v5 2/4] virtio-dmabuf: introduce virtio-dmabuf

2023-09-06 Thread Albert Esteve
On Wed, Sep 6, 2023 at 7:56 AM Philippe Mathieu-Daudé 
wrote:

> Hi Albert,
>
> On 2/8/23 11:08, Albert Esteve wrote:
> > This API manages objects (in this iteration,
> > dmabuf fds) that can be shared along different
> > virtio devices, associated to a UUID.
> >
> > The API allows the different devices to add,
> > remove and/or retrieve the objects by simply
> > invoking the public functions that reside in the
> > virtio-dmabuf file.
> >
> > For vhost backends, the API stores the pointer
> > to the backend holding the object.
> >
> > Suggested-by: Gerd Hoffmann 
> > Signed-off-by: Albert Esteve 
> > ---
> >   MAINTAINERS   |   7 ++
> >   hw/display/meson.build|   1 +
> >   hw/display/virtio-dmabuf.c| 136 +
> >   include/hw/virtio/virtio-dmabuf.h | 103 ++
> >   tests/unit/meson.build|   1 +
> >   tests/unit/test-virtio-dmabuf.c   | 137 ++
> >   6 files changed, 385 insertions(+)
> >   create mode 100644 hw/display/virtio-dmabuf.c
> >   create mode 100644 include/hw/virtio/virtio-dmabuf.h
> >   create mode 100644 tests/unit/test-virtio-dmabuf.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 12e59b6b27..cd8487785a 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -2158,6 +2158,13 @@ T: git https://gitlab.com/cohuck/qemu.git
> s390-next
> >   T: git https://github.com/borntraeger/qemu.git s390-next
> >   L: qemu-s3...@nongnu.org
> >
> > +virtio-dmabuf
> > +M: Albert Esteve 
> > +S: Supported
> > +F: hw/display/virtio-dmabuf.c
> > +F: include/hw/virtio/virtio-dmabuf.h
> > +F: tests/unit/test-virtio-dmabuf.c
> > +
> >   virtiofs
> >   M: Stefan Hajnoczi 
> >   S: Supported
> > diff --git a/hw/display/meson.build b/hw/display/meson.build
> > index 413ba4ab24..05619c6968 100644
> > --- a/hw/display/meson.build
> > +++ b/hw/display/meson.build
> > @@ -37,6 +37,7 @@ system_ss.add(when: 'CONFIG_MACFB', if_true:
> files('macfb.c'))
> >   system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c'))
> >
> >   system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c'))
> > +system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c'))
> >
> >   if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or
> >   config_all_devices.has_key('CONFIG_VGA_PCI') or
> > diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
> > new file mode 100644
> > index 00..e852c71ba9
> > --- /dev/null
> > +++ b/hw/display/virtio-dmabuf.c
> > @@ -0,0 +1,136 @@
> > +/*
> > + * Virtio Shared dma-buf
> > + *
> > + * Copyright Red Hat, Inc. 2023
> > + *
> > + * Authors:
> > + * Albert Esteve 
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> > + * See the COPYING file in the top-level directory.
> > + */
> > +
> > +#include "hw/virtio/virtio-dmabuf.h"
> > +
> > +
> > +static GMutex lock;
> > +static GHashTable *resource_uuids;
> > +
> > +/*
> > + * uuid_equal_func: wrapper for UUID is_equal function to
> > + * satisfy g_hash_table_new expected parameters signatures.
> > + */
> > +static int uuid_equal_func(const void *lhv, const void *rhv)
> > +{
> > +return qemu_uuid_is_equal(lhv, rhv);
> > +}
> > +
> > +static bool virtio_add_resource(QemuUUID *uuid, struct
> VirtioSharedObject *value)
>
> Per QEMU coding style we use typedefs, so "VirtioSharedObject" here.
>
> > +{
> > +if (resource_uuids == NULL) {
> > +resource_uuids = g_hash_table_new_full(
> > +qemu_uuid_hash, uuid_equal_func, NULL, g_free);
> > +}
> > +if (g_hash_table_lookup(resource_uuids, uuid) != NULL) {
> > +return false;
> > +}
> > +
> > +return g_hash_table_insert(resource_uuids, uuid, value);
>
> Hmm shouldn't this function take the lock to access resource_uuids?
>
> > +}
> > +
> > +static gpointer virtio_lookup_resource(const QemuUUID *uuid)
> > +{
> > +if (resource_uuids == NULL) {
> > +return NULL;
> > +}
> > +
> > +return g_hash_table_lookup(resource_uuids, uuid);
>
> Ditto.
>
> Here you can directly return the casted type (VirtioSharedObject *),
> since a plain gpointer isn't really used / useful.
>
> > +}
> > +
> > +bool virt

  1   2   >