Patchwork [1/2] vring: create a common function to parse descriptors

login
register
mail settings
Submitter Paolo Bonzini
Date May 10, 2013, 12:27 p.m.
Message ID <1368188849-5647-2-git-send-email-pbonzini@redhat.com>
Download mbox | patch
Permalink /patch/242975/
State New
Headers show

Comments

Paolo Bonzini - May 10, 2013, 12:27 p.m.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/virtio/dataplane/vring.c | 113 ++++++++++++++++++++------------------------
 1 file changed, 51 insertions(+), 62 deletions(-)

Patch

diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c
index e0d6e83..bd1ff25 100644
--- a/hw/virtio/dataplane/vring.c
+++ b/hw/virtio/dataplane/vring.c
@@ -107,6 +107,47 @@  bool vring_should_notify(VirtIODevice *vdev, Vring *vring)
     return vring_need_event(vring_used_event(&vring->vr), new, old);
 }
 
+
+static int get_desc(Vring *vring,
+                    struct iovec iov[], struct iovec *iov_end,
+                    unsigned int *out_num, unsigned int *in_num,
+                    struct vring_desc *desc)
+{
+    unsigned *num;
+
+    if (desc->flags & VRING_DESC_F_WRITE) {
+        num = in_num;
+    } else {
+        num = out_num;
+
+        /* If it's an output descriptor, they're all supposed
+         * to come before any input descriptors. */
+        if (unlikely(*in_num)) {
+            error_report("Descriptor has out after in");
+            return -EFAULT;
+        }
+    }
+
+    /* Stop for now if there are not enough iovecs available. */
+    iov += *in_num + *out_num;
+    if (iov >= iov_end) {
+        return -ENOBUFS;
+    }
+
+    /* TODO handle non-contiguous memory across region boundaries */
+    iov->iov_base = hostmem_lookup(&vring->hostmem, desc->addr, desc->len,
+                                   desc->flags & VRING_DESC_F_WRITE);
+    if (!iov->iov_base) {
+        error_report("Failed to map descriptor addr %#" PRIx64 " len %u",
+                     (uint64_t)desc->addr, desc->len);
+        return -EFAULT;
+    }
+
+    iov->iov_len = desc->len;
+    *num += 1;
+    return 0;
+}
+
 /* This is stolen from linux/drivers/vhost/vhost.c. */
 static int get_indirect(Vring *vring,
                         struct iovec iov[], struct iovec *iov_end,
@@ -115,6 +156,7 @@  static int get_indirect(Vring *vring,
 {
     struct vring_desc desc;
     unsigned int i = 0, count, found = 0;
+    int ret;
 
     /* Sanity check */
     if (unlikely(indirect->len % sizeof(desc))) {
@@ -167,36 +209,10 @@  static int get_indirect(Vring *vring,
             return -EFAULT;
         }
 
-        /* Stop for now if there are not enough iovecs available. */
-        if (iov >= iov_end) {
-            return -ENOBUFS;
-        }
-
-        iov->iov_base = hostmem_lookup(&vring->hostmem, desc.addr, desc.len,
-                                       desc.flags & VRING_DESC_F_WRITE);
-        if (!iov->iov_base) {
-            error_report("Failed to map indirect descriptor"
-                         "addr %#" PRIx64 " len %u",
-                         (uint64_t)desc.addr, desc.len);
-            vring->broken = true;
-            return -EFAULT;
-        }
-        iov->iov_len = desc.len;
-        iov++;
-
-        /* If this is an input descriptor, increment that count. */
-        if (desc.flags & VRING_DESC_F_WRITE) {
-            *in_num += 1;
-        } else {
-            /* If it's an output descriptor, they're all supposed
-             * to come before any input descriptors. */
-            if (unlikely(*in_num)) {
-                error_report("Indirect descriptor "
-                             "has out after in: idx %u", i);
-                vring->broken = true;
-                return -EFAULT;
-            }
-            *out_num += 1;
+        ret = get_desc(vring, iov, iov_end, out_num, in_num, &desc);
+        if (ret < 0) {
+            vring->broken |= (ret == -EFAULT);
+            return ret;
         }
         i = desc.next;
     } while (desc.flags & VRING_DESC_F_NEXT);
@@ -221,6 +237,7 @@  int vring_pop(VirtIODevice *vdev, Vring *vring,
     struct vring_desc desc;
     unsigned int i, head, found = 0, num = vring->vr.num;
     uint16_t avail_idx, last_avail_idx;
+    int ret;
 
     /* If there was a fatal error then refuse operation */
     if (vring->broken) {
@@ -291,40 +308,12 @@  int vring_pop(VirtIODevice *vdev, Vring *vring,
             continue;
         }
 
-        /* If there are not enough iovecs left, stop for now.  The caller
-         * should check if there are more descs available once they have dealt
-         * with the current set.
-         */
-        if (iov >= iov_end) {
-            return -ENOBUFS;
+        ret = get_desc(vring, iov, iov_end, out_num, in_num, &desc);
+        if (ret < 0) {
+            vring->broken |= (ret == -EFAULT);
+            return ret;
         }
 
-        /* TODO handle non-contiguous memory across region boundaries */
-        iov->iov_base = hostmem_lookup(&vring->hostmem, desc.addr, desc.len,
-                                       desc.flags & VRING_DESC_F_WRITE);
-        if (!iov->iov_base) {
-            error_report("Failed to map vring desc addr %#" PRIx64 " len %u",
-                         (uint64_t)desc.addr, desc.len);
-            vring->broken = true;
-            return -EFAULT;
-        }
-        iov->iov_len  = desc.len;
-        iov++;
-
-        if (desc.flags & VRING_DESC_F_WRITE) {
-            /* If this is an input descriptor,
-             * increment that count. */
-            *in_num += 1;
-        } else {
-            /* If it's an output descriptor, they're all supposed
-             * to come before any input descriptors. */
-            if (unlikely(*in_num)) {
-                error_report("Descriptor has out after in: idx %d", i);
-                vring->broken = true;
-                return -EFAULT;
-            }
-            *out_num += 1;
-        }
         i = desc.next;
     } while (desc.flags & VRING_DESC_F_NEXT);