]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm tools: Support virtio indirect buffers
authorSasha Levin <levinsasha928@gmail.com>
Mon, 28 Nov 2011 17:54:27 +0000 (19:54 +0200)
committerPekka Enberg <penberg@kernel.org>
Mon, 28 Nov 2011 20:50:55 +0000 (22:50 +0200)
Indirect buffers are ring descriptors which point to more (even more)
descriptors.

This can be used to increase the effective ring capacity, which helps the
guest to batch large requests - very useful for blk devices.

This patch also enables indirect buffers for virtio-net and virtio-blk.

The patch is based on the lguest's code which does the same.

Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
tools/kvm/virtio/blk.c
tools/kvm/virtio/core.c
tools/kvm/virtio/net.c

index 8c6f90b88f5c72e64011046fd4fa3764597e6c74..d1a0197d1346ad7bf0c18e6718bbad392a21350d 100644 (file)
@@ -148,7 +148,8 @@ static u32 get_host_features(struct kvm *kvm, void *dev)
 {
        return  1UL << VIRTIO_BLK_F_SEG_MAX
                | 1UL << VIRTIO_BLK_F_FLUSH
-               | 1UL << VIRTIO_RING_F_EVENT_IDX;
+               | 1UL << VIRTIO_RING_F_EVENT_IDX
+               | 1UL << VIRTIO_RING_F_INDIRECT_DESC;
 }
 
 static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
index a6f180ed0a265532c3e9951308f5135210ff4aff..fe9d588554395aaeb2e7541259eda90df5176848 100644 (file)
@@ -33,27 +33,56 @@ struct vring_used_elem *virt_queue__set_used_elem(struct virt_queue *queue, u32
        return used_elem;
 }
 
+/*
+ * Each buffer in the virtqueues is actually a chain of descriptors.  This
+ * function returns the next descriptor in the chain, or vq->vring.num if we're
+ * at the end.
+ */
+static unsigned next_desc(struct vring_desc *desc,
+                         unsigned int i, unsigned int max)
+{
+       unsigned int next;
+
+       /* If this descriptor says it doesn't chain, we're done. */
+       if (!(desc[i].flags & VRING_DESC_F_NEXT))
+               return max;
+
+       /* Check they're not leading us off end of descriptors. */
+       next = desc[i].next;
+       /* Make sure compiler knows to grab that: we don't want it changing! */
+       wmb();
+
+       return next;
+}
+
 u16 virt_queue__get_head_iov(struct virt_queue *vq, struct iovec iov[], u16 *out, u16 *in, u16 head, struct kvm *kvm)
 {
        struct vring_desc *desc;
        u16 idx;
+       u16 max;
 
        idx = head;
        *out = *in = 0;
+       max = vq->vring.num;
+       desc = vq->vring.desc;
+
+       if (desc[idx].flags & VRING_DESC_F_INDIRECT) {
+
+               max = desc[idx].len / sizeof(struct vring_desc);
+               desc = guest_flat_to_host(kvm, desc[idx].addr);
+               idx = 0;
+       }
 
        do {
-               desc                     = virt_queue__get_desc(vq, idx);
-               iov[*out + *in].iov_base = guest_flat_to_host(kvm, desc->addr);
-               iov[*out + *in].iov_len  = desc->len;
-               if (desc->flags & VRING_DESC_F_WRITE)
+               /* Grab the first descriptor, and check it's OK. */
+               iov[*out + *in].iov_len = desc[idx].len;
+               iov[*out + *in].iov_base = guest_flat_to_host(kvm, desc[idx].addr);
+               /* If this is an input descriptor, increment that count. */
+               if (desc[idx].flags & VRING_DESC_F_WRITE)
                        (*in)++;
                else
                        (*out)++;
-               if (desc->flags & VRING_DESC_F_NEXT)
-                       idx = desc->next;
-               else
-                       break;
-       } while (1);
+       } while ((idx = next_desc(desc, idx, max)) != max);
 
        return head;
 }
index ce34555e8d5493a384faecac8085e97a80bb44e2..3fb50541ee45575d4721f0a4196a9fcd39852ede 100644 (file)
@@ -318,7 +318,8 @@ static u32 get_host_features(struct kvm *kvm, void *dev)
                | 1UL << VIRTIO_NET_F_GUEST_UFO
                | 1UL << VIRTIO_NET_F_GUEST_TSO4
                | 1UL << VIRTIO_NET_F_GUEST_TSO6
-               | 1UL << VIRTIO_RING_F_EVENT_IDX;
+               | 1UL << VIRTIO_RING_F_EVENT_IDX
+               | 1UL << VIRTIO_RING_F_INDIRECT_DESC;
 }
 
 static void set_guest_features(struct kvm *kvm, void *dev, u32 features)