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@xxxxxxxxx> --- tools/kvm/virtio/blk.c | 3 ++- tools/kvm/virtio/core.c | 47 ++++++++++++++++++++++++++++++++++++++--------- tools/kvm/virtio/net.c | 3 ++- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/tools/kvm/virtio/blk.c b/tools/kvm/virtio/blk.c index 8c6f90b..d1a0197 100644 --- a/tools/kvm/virtio/blk.c +++ b/tools/kvm/virtio/blk.c @@ -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) diff --git a/tools/kvm/virtio/core.c b/tools/kvm/virtio/core.c index a6f180e..fe9d588 100644 --- a/tools/kvm/virtio/core.c +++ b/tools/kvm/virtio/core.c @@ -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; } diff --git a/tools/kvm/virtio/net.c b/tools/kvm/virtio/net.c index ce34555..3fb5054 100644 --- a/tools/kvm/virtio/net.c +++ b/tools/kvm/virtio/net.c @@ -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) -- 1.7.8.rc3 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html