Signed-off-by: Eugenio Pérez <eperezma@xxxxxxxxxx> --- hw/virtio/vhost-sw-lm-ring.h | 1 + hw/virtio/vhost-sw-lm-ring.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/hw/virtio/vhost-sw-lm-ring.h b/hw/virtio/vhost-sw-lm-ring.h index 03257d60c1..429a125558 100644 --- a/hw/virtio/vhost-sw-lm-ring.h +++ b/hw/virtio/vhost-sw-lm-ring.h @@ -19,6 +19,7 @@ typedef struct VhostShadowVirtqueue VhostShadowVirtqueue; bool vhost_vring_kick(VhostShadowVirtqueue *vq); int vhost_vring_add(VhostShadowVirtqueue *vq, VirtQueueElement *elem); +VirtQueueElement *vhost_vring_get_buf_rcu(VhostShadowVirtqueue *vq, size_t sz); /* Called within rcu_read_lock(). */ void vhost_vring_set_notification_rcu(VhostShadowVirtqueue *vq, bool enable); diff --git a/hw/virtio/vhost-sw-lm-ring.c b/hw/virtio/vhost-sw-lm-ring.c index 3652889d8e..4fafd1b278 100644 --- a/hw/virtio/vhost-sw-lm-ring.c +++ b/hw/virtio/vhost-sw-lm-ring.c @@ -187,6 +187,35 @@ int vhost_vring_add(VhostShadowVirtqueue *vq, VirtQueueElement *elem) return 0; } +VirtQueueElement *vhost_vring_get_buf_rcu(VhostShadowVirtqueue *vq, size_t sz) +{ + const vring_used_t *used = vq->vring.used; + VirtQueueElement *ret; + vring_used_elem_t used_elem; + uint16_t last_used; + + if (!vhost_vring_poll_rcu(vq)) { + return NULL; + } + + last_used = vq->used_idx & (vq->vring.num - 1); + used_elem.id = virtio_tswap32(vq->vdev, used->ring[last_used].id); + used_elem.len = virtio_tswap32(vq->vdev, used->ring[last_used].len); + + if (unlikely(used_elem.id >= vq->vring.num)) { + virtio_error(vq->vdev, "Device says index %u is available", + used_elem.id); + return NULL; + } + + ret = vq->ring_id_maps[used_elem.id]; + ret->len = used_elem.len; + + vq->used_idx++; + + return ret; +} + void vhost_vring_write_addr(const VhostShadowVirtqueue *vq, struct vhost_vring_addr *addr) { -- 2.18.4