100
VHOST_USER_GET_SHARED_OBJECT = 41,
101
VHOST_USER_SET_DEVICE_STATE_FD = 42,
102
VHOST_USER_CHECK_DEVICE_STATE = 43,
103
+ VHOST_USER_GET_SHMEM_CONFIG = 44,
104
VHOST_USER_MAX
105
} VhostUserRequest;
106
112
VHOST_USER_BACKEND_SHARED_OBJECT_ADD = 6,
113
VHOST_USER_BACKEND_SHARED_OBJECT_REMOVE = 7,
114
VHOST_USER_BACKEND_SHARED_OBJECT_LOOKUP = 8,
115
+ VHOST_USER_BACKEND_SHMEM_MAP = 9,
116
+ VHOST_USER_BACKEND_SHMEM_UNMAP = 10,
117
VHOST_USER_BACKEND_MAX
118
} VhostUserBackendRequest;
119
192
VhostUserMemoryRegion region;
193
} VhostUserMemRegMsg;
194
195
+typedef struct VhostUserShMemConfig {
196
+ uint32_t nregions;
197
+ uint32_t padding;
198
+ uint64_t memory_sizes[VIRTIO_MAX_SHMEM_REGIONS];
199
+} VhostUserShMemConfig;
200
+
201
typedef struct VhostUserLog {
202
uint64_t mmap_size;
203
uint64_t mmap_offset;
254
unsigned char uuid[16];
255
} VhostUserShared;
256
257
+/* For the flags field of VhostUserMMap */
258
+#define VHOST_USER_FLAG_MAP_RW (1u << 0)
259
+
260
+typedef struct {
261
+ /* VIRTIO Shared Memory Region ID */
262
+ uint8_t shmid;
263
+ uint8_t padding[7];
264
+ /* File offset */
265
+ uint64_t fd_offset;
266
+ /* Offset within the VIRTIO Shared Memory Region */
267
+ uint64_t shm_offset;
268
+ /* Size of the mapping */
269
+ uint64_t len;
270
+ /* Flags for the mmap operation, from VHOST_USER_FLAG_MAP_* */
271
+ uint64_t flags;
272
+} VhostUserMMap;
273
+
274
typedef struct {
275
VhostUserRequest request;
276
303
VhostUserInflight inflight;
304
VhostUserShared object;
305
VhostUserTransferDeviceState transfer_state;
306
+ VhostUserMMap mmap;
307
+ VhostUserShMemConfig shmem;
308
} VhostUserPayload;
309
310
typedef struct VhostUserMsg {
1888
return 0;
1889
}
1890
1891
+/**
1892
+ * vhost_user_backend_handle_shmem_map() - Handle SHMEM_MAP backend request
1893
+ * @dev: vhost device
1894
+ * @ioc: QIOChannel for communication
1895
+ * @hdr: vhost-user message header
1896
+ * @payload: message payload containing mapping details
1897
+ * @fd: file descriptor for the shared memory region
1898
+ *
1899
+ * Handles VHOST_USER_BACKEND_SHMEM_MAP requests from the backend. Creates
1900
+ * a VhostUserShmemObject to manage the shared memory mapping and adds it
1901
+ * to the appropriate VirtIO shared memory region. The VhostUserShmemObject
1902
+ * serves as an intermediate parent for the MemoryRegion, ensuring proper
1903
+ * lifecycle management with reference counting.
1904
+ *
1905
+ * Returns: 0 on success, negative errno on failure
1906
+ */
1907
+static int
1908
+vhost_user_backend_handle_shmem_map(struct vhost_dev *dev,
1909
+ QIOChannel *ioc,
1910
+ VhostUserHeader *hdr,
1911
+ VhostUserPayload *payload,
1912
+ int fd)
1913
+{
1914
+ VirtioSharedMemory *shmem;
1915
+ VhostUserMMap *vu_mmap = &payload->mmap;
1916
+ VirtioSharedMemoryMapping *existing;
1917
+ Error *local_err = NULL;
1918
+ int ret = 0;
1919
+
1920
+ if (fd < 0) {
1921
+ error_report("Bad fd for map");
1922
+ ret = -EBADF;
1923
+ goto send_reply;
1924
+ }
1925
+
1926
+ if (QSIMPLEQ_EMPTY(&dev->vdev->shmem_list)) {
1927
+ error_report("Device has no VIRTIO Shared Memory Regions. "
1928
+ "Requested ID: %d", vu_mmap->shmid);
1929
+ ret = -EFAULT;
1930
+ goto send_reply;
1931
+ }
1932
+
1933
+ shmem = virtio_find_shmem_region(dev->vdev, vu_mmap->shmid);
1934
+ if (!shmem) {
1935
+ error_report("VIRTIO Shared Memory Region at "
1936
+ "ID %d not found or uninitialized", vu_mmap->shmid);
1937
+ ret = -EFAULT;
1938
+ goto send_reply;
1939
+ }
1940
+
1941
+ if ((vu_mmap->shm_offset + vu_mmap->len) < vu_mmap->len ||
1942
+ (vu_mmap->shm_offset + vu_mmap->len) > memory_region_size(&shmem->mr)) {
1943
+ error_report("Bad offset/len for mmap %" PRIx64 "+%" PRIx64,
1944
+ vu_mmap->shm_offset, vu_mmap->len);
1945
+ ret = -EFAULT;
1946
+ goto send_reply;
1947
+ }
1948
+
1949
+ QTAILQ_FOREACH(existing, &shmem->mmaps, link) {
1950
+ if (ranges_overlap(existing->offset, existing->len,
1951
+ vu_mmap->shm_offset, vu_mmap->len)) {
1952
+ error_report("VIRTIO Shared Memory mapping overlap");
1953
+ ret = -EFAULT;
1954
+ goto send_reply;
1955
+ }
1956
+ }
1957
+
1958
+ memory_region_transaction_begin();
1959
+
1960
+ /* Create VirtioSharedMemoryMapping object */
1961
+ VirtioSharedMemoryMapping *mapping = virtio_shared_memory_mapping_new(
1962
+ vu_mmap->shmid, fd, vu_mmap->fd_offset, vu_mmap->shm_offset,
1963
+ vu_mmap->len, vu_mmap->flags & VHOST_USER_FLAG_MAP_RW);
1964
+
1965
+ if (!mapping) {
1966
+ ret = -EFAULT;
1967
+ goto send_reply_commit;
1968
+ }
1969
+
1970
+ /* Add the mapping to the shared memory region */
1971
+ if (virtio_add_shmem_map(shmem, mapping) != 0) {
1972
+ error_report("Failed to add shared memory mapping");
1973
+ object_unref(OBJECT(mapping));
1974
+ ret = -EFAULT;
1975
+ goto send_reply_commit;
1976
+ }
1977
+
1978
+send_reply_commit:
1979
+ /* Send reply and commit after transaction started */
1980
+ if (hdr->flags & VHOST_USER_NEED_REPLY_MASK) {
1981
+ payload->u64 = !!ret;
1982
+ hdr->size = sizeof(payload->u64);
1983
+ if (!vhost_user_send_resp(ioc, hdr, payload, &local_err)) {
1984
+ error_report_err(local_err);
1985
+ memory_region_transaction_commit();
1986
+ return -EFAULT;
1987
+ }
1988
+ }
1989
+ memory_region_transaction_commit();
1990
+ return 0;
1991
+
1992
+send_reply:
1993
+ if (hdr->flags & VHOST_USER_NEED_REPLY_MASK) {
1994
+ payload->u64 = !!ret;
1995
+ hdr->size = sizeof(payload->u64);
1996
+ if (!vhost_user_send_resp(ioc, hdr, payload, &local_err)) {
1997
+ error_report_err(local_err);
1998
+ return -EFAULT;
1999
+ }
2000
+ }
2001
+ return 0;
2002
+}
2003
+
2004
+/**
2005
+ * vhost_user_backend_handle_shmem_unmap() - Handle SHMEM_UNMAP backend request
2006
+ * @dev: vhost device
2007
+ * @ioc: QIOChannel for communication
2008
+ * @hdr: vhost-user message header
2009
+ * @payload: message payload containing unmapping details
2010
+ *
2011
+ * Handles VHOST_USER_BACKEND_SHMEM_UNMAP requests from the backend. Removes
2012
+ * the specified memory mapping from the VirtIO shared memory region. This
2013
+ * automatically unreferences the associated VhostUserShmemObject, which may
2014
+ * trigger its finalization and cleanup (munmap, close fd) if no other
2015
+ * references exist.
2016
+ *
2017
+ * Returns: 0 on success, negative errno on failure
2018
+ */
2019
+static int
2020
+vhost_user_backend_handle_shmem_unmap(struct vhost_dev *dev,
2021
+ QIOChannel *ioc,
2022
+ VhostUserHeader *hdr,
2023
+ VhostUserPayload *payload)
2024
+{
2025
+ VirtioSharedMemory *shmem = NULL;
2026
+ VirtioSharedMemoryMapping *mmap = NULL;
2027
+ VhostUserMMap *vu_mmap = &payload->mmap;
2028
+ Error *local_err = NULL;
2029
+ int ret = 0;
2030
+
2031
+ if (QSIMPLEQ_EMPTY(&dev->vdev->shmem_list)) {
2032
+ error_report("Device has no VIRTIO Shared Memory Regions. "
2033
+ "Requested ID: %d", vu_mmap->shmid);
2034
+ ret = -EFAULT;
2035
+ goto send_reply;
2036
+ }
2037
+
2038
+ shmem = virtio_find_shmem_region(dev->vdev, vu_mmap->shmid);
2039
+ if (!shmem) {
2040
+ error_report("VIRTIO Shared Memory Region at "
2041
+ "ID %d not found or uninitialized", vu_mmap->shmid);
2042
+ ret = -EFAULT;
2043
+ goto send_reply;
2044
+ }
2045
+
2046
+ if ((vu_mmap->shm_offset + vu_mmap->len) < vu_mmap->len ||
2047
+ (vu_mmap->shm_offset + vu_mmap->len) > memory_region_size(&shmem->mr)) {
2048
+ error_report("Bad offset/len for unmmap %" PRIx64 "+%" PRIx64,
2049
+ vu_mmap->shm_offset, vu_mmap->len);
2050
+ ret = -EFAULT;
2051
+ goto send_reply;
2052
+ }
2053
+
2054
+ mmap = virtio_find_shmem_map(shmem, vu_mmap->shm_offset, vu_mmap->len);
2055
+ if (!mmap) {
2056
+ error_report("Shared memory mapping not found at offset %" PRIx64
2057
+ " with length %" PRIx64,
2058
+ vu_mmap->shm_offset, vu_mmap->len);
2059
+ ret = -EFAULT;
2060
+ goto send_reply;
2061
+ }
2062
+
2063
+send_reply:
2064
+ if (hdr->flags & VHOST_USER_NEED_REPLY_MASK) {
2065
+ payload->u64 = !!ret;
2066
+ hdr->size = sizeof(payload->u64);
2067
+ if (!vhost_user_send_resp(ioc, hdr, payload, &local_err)) {
2068
+ error_report_err(local_err);
2069
+ return -EFAULT;
2070
+ }
2071
+ }
2072
+
2073
+ if (!ret && shmem && mmap) {
2074
+ /* Free the MemoryRegion only after reply */
2075
+ virtio_del_shmem_map(shmem, vu_mmap->shm_offset, vu_mmap->len);
2076
+ }
2077
+
2078
+ return 0;
2079
+}
2080
+
2081
static void close_backend_channel(struct vhost_user *u)
2082
{
2083
g_source_destroy(u->backend_src);
2151
ret = vhost_user_backend_handle_shared_object_lookup(dev->opaque,
2152
&payload.object);
2153
break;
2154
+ case VHOST_USER_BACKEND_SHMEM_MAP:
2155
+ /* Handler manages its own response, check error and close connection */
2156
+ reply_ack = false;
2157
+ if (vhost_user_backend_handle_shmem_map(dev, ioc, &hdr, &payload,
2158
+ fd ? fd[0] : -1) < 0) {
2159
+ goto err;
2160
+ }
2161
+ break;
2162
+ case VHOST_USER_BACKEND_SHMEM_UNMAP:
2163
+ /* Handler manages its own response, check error and close connection */
2164
+ reply_ack = false;
2165
+ if (vhost_user_backend_handle_shmem_unmap(dev, ioc, &hdr, &payload) < 0) {
2166
+ goto err;
2167
+ }
2168
+ break;
2169
default:
2170
error_report("Received unexpected msg type: %d.", hdr.request);
2171
ret = -EINVAL;
3356
qmp_decode_protocols(u->protocol_features);
3357
}
3358
3359
+static int vhost_user_get_shmem_config(struct vhost_dev *dev,
3360
+ int *nregions,
3361
+ uint64_t *memory_sizes,
3362
+ Error **errp)
3363
+{
3364
+ int ret;
3365
+ VhostUserMsg msg = {
3366
+ .hdr.request = VHOST_USER_GET_SHMEM_CONFIG,
3367
+ .hdr.flags = VHOST_USER_VERSION,
3368
+ };
3369
+
3370
+ if (!vhost_user_has_protocol_feature(dev,
3371
+ VHOST_USER_PROTOCOL_F_SHMEM)) {
3372
+ *nregions = 0;
3373
+ return 0;
3374
+ }
3375
+
3376
+ ret = vhost_user_write(dev, &msg, NULL, 0);
3377
+ if (ret < 0) {
3378
+ return ret;
3379
+ }
3380
+
3381
+ ret = vhost_user_read(dev, &msg);
3382
+ if (ret < 0) {
3383
+ return ret;
3384
+ }
3385
+
3386
+ if (msg.payload.shmem.nregions > VIRTIO_MAX_SHMEM_REGIONS) {
3387
+ error_setg(errp, "Received too many shared memory regions: %d",
3388
+ msg.payload.shmem.nregions);
3389
+ return -EINVAL;
3390
+ }
3391
+
3392
+ *nregions = msg.payload.shmem.nregions;
3393
+ memcpy(memory_sizes,
3394
+ &msg.payload.shmem.memory_sizes,
3395
+ sizeof(uint64_t) * VIRTIO_MAX_SHMEM_REGIONS);
3396
+ return 0;
3397
+}
3398
+
3399
const VhostOps user_ops = {
3400
.backend_type = VHOST_BACKEND_TYPE_USER,
3401
.vhost_init = vhost_user_backend_init,
3436
.vhost_check_device_state = vhost_user_check_device_state,
3437
.vhost_phys_vring_addr = vhost_user_gpa_addresses,
3438
.vhost_phys_iotlb_msg = vhost_user_gpa_addresses,
3439
+ .vhost_get_shmem_config = vhost_user_get_shmem_config,
3440
};