This patch splits out ring head fetching logic and leave the
descriptor fetching and translation logic. This makes it is possible
to batch fetching the descriptor indices.

Signed-off-by: Jason Wang <jasow...@redhat.com>
---
 drivers/vhost/vhost.c | 75 +++++++++++++++++++++++++++++++++------------------
 drivers/vhost/vhost.h |  5 ++++
 2 files changed, 54 insertions(+), 26 deletions(-)

diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index d6dbb28..f87ec75 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1984,41 +1984,23 @@ static int get_indirect(struct vhost_virtqueue *vq,
        return 0;
 }
 
-/* This looks in the virtqueue and for the first available buffer, and converts
- * it to an iovec for convenient access.  Since descriptors consist of some
- * number of output then some number of input descriptors, it's actually two
- * iovecs, but we pack them into one and note how many of each there were.
- *
- * This function returns the descriptor number found, or vq->num (which is
- * never a valid descriptor number) if none was found.  A negative code is
- * returned on error. */
-int vhost_get_vq_desc(struct vhost_virtqueue *vq,
-                     struct iovec iov[], unsigned int iov_size,
-                     unsigned int *out_num, unsigned int *in_num,
-                     struct vhost_log *log, unsigned int *log_num)
+static unsigned int vhost_get_vq_head(struct vhost_virtqueue *vq, int *err)
 {
-       struct vring_desc desc;
-       unsigned int i, head, found = 0;
-       u16 last_avail_idx;
-       __virtio16 avail_idx;
-       __virtio16 ring_head;
-       int ret, access;
-
-       /* Check it isn't doing very strange things with descriptor numbers. */
-       last_avail_idx = vq->last_avail_idx;
+       u16 last_avail_idx = vq->last_avail_idx;
+       __virtio16 avail_idx, ring_head;
 
        if (vq->avail_idx == vq->last_avail_idx) {
                if (unlikely(vhost_get_avail(vq, avail_idx, &vq->avail->idx))) {
                        vq_err(vq, "Failed to access avail idx at %p\n",
                                &vq->avail->idx);
-                       return -EFAULT;
+                       goto err;
                }
                vq->avail_idx = vhost16_to_cpu(vq, avail_idx);
 
                if (unlikely((u16)(vq->avail_idx - last_avail_idx) > vq->num)) {
                        vq_err(vq, "Guest moved used index from %u to %u",
                                last_avail_idx, vq->avail_idx);
-                       return -EFAULT;
+                       goto err;
                }
 
                /* If there's nothing new since last we looked, return
@@ -2040,13 +2022,35 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
                vq_err(vq, "Failed to read head: idx %d address %p\n",
                       last_avail_idx,
                       &vq->avail->ring[last_avail_idx % vq->num]);
-               return -EFAULT;
+               goto err;
        }
 
-       head = vhost16_to_cpu(vq, ring_head);
+       return vhost16_to_cpu(vq, ring_head);
+err:
+       *err = -EFAULT;
+       return 0;
+}
+
+/* This looks in the virtqueue and for the first available buffer, and converts
+ * it to an iovec for convenient access.  Since descriptors consist of some
+ * number of output then some number of input descriptors, it's actually two
+ * iovecs, but we pack them into one and note how many of each there were.
+ *
+ * This function returns the descriptor number found, or vq->num (which is
+ * never a valid descriptor number) if none was found.  A negative code is
+ * returned on error. */
+int __vhost_get_vq_desc(struct vhost_virtqueue *vq,
+                       struct iovec iov[], unsigned int iov_size,
+                       unsigned int *out_num, unsigned int *in_num,
+                       struct vhost_log *log, unsigned int *log_num,
+                       __virtio16 head)
+{
+       struct vring_desc desc;
+       unsigned int i, found = 0;
+       int ret = 0, access;
 
        /* If their number is silly, that's an error. */
-       if (unlikely(head >= vq->num)) {
+       if (unlikely(head > vq->num)) {
                vq_err(vq, "Guest says index %u > %u is available",
                       head, vq->num);
                return -EINVAL;
@@ -2133,6 +2137,25 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
        BUG_ON(!(vq->used_flags & VRING_USED_F_NO_NOTIFY));
        return head;
 }
+EXPORT_SYMBOL_GPL(__vhost_get_vq_desc);
+
+int vhost_get_vq_desc(struct vhost_virtqueue *vq,
+                     struct iovec iov[], unsigned int iov_size,
+                     unsigned int *out_num, unsigned int *in_num,
+                     struct vhost_log *log, unsigned int *log_num)
+{
+       int ret = 0;
+       unsigned int head = vhost_get_vq_head(vq, &ret);
+
+       if (ret)
+               return ret;
+
+       if (head == vq->num)
+               return head;
+
+       return __vhost_get_vq_desc(vq, iov, iov_size, out_num, in_num,
+                                  log, log_num, head);
+}
 EXPORT_SYMBOL_GPL(vhost_get_vq_desc);
 
 /* Reverse the effect of vhost_get_vq_desc. Useful for error handling. */
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index d59a9cc..39ff897 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -191,6 +191,11 @@ int vhost_get_vq_desc(struct vhost_virtqueue *,
                      struct iovec iov[], unsigned int iov_count,
                      unsigned int *out_num, unsigned int *in_num,
                      struct vhost_log *log, unsigned int *log_num);
+int __vhost_get_vq_desc(struct vhost_virtqueue *vq,
+                       struct iovec iov[], unsigned int iov_count,
+                       unsigned int *out_num, unsigned int *in_num,
+                       struct vhost_log *log, unsigned int *log_num,
+                       __virtio16 ring_head);
 void vhost_discard_vq_desc(struct vhost_virtqueue *, int n);
 
 int vhost_vq_init_access(struct vhost_virtqueue *);
-- 
2.7.4

Reply via email to