On 3/18/26 10:04, Stefano Brivio wrote:
On Wed, 18 Mar 2026 08:21:10 +0100 Laurent Vivier
wrote: On 3/18/26 02:16, David Gibson wrote:
On Tue, Mar 17, 2026 at 05:30:32PM +0100, Laurent Vivier wrote:
On 3/17/26 16:23, Stefano Brivio wrote:
On Tue, 17 Mar 2026 08:25:49 +0100 Laurent Vivier
wrote: On 3/17/26 03:40, David Gibson wrote: > On Fri, Mar 13, 2026 at 07:26:18PM +0100, Laurent Vivier wrote: >> Previously, callers had to pre-initialize virtqueue elements with iovec >> entries using vu_set_element() or vu_init_elem() before calling >> vu_collect(). This meant each element owned a fixed, pre-assigned iovec >> slot. >> >> Move the iovec array into vu_collect() as explicit parameters (in_sg, >> max_in_sg, and in_num), letting it pass the remaining iovec capacity >> directly to vu_queue_pop(). A running current_iov counter tracks >> consumed entries across elements, so multiple elements share a single >> iovec pool. The optional in_num output parameter reports how many iovec >> entries were consumed, allowing callers to track usage across multiple >> vu_collect() calls. >> >> This removes vu_set_element() and vu_init_elem() which are no longer >> needed, and is a prerequisite for multi-buffer support where a single >> virtqueue element can use more than one iovec entry. For now, callers >> assert the current single-iovec-per-element invariant until they are >> updated to handle multiple iovecs. >> >> Signed-off-by: Laurent Vivier
> > Reviewed-by: David Gibson > > Couple of thoughts on possible polish below. > > [snip] >> /** >> * vu_collect() - collect virtio buffers from a given virtqueue >> * @vdev: vhost-user device >> * @vq: virtqueue to collect from >> - * @elem: Array of virtqueue element >> - * each element must be initialized with one iovec entry >> - * in the in_sg array. >> + * @elem: Array of @max_elem virtqueue elements >> * @max_elem: Number of virtqueue elements in the array >> + * @in_sg: Incoming iovec array for device-writable descriptors >> + * @max_in_sg: Maximum number of entries in @in_sg >> + * @in_num: Number of collected entries from @in_sg (output) >> * @size: Maximum size of the data in the frame >> * @collected: Collected buffer length, up to @size, set on return >> * >> @@ -80,20 +67,21 @@ void vu_init_elem(struct vu_virtq_element *elem, struct iovec *iov, int elem_cnt >> */ >> int vu_collect(const struct vu_dev *vdev, struct vu_virtq *vq, >> struct vu_virtq_element *elem, int max_elem, >> + struct iovec *in_sg, size_t max_in_sg, size_t *in_num, >> size_t size, size_t *collected) >> { >> size_t current_size = 0; >> + size_t current_iov = 0; >> int elem_cnt = 0; >> - while (current_size < size && elem_cnt < max_elem) { >> - struct iovec *iov; >> + while (current_size < size && elem_cnt < max_elem && >> + current_iov < max_in_sg) { >> int ret; >> 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); >> + &in_sg[current_iov], >> + max_in_sg - current_iov, >> + NULL, 0); >> if (ret < 0) >> break; >> @@ -103,18 +91,22 @@ int vu_collect(const struct vu_dev *vdev, struct vu_virtq *vq, >> break; >> } >> - iov = &elem[elem_cnt].in_sg[0]; >> - >> - if (iov->iov_len > size - current_size) >> - iov->iov_len = size - current_size; >> + elem[elem_cnt].in_num = iov_truncate(elem[elem_cnt].in_sg, >> + elem[elem_cnt].in_num, >> + size - current_size); > > Will elem[].in_num always end up with the same value as the @in_num > parameter? If so, do we need the explicit parameter? @in_num parameter of vu_collect()?
@in_num is the sum of all elem[].in_num, it can be computed by the caller function from elem, but it is simpler to return it as we need to compute it in the loop.
I'm not sure I understood the point of David's comment here, and this explanation makes sense to me now, but it took me a bit to figure that out.
Could it be that @in_num is a bit confusing as it has "in" and "num" in it, but it's actually an output representing how many "in" entries we used/need?
For an element, *ìn_*num is the number of *in_*sg we have read from the ring for an element.
It's virtio semantic, so *in_* means sg going *in* the guest.
For *out_*sg we have *out_*num.
What if we rename it to @in_used or @in_collected?
The idea was to keep the same name as in the element. But we can change this to @in_used.
Would "in_total" work better to suggest that it's the sum of all the elements' in_num?
Yes, I think it gives the information it's the sum of the in_num
Okay, should I change this on merge, or do you plan to repost (which would be slightly more convenient for me but not really needed)?
I'm preparing the v3. Thanks, Laurent