From b9d076d8af993359ec7cd2eb97572c1fe0675089 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 18 Mar 2026 10:19:39 +0100 Subject: virtio: Pass iovec arrays as separate parameters to vu_queue_pop() Currently vu_queue_pop() and vu_queue_map_desc() read the iovec arrays (in_sg/out_sg) and their sizes (in_num/out_num) from the vu_virtq_element struct. This couples the iovec storage to the element, requiring callers like vu_handle_tx() to pre-initialize the element fields before calling vu_queue_pop(). Pass the iovec arrays and their maximum sizes as separate parameters instead. vu_queue_map_desc() now writes the actual descriptor count and iovec pointers back into the element after mapping, rather than using the element as both input and output. This decouples the iovec storage from the element, which is a prerequisite for multi-buffer support where a single frame can span multiple virtqueue elements sharing a common iovec pool. No functional change. Signed-off-by: Laurent Vivier Reviewed-by: David Gibson Signed-off-by: Stefano Brivio --- virtio.c | 29 ++++++++++++++++++++++------- virtio.h | 4 +++- vu_common.c | 14 +++++++------- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/virtio.c b/virtio.c index 447137e..a671163 100644 --- a/virtio.c +++ b/virtio.c @@ -428,12 +428,18 @@ static bool virtqueue_map_desc(const struct vu_dev *dev, * @vq: Virtqueue * @idx: First descriptor ring entry to map * @elem: Virtqueue element to store descriptor ring iov + * @in_sg: Incoming iovec array for device-writable descriptors + * @max_in_sg: Maximum number of entries in @in_sg + * @out_sg: Outgoing iovec array for device-readable descriptors + * @max_out_sg: Maximum number of entries in @out_sg * * Return: -1 if there is an error, 0 otherwise */ static int vu_queue_map_desc(const struct vu_dev *dev, struct vu_virtq *vq, unsigned int idx, - struct vu_virtq_element *elem) + struct vu_virtq_element *elem, + struct iovec *in_sg, size_t max_in_sg, + struct iovec *out_sg, size_t max_out_sg) { const struct vring_desc *desc = vq->vring.desc; struct vring_desc desc_buf[VIRTQUEUE_MAX_SIZE]; @@ -470,16 +476,16 @@ static int vu_queue_map_desc(const struct vu_dev *dev, /* Collect all the descriptors */ do { if (le16toh(desc[i].flags) & VRING_DESC_F_WRITE) { - if (!virtqueue_map_desc(dev, &in_num, elem->in_sg, - elem->in_num, + if (!virtqueue_map_desc(dev, &in_num, in_sg, + max_in_sg, le64toh(desc[i].addr), le32toh(desc[i].len))) return -1; } else { if (in_num) die("Incorrect order for descriptors"); - if (!virtqueue_map_desc(dev, &out_num, elem->out_sg, - elem->out_num, + if (!virtqueue_map_desc(dev, &out_num, out_sg, + max_out_sg, le64toh(desc[i].addr), le32toh(desc[i].len))) { return -1; @@ -496,7 +502,9 @@ static int vu_queue_map_desc(const struct vu_dev *dev, die("vhost-user: Failed to read descriptor list"); elem->index = idx; + elem->in_sg = in_sg; elem->in_num = in_num; + elem->out_sg = out_sg; elem->out_num = out_num; return 0; @@ -507,11 +515,17 @@ static int vu_queue_map_desc(const struct vu_dev *dev, * @dev: Vhost-user device * @vq: Virtqueue * @elem: Virtqueue element to fill with the entry information + * @in_sg: Incoming iovec array for device-writable descriptors + * @max_in_sg: Maximum number of entries in @in_sg + * @out_sg: Outgoing iovec array for device-readable descriptors + * @max_out_sg: Maximum number of entries in @out_sg * * Return: -1 if there is an error, 0 otherwise */ int vu_queue_pop(const struct vu_dev *dev, struct vu_virtq *vq, - struct vu_virtq_element *elem) + struct vu_virtq_element *elem, + struct iovec *in_sg, size_t max_in_sg, + struct iovec *out_sg, size_t max_out_sg) { unsigned int head; int ret; @@ -535,7 +549,8 @@ int vu_queue_pop(const struct vu_dev *dev, struct vu_virtq *vq, if (vu_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) vring_set_avail_event(vq, vq->last_avail_idx); - ret = vu_queue_map_desc(dev, vq, head, elem); + ret = vu_queue_map_desc(dev, vq, head, elem, in_sg, max_in_sg, + out_sg, max_out_sg); if (ret < 0) return ret; diff --git a/virtio.h b/virtio.h index d04bbe8..c7e447d 100644 --- a/virtio.h +++ b/virtio.h @@ -188,7 +188,9 @@ static inline bool vu_has_protocol_feature(const struct vu_dev *vdev, void vu_queue_notify(const struct vu_dev *dev, struct vu_virtq *vq); int vu_queue_pop(const struct vu_dev *dev, struct vu_virtq *vq, - struct vu_virtq_element *elem); + struct vu_virtq_element *elem, + struct iovec *in_sg, size_t max_in_sg, + struct iovec *out_sg, size_t max_out_sg); void vu_queue_detach_element(struct vu_virtq *vq); void vu_queue_unpop(struct vu_virtq *vq); bool vu_queue_rewind(struct vu_virtq *vq, unsigned int num); diff --git a/vu_common.c b/vu_common.c index 5f2ce18..4d809ac 100644 --- a/vu_common.c +++ b/vu_common.c @@ -91,7 +91,11 @@ int vu_collect(const struct vu_dev *vdev, struct vu_virtq *vq, struct iovec *iov; int ret; - ret = vu_queue_pop(vdev, vq, &elem[elem_cnt]); + ret = vu_queue_pop(vdev, vq, &elem[elem_cnt], + elem[elem_cnt].in_sg, + elem[elem_cnt].in_num, + elem[elem_cnt].out_sg, + elem[elem_cnt].out_num); if (ret < 0) break; @@ -178,12 +182,8 @@ static void vu_handle_tx(struct vu_dev *vdev, int index, int ret; struct iov_tail data; - elem[count].out_num = VU_MAX_TX_BUFFER_NB; - elem[count].out_sg = &out_sg[out_sg_count]; - elem[count].in_num = 0; - elem[count].in_sg = NULL; - - ret = vu_queue_pop(vdev, vq, &elem[count]); + ret = vu_queue_pop(vdev, vq, &elem[count], NULL, 0, + &out_sg[out_sg_count], VU_MAX_TX_BUFFER_NB); if (ret < 0) break; out_sg_count += elem[count].out_num; -- cgit v1.2.3