in vringh.c [431:478]
static inline int __vringh_complete(struct vringh *vrh,
const struct vring_used_elem *used,
unsigned int num_used,
int (*putu16)(const struct vringh *vrh,
__virtio16 *p, u16 val),
int (*putused)(const struct vringh *vrh,
struct vring_used_elem *dst,
const struct vring_used_elem
*src, unsigned num))
{
struct vring_used *used_ring;
int err;
u16 used_idx, off;
used_ring = vrh->vring.used;
used_idx = vrh->last_used_idx + vrh->completed;
off = used_idx % vrh->vring.num;
/* Compiler knows num_used == 1 sometimes, hence extra check */
if (num_used > 1 && unlikely(off + num_used >= vrh->vring.num)) {
u16 part = vrh->vring.num - off;
err = putused(vrh, &used_ring->ring[off], used, part);
if (!err)
err = putused(vrh, &used_ring->ring[0], used + part,
num_used - part);
} else
err = putused(vrh, &used_ring->ring[off], used, num_used);
if (err) {
vringh_bad("Failed to write %u used entries %u at %p",
num_used, off, &used_ring->ring[off]);
return err;
}
/* Make sure buffer is written before we update index. */
virtio_wmb(vrh->weak_barriers);
err = putu16(vrh, &vrh->vring.used->idx, used_idx + num_used);
if (err) {
vringh_bad("Failed to update used index at %p",
&vrh->vring.used->idx);
return err;
}
vrh->completed += num_used;
return 0;
}