kvm tools: Support virtio indirect buffers

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>
This commit is contained in:
Sasha Levin
2011-11-28 19:54:27 +02:00
committed by Will Deacon
parent 2fddfdb536
commit 754c8ce330
3 changed files with 42 additions and 11 deletions
+2 -1
View 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)
+38 -9
View 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;
}
+2 -1
View 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)