From nobody Sat Nov 15 17:43:58 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1749480562; cv=none; d=zohomail.com; s=zohoarc; b=JduFDn5/KwWTin7fRQ6Ae6JvRpBy6G6+6iR2uy5RQJDmJOcAN0lyTjBmoTR1KyZJMuNEkc8+u0zmmggzI2VHQ49yqY70d0H15L0iAFS0JhF/gRC44ePU+AFwSF0vxnZWL3uJzvIfr7+KqeaarZx7xFHfsS8C5ithMzaObVhjmeQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749480562; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=cSRvFPrucGq8avWh7bq40Vvge+7p2t9JoEZpR4AiD1U=; b=KoXhHgFHuB1ToqAoCtgLAc+O3yJC4v1JG06rlUGEPrHvq6d6QgXE9iNEGCizxplo793sw2e2nwGSFSorpZa/mu11pTaXI3UgBTgkEf1Ltfqgg0FB/Hse3ZvVrDncgY1X6NaRMpU/YO89gSu4TFip2DR5sIcdhUd//PDShIhW7Bg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749480562809430.08401557039997; Mon, 9 Jun 2025 07:49:22 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOdoD-0005Kh-IQ; Mon, 09 Jun 2025 10:49:09 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOdo9-0005IT-K7 for qemu-devel@nongnu.org; Mon, 09 Jun 2025 10:49:05 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOdo6-0008OW-Ky for qemu-devel@nongnu.org; Mon, 09 Jun 2025 10:49:05 -0400 Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-124-ISnaNOUjM66GFsnpi1b3IQ-1; Mon, 09 Jun 2025 10:47:43 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0F2AB19560B0; Mon, 9 Jun 2025 14:47:42 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.44.33.48]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 86A3619560AF; Mon, 9 Jun 2025 14:47:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1749480541; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cSRvFPrucGq8avWh7bq40Vvge+7p2t9JoEZpR4AiD1U=; b=TZvWJKouRC4u+u/lVuFKPS7VXf67sEJM707GDHBEcFCDeG72a9JwvhQPfnljYZsgZkgcFw sR2E9o3lEL3zGD2Z8dE/XCCIEzb8pZnQuY2i2x4e9Fd6zWYxYN2UD+BaOsuD0KKOF0T7EI PF07FWmpaXPydjFOKlzhmMfNRpv7Bbs= X-MC-Unique: ISnaNOUjM66GFsnpi1b3IQ-1 X-Mimecast-MFC-AGG-ID: ISnaNOUjM66GFsnpi1b3IQ_1749480462 From: Albert Esteve To: qemu-devel@nongnu.org Cc: stefanha@redhat.com, slp@redhat.com, david@redhat.com, "Michael S. Tsirkin" , Stefano Garzarella , jasowang@redhat.com, stevensd@chromium.org, hi@alyssa.is, =?UTF-8?q?Alex=20Benn=C3=A9e?= , Albert Esteve Subject: [PATCH v5 1/7] vhost-user: Add VirtIO Shared Memory map request Date: Mon, 9 Jun 2025 16:47:23 +0200 Message-ID: <20250609144729.884027-2-aesteve@redhat.com> In-Reply-To: <20250609144729.884027-1-aesteve@redhat.com> References: <20250609144729.884027-1-aesteve@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=aesteve@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1749480564225116600 Content-Type: text/plain; charset="utf-8" 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`. The map is performed by calling `memory_region_init_ram_from_fd` and adding the new region as a subregion of the shmem container MR. 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 it is valid. The backend can unmap 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 delete the MR as a subregion of the shmem container region and free its resources. Note that commit all these operations need to be delayed to after we respond the request to the backend to avoid deadlocks. The device model needs to create VirtSharedMemory instances for the VirtIO Shared Memory Regions and add them to the `VirtIODevice` instance. Signed-off-by: Albert Esteve --- hw/virtio/vhost-user.c | 150 ++++++++++++++++++++++ hw/virtio/virtio.c | 97 ++++++++++++++ include/hw/virtio/virtio.h | 29 +++++ subprojects/libvhost-user/libvhost-user.c | 70 ++++++++++ subprojects/libvhost-user/libvhost-user.h | 54 ++++++++ 5 files changed, 400 insertions(+) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 1e1d6b0d6e..9c635fb928 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 =3D 6, VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE =3D 7, VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP =3D 8, + VHOST_USER_BACKEND_SHMEM_MAP =3D 9, + VHOST_USER_BACKEND_SHMEM_UNMAP =3D 10, VHOST_USER_BACKEND_MAX } VhostUserBackendRequest; =20 @@ -192,6 +194,23 @@ typedef struct VhostUserShared { unsigned char uuid[16]; } VhostUserShared; =20 +/* For the flags field of VhostUserMMap */ +#define VHOST_USER_FLAG_MAP_RW (1u << 0) + +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_MAP_* */ + uint16_t flags; +} VhostUserMMap; + typedef struct { VhostUserRequest request; =20 @@ -224,6 +243,7 @@ typedef union { VhostUserInflight inflight; VhostUserShared object; VhostUserTransferDeviceState transfer_state; + VhostUserMMap mmap; } VhostUserPayload; =20 typedef struct VhostUserMsg { @@ -1768,6 +1788,129 @@ vhost_user_backend_handle_shared_object_lookup(stru= ct vhost_user *u, return 0; } =20 +static int +vhost_user_backend_handle_shmem_map(struct vhost_dev *dev, + QIOChannel *ioc, + VhostUserHeader *hdr, + VhostUserPayload *payload, + int fd) +{ + uint32_t ram_flags; + VirtSharedMemory *shmem; + VhostUserMMap *vu_mmap =3D &payload->mmap; + Error *local_err =3D NULL; + g_autoptr(GString) shm_name =3D g_string_new(NULL); + + if (fd < 0) { + error_report("Bad fd for map"); + return -EBADF; + } + + if (QSIMPLEQ_EMPTY(&dev->vdev->shmem_list)) { + error_report("Device has no VIRTIO Shared Memory Regions. " + "Requested ID: %d", vu_mmap->shmid); + return -EFAULT; + } + + shmem =3D virtio_find_shmem_region(dev->vdev, vu_mmap->shmid); + if (!shmem) { + error_report("VIRTIO Shared Memory Region at " + "ID %d not found or unitialized", vu_mmap->shmid); + return -EFAULT; + } + + if ((vu_mmap->shm_offset + vu_mmap->len) < vu_mmap->len || + (vu_mmap->shm_offset + vu_mmap->len) > shmem->mr->size) { + error_report("Bad offset/len for mmap %" PRIx64 "+%" PRIx64, + vu_mmap->shm_offset, vu_mmap->len); + return -EFAULT; + } + + g_string_printf(shm_name, "virtio-shm%i-%lu", + vu_mmap->shmid, vu_mmap->shm_offset); + + memory_region_transaction_begin(); + ram_flags =3D RAM_SHARED | + ((vu_mmap->flags & VHOST_USER_FLAG_MAP_RW) ? 0 : RAM_READO= NLY); + if (virtio_add_shmem_map(shmem, shm_name->str, vu_mmap->shm_offset, + vu_mmap->fd_offset, vu_mmap->len, ram_flags, + fd) !=3D 0) { + memory_region_transaction_commit(); + return -EFAULT; + } + + if (hdr->flags & VHOST_USER_NEED_REPLY_MASK) { + payload->u64 =3D 0; + hdr->size =3D sizeof(payload->u64); + vhost_user_send_resp(ioc, hdr, payload, &local_err); + if (local_err) { + error_report_err(local_err); + memory_region_transaction_commit(); + return -EFAULT; + } + } + + memory_region_transaction_commit(); + + return 0; +} + +static int +vhost_user_backend_handle_shmem_unmap(struct vhost_dev *dev, + QIOChannel *ioc, + VhostUserHeader *hdr, + VhostUserPayload *payload) +{ + VirtSharedMemory *shmem; + MappedMemoryRegion *mmap =3D NULL; + VhostUserMMap *vu_mmap =3D &payload->mmap; + Error *local_err =3D NULL; + + if (QSIMPLEQ_EMPTY(&dev->vdev->shmem_list)) { + error_report("Device has no VIRTIO Shared Memory Regions. " + "Requested ID: %d", vu_mmap->shmid); + return -EFAULT; + } + + shmem =3D virtio_find_shmem_region(dev->vdev, vu_mmap->shmid); + if (!shmem) { + error_report("VIRTIO Shared Memory Region at " + "ID %d not found or unitialized", vu_mmap->shmid); + return -EFAULT; + } + + if ((vu_mmap->shm_offset + vu_mmap->len) < vu_mmap->len || + (vu_mmap->shm_offset + vu_mmap->len) > shmem->mr->size) { + error_report("Bad offset/len for unmmap %" PRIx64 "+%" PRIx64, + vu_mmap->shm_offset, vu_mmap->len); + return -EFAULT; + } + + mmap =3D virtio_find_shmem_map(shmem, vu_mmap->shm_offset, vu_mmap->le= n); + if (!mmap) { + return -EFAULT; + } + + memory_region_transaction_begin(); + memory_region_del_subregion(shmem->mr, mmap->mem); + if (hdr->flags & VHOST_USER_NEED_REPLY_MASK) { + payload->u64 =3D 0; + hdr->size =3D sizeof(payload->u64); + vhost_user_send_resp(ioc, hdr, payload, &local_err); + if (local_err) { + error_report_err(local_err); + memory_region_transaction_commit(); + return -EFAULT; + } + } + memory_region_transaction_commit(); + + /* Free the MemoryRegion only after vhost_commit */ + virtio_del_shmem_map(shmem, vu_mmap->shm_offset, vu_mmap->len); + + return 0; +} + static void close_backend_channel(struct vhost_user *u) { g_source_destroy(u->backend_src); @@ -1836,6 +1979,13 @@ static gboolean backend_read(QIOChannel *ioc, GIOCon= dition condition, ret =3D vhost_user_backend_handle_shared_object_lookup(dev->opaque= , ioc, &hdr, &payloa= d); break; + case VHOST_USER_BACKEND_SHMEM_MAP: + ret =3D vhost_user_backend_handle_shmem_map(dev, ioc, &hdr, &paylo= ad, + fd ? fd[0] : -1); + break; + case VHOST_USER_BACKEND_SHMEM_UNMAP: + ret =3D vhost_user_backend_handle_shmem_unmap(dev, ioc, &hdr, &pay= load); + break; default: error_report("Received unexpected msg type: %d.", hdr.request); ret =3D -EINVAL; diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 5534251e01..208ad11685 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3035,6 +3035,92 @@ int virtio_save(VirtIODevice *vdev, QEMUFile *f) return vmstate_save_state(f, &vmstate_virtio, vdev, NULL); } =20 +VirtSharedMemory *virtio_new_shmem_region(VirtIODevice *vdev, uint8_t shmi= d) +{ + VirtSharedMemory *elem; + elem =3D g_new0(VirtSharedMemory, 1); + elem->shmid =3D shmid; + elem->mr =3D g_new0(MemoryRegion, 1); + QTAILQ_INIT(&elem->mmaps); + QSIMPLEQ_INSERT_TAIL(&vdev->shmem_list, elem, entry); + return QSIMPLEQ_LAST(&vdev->shmem_list, VirtSharedMemory, entry); +} + +VirtSharedMemory *virtio_find_shmem_region(VirtIODevice *vdev, uint8_t shm= id) +{ + VirtSharedMemory *shmem, *next; + QSIMPLEQ_FOREACH_SAFE(shmem, &vdev->shmem_list, entry, next) { + if (shmem->shmid =3D=3D shmid) { + return shmem; + } + } + return NULL; +} + +int virtio_add_shmem_map(VirtSharedMemory *shmem, const char *shm_name, + hwaddr shm_offset, hwaddr fd_offset, uint64_t si= ze, + uint32_t ram_flags, int fd) +{ + Error *err =3D NULL; + MappedMemoryRegion *mmap; + fd =3D dup(fd); + if (fd < 0) { + error_report("Failed to duplicate fd: %s", strerror(errno)); + return -1; + } + + if (shm_offset + size > shmem->mr->size) { + error_report("Memory exceeds the shared memory boundaries"); + close(fd); + return -1; + } + + mmap =3D g_new0(MappedMemoryRegion, 1); + mmap->mem =3D g_new0(MemoryRegion, 1); + mmap->offset =3D shm_offset; + memory_region_init_ram_from_fd(mmap->mem, + OBJECT(shmem->mr), + shm_name, size, ram_flags, + fd, fd_offset, &err); + if (err) { + error_report_err(err); + close(fd); + g_free(mmap->mem); + g_free(mmap); + return -1; + } + memory_region_add_subregion(shmem->mr, shm_offset, mmap->mem); + + QTAILQ_INSERT_TAIL(&shmem->mmaps, mmap, link); + + return 0; +} + +MappedMemoryRegion *virtio_find_shmem_map(VirtSharedMemory *shmem, + hwaddr offset, uint64_t size) +{ + MappedMemoryRegion *mmap; + QTAILQ_FOREACH(mmap, &shmem->mmaps, link) { + if (mmap->offset =3D=3D offset && mmap->mem->size =3D=3D size) { + return mmap; + } + } + return NULL; +} + +void virtio_del_shmem_map(VirtSharedMemory *shmem, hwaddr offset, + uint64_t size) +{ + MappedMemoryRegion *mmap =3D virtio_find_shmem_map(shmem, offset, size= ); + if (mmap =3D=3D NULL) { + return; + } + + object_unparent(OBJECT(mmap->mem)); + QTAILQ_REMOVE(&shmem->mmaps, mmap, link); + g_free(mmap); +} + /* A wrapper for use as a VMState .put function */ static int virtio_device_put(QEMUFile *f, void *opaque, size_t size, const VMStateField *field, JSONWriter *vmdes= c) @@ -3511,6 +3597,7 @@ void virtio_init(VirtIODevice *vdev, uint16_t device_= id, size_t config_size) NULL, virtio_vmstate_change, vdev); vdev->device_endian =3D virtio_default_endian(); vdev->use_guest_notifier_mask =3D true; + QSIMPLEQ_INIT(&vdev->shmem_list); } =20 /* @@ -4022,11 +4109,21 @@ static void virtio_device_free_virtqueues(VirtIODev= ice *vdev) static void virtio_device_instance_finalize(Object *obj) { VirtIODevice *vdev =3D VIRTIO_DEVICE(obj); + VirtSharedMemory *shmem; =20 virtio_device_free_virtqueues(vdev); =20 g_free(vdev->config); g_free(vdev->vector_queues); + while (!QSIMPLEQ_EMPTY(&vdev->shmem_list)) { + shmem =3D QSIMPLEQ_FIRST(&vdev->shmem_list); + while (!QTAILQ_EMPTY(&shmem->mmaps)) { + MappedMemoryRegion *mmap_reg =3D QTAILQ_FIRST(&shmem->mmaps); + virtio_del_shmem_map(shmem, mmap_reg->offset, mmap_reg->mem->s= ize); + } + QSIMPLEQ_REMOVE_HEAD(&vdev->shmem_list, entry); + g_free(shmem); + } } =20 static const Property virtio_properties[] =3D { diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 214d4a77e9..331dbcfbe0 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -98,6 +98,23 @@ enum virtio_device_endian { VIRTIO_DEVICE_ENDIAN_BIG, }; =20 +struct MappedMemoryRegion { + MemoryRegion *mem; + hwaddr offset; + QTAILQ_ENTRY(MappedMemoryRegion) link; +}; + +typedef struct MappedMemoryRegion MappedMemoryRegion; + +struct VirtSharedMemory { + uint8_t shmid; + MemoryRegion *mr; + QTAILQ_HEAD(, MappedMemoryRegion) mmaps; + QSIMPLEQ_ENTRY(VirtSharedMemory) entry; +}; + +typedef struct VirtSharedMemory VirtSharedMemory; + /** * struct VirtIODevice - common VirtIO structure * @name: name of the device @@ -167,6 +184,8 @@ struct VirtIODevice */ EventNotifier config_notifier; bool device_iotlb_enabled; + /* Shared memory region for mappings. */ + QSIMPLEQ_HEAD(, VirtSharedMemory) shmem_list; }; =20 struct VirtioDeviceClass { @@ -289,6 +308,16 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); =20 int virtio_save(VirtIODevice *vdev, QEMUFile *f); =20 +VirtSharedMemory *virtio_new_shmem_region(VirtIODevice *vdev, uint8_t shmi= d); +VirtSharedMemory *virtio_find_shmem_region(VirtIODevice *vdev, uint8_t shm= id); +int virtio_add_shmem_map(VirtSharedMemory *shmem, const char *shm_name, + hwaddr shm_offset, hwaddr fd_offset, uint64_t si= ze, + uint32_t ram_flags, int fd); +MappedMemoryRegion *virtio_find_shmem_map(VirtSharedMemory *shmem, + hwaddr offset, uint64_t size); +void virtio_del_shmem_map(VirtSharedMemory *shmem, hwaddr offset, + uint64_t size); + extern const VMStateInfo virtio_vmstate_info; =20 #define VMSTATE_VIRTIO_DEVICE \ diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvho= st-user/libvhost-user.c index 9c630c2170..034cbfdc3c 100644 --- a/subprojects/libvhost-user/libvhost-user.c +++ b/subprojects/libvhost-user/libvhost-user.c @@ -1592,6 +1592,76 @@ vu_rm_shared_object(VuDev *dev, unsigned char uuid[U= UID_LEN]) return vu_send_message(dev, &msg); } =20 +bool +vu_shmem_map(VuDev *dev, uint8_t shmid, uint64_t fd_offset, + uint64_t shm_offset, uint64_t len, uint64_t flags, int fd) +{ + VhostUserMsg vmsg =3D { + .request =3D VHOST_USER_BACKEND_SHMEM_MAP, + .size =3D sizeof(vmsg.payload.mmap), + .flags =3D VHOST_USER_VERSION, + .payload.mmap =3D { + .shmid =3D shmid, + .fd_offset =3D fd_offset, + .shm_offset =3D shm_offset, + .len =3D len, + .flags =3D flags, + }, + .fd_num =3D 1, + .fds[0] =3D fd, + }; + + if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHMEM)) { + return false; + } + + if (vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_REPLY_ACK)) { + vmsg.flags |=3D VHOST_USER_NEED_REPLY_MASK; + } + + pthread_mutex_lock(&dev->backend_mutex); + if (!vu_message_write(dev, dev->backend_fd, &vmsg)) { + pthread_mutex_unlock(&dev->backend_mutex); + return false; + } + + /* Also unlocks the backend_mutex */ + return vu_process_message_reply(dev, &vmsg); +} + +bool +vu_shmem_unmap(VuDev *dev, uint8_t shmid, uint64_t shm_offset, uint64_t le= n) +{ + VhostUserMsg vmsg =3D { + .request =3D VHOST_USER_BACKEND_SHMEM_UNMAP, + .size =3D sizeof(vmsg.payload.mmap), + .flags =3D VHOST_USER_VERSION, + .payload.mmap =3D { + .shmid =3D shmid, + .fd_offset =3D 0, + .shm_offset =3D shm_offset, + .len =3D len, + }, + }; + + if (!vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_SHMEM)) { + return false; + } + + if (vu_has_protocol_feature(dev, VHOST_USER_PROTOCOL_F_REPLY_ACK)) { + vmsg.flags |=3D VHOST_USER_NEED_REPLY_MASK; + } + + pthread_mutex_lock(&dev->backend_mutex); + if (!vu_message_write(dev, dev->backend_fd, &vmsg)) { + pthread_mutex_unlock(&dev->backend_mutex); + return false; + } + + /* Also unlocks the backend_mutex */ + return vu_process_message_reply(dev, &vmsg); +} + static bool vu_set_vring_call_exec(VuDev *dev, VhostUserMsg *vmsg) { diff --git a/subprojects/libvhost-user/libvhost-user.h b/subprojects/libvho= st-user/libvhost-user.h index 2ffc58c11b..26b710c92d 100644 --- a/subprojects/libvhost-user/libvhost-user.h +++ b/subprojects/libvhost-user/libvhost-user.h @@ -69,6 +69,8 @@ enum VhostUserProtocolFeature { /* Feature 16 is reserved for VHOST_USER_PROTOCOL_F_STATUS. */ /* Feature 17 reserved for VHOST_USER_PROTOCOL_F_XEN_MMAP. */ VHOST_USER_PROTOCOL_F_SHARED_OBJECT =3D 18, + /* Feature 19 is reserved for VHOST_USER_PROTOCOL_F_DEVICE_STATE */ + VHOST_USER_PROTOCOL_F_SHMEM =3D 20, VHOST_USER_PROTOCOL_F_MAX }; =20 @@ -127,6 +129,8 @@ typedef enum VhostUserBackendRequest { VHOST_USER_BACKEND_SHARED_OBJECT_ADD =3D 6, VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE =3D 7, VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP =3D 8, + VHOST_USER_BACKEND_SHMEM_MAP =3D 9, + VHOST_USER_BACKEND_SHMEM_UNMAP =3D 10, VHOST_USER_BACKEND_MAX } VhostUserBackendRequest; =20 @@ -186,6 +190,23 @@ typedef struct VhostUserShared { unsigned char uuid[UUID_LEN]; } VhostUserShared; =20 +/* For the flags field of VhostUserMMap */ +#define VHOST_USER_FLAG_MAP_RW (1u << 0) + +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_MAP_* */ + uint16_t flags; +} VhostUserMMap; + #define VU_PACKED __attribute__((packed)) =20 typedef struct VhostUserMsg { @@ -210,6 +231,7 @@ typedef struct VhostUserMsg { VhostUserVringArea area; VhostUserInflight inflight; VhostUserShared object; + VhostUserMMap mmap; } payload; =20 int fds[VHOST_MEMORY_BASELINE_NREGIONS]; @@ -593,6 +615,38 @@ bool vu_add_shared_object(VuDev *dev, unsigned char uu= id[UUID_LEN]); */ bool vu_rm_shared_object(VuDev *dev, unsigned char uuid[UUID_LEN]); =20 +/** + * vu_shmem_map: + * @dev: a VuDev context + * @shmid: VIRTIO Shared Memory Region ID + * @fd_offset: File offset + * @shm_offset: Offset within the VIRTIO Shared Memory Region + * @len: Size of the mapping + * @flags: Flags for the mmap operation + * @fd: A file descriptor + * + * Advertises a new mapping to be made in a given VIRTIO Shared Memory Reg= ion. + * + * Returns: TRUE on success, FALSE on failure. + */ +bool vu_shmem_map(VuDev *dev, uint8_t shmid, uint64_t fd_offset, + uint64_t shm_offset, uint64_t len, uint64_t flags, int f= d); + +/** + * vu_shmem_unmap: + * @dev: a VuDev context + * @shmid: VIRTIO Shared Memory Region ID + * @fd_offset: File offset + * @len: Size of the mapping + * + * The front-end un-mmaps a given range in the VIRTIO Shared Memory Region + * with the requested `shmid`. + * + * Returns: TRUE on success, FALSE on failure. + */ +bool vu_shmem_unmap(VuDev *dev, uint8_t shmid, uint64_t shm_offset, + uint64_t len); + /** * vu_queue_set_notification: * @dev: a VuDev context --=20 2.49.0