diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2016-02-04 16:26:51 +0200 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2016-02-06 20:39:07 +0200 |
commit | 51b19ebe4320f3dcd93cea71235c1219318ddfd2 (patch) | |
tree | a242566284e7efb7a45e151481b0433a3ffe39b5 /hw/virtio | |
parent | 6aa46d8ff1ee7e9ca0c4a54d75c74108bee22124 (diff) |
virtio: move allocation to virtqueue_pop/vring_pop
The return code of virtqueue_pop/vring_pop is unused except to check for
errors or 0. We can thus easily move allocation inside the functions
and just return a pointer to the VirtQueueElement.
The advantage is that we will be able to allocate only the space that
is needed for the actual size of the s/g list instead of the full
VIRTQUEUE_MAX_SIZE items. Currently VirtQueueElement takes about 48K
of memory, and this kind of allocation puts a lot of stress on malloc.
By cutting the size by two or three orders of magnitude, malloc can
use much more efficient algorithms.
The patch is pretty large, but changes to each device are testable
more or less independently. Splitting it would mostly add churn.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Diffstat (limited to 'hw/virtio')
-rw-r--r-- | hw/virtio/dataplane/vring.c | 18 | ||||
-rw-r--r-- | hw/virtio/virtio-balloon.c | 22 | ||||
-rw-r--r-- | hw/virtio/virtio-rng.c | 10 | ||||
-rw-r--r-- | hw/virtio/virtio.c | 12 |
4 files changed, 40 insertions, 22 deletions
diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c index 1a78df10fa..4fb84bb00a 100644 --- a/hw/virtio/dataplane/vring.c +++ b/hw/virtio/dataplane/vring.c @@ -389,23 +389,26 @@ static void vring_unmap_element(VirtQueueElement *elem) * * Stolen from linux/drivers/vhost/vhost.c. */ -int vring_pop(VirtIODevice *vdev, Vring *vring, - VirtQueueElement *elem) +void *vring_pop(VirtIODevice *vdev, Vring *vring, size_t sz) { struct vring_desc desc; unsigned int i, head, found = 0, num = vring->vr.num; uint16_t avail_idx, last_avail_idx; + VirtQueueElement *elem = NULL; int ret; - /* Initialize elem so it can be safely unmapped */ - elem->in_num = elem->out_num = 0; - /* If there was a fatal error then refuse operation */ if (vring->broken) { ret = -EFAULT; goto out; } + assert(sz >= sizeof(VirtQueueElement)); + elem = g_malloc(sz); + + /* Initialize elem so it can be safely unmapped */ + elem->in_num = elem->out_num = 0; + /* Check it isn't doing very strange things with descriptor numbers. */ last_avail_idx = vring->last_avail_idx; avail_idx = vring_get_avail_idx(vdev, vring); @@ -481,7 +484,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring, virtio_tswap16(vdev, vring->last_avail_idx); } - return head; + return elem; out: assert(ret < 0); @@ -489,7 +492,8 @@ out: vring->broken = true; } vring_unmap_element(elem); - return ret; + g_free(elem); + return NULL; } /* After we've used one of their buffers, we tell them about it. diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index f5f25a95fc..5c3020331c 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -107,8 +107,10 @@ static void balloon_stats_poll_cb(void *opaque) return; } - virtqueue_push(s->svq, &s->stats_vq_elem, s->stats_vq_offset); + virtqueue_push(s->svq, s->stats_vq_elem, s->stats_vq_offset); virtio_notify(vdev, s->svq); + g_free(s->stats_vq_elem); + s->stats_vq_elem = NULL; } static void balloon_stats_get_all(Object *obj, struct Visitor *v, @@ -206,14 +208,18 @@ static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v, static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) { VirtIOBalloon *s = VIRTIO_BALLOON(vdev); - VirtQueueElement elem; + VirtQueueElement *elem; MemoryRegionSection section; - while (virtqueue_pop(vq, &elem)) { + for (;;) { size_t offset = 0; uint32_t pfn; + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + return; + } - while (iov_to_buf(elem.out_sg, elem.out_num, offset, &pfn, 4) == 4) { + while (iov_to_buf(elem->out_sg, elem->out_num, offset, &pfn, 4) == 4) { ram_addr_t pa; ram_addr_t addr; int p = virtio_ldl_p(vdev, &pfn); @@ -236,20 +242,22 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) memory_region_unref(section.mr); } - virtqueue_push(vq, &elem, offset); + virtqueue_push(vq, elem, offset); virtio_notify(vdev, vq); + g_free(elem); } } static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq) { VirtIOBalloon *s = VIRTIO_BALLOON(vdev); - VirtQueueElement *elem = &s->stats_vq_elem; + VirtQueueElement *elem; VirtIOBalloonStat stat; size_t offset = 0; qemu_timeval tv; - if (!virtqueue_pop(vq, elem)) { + s->stats_vq_elem = elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { goto out; } diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index a80fb89069..17da2f8f3d 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -44,7 +44,7 @@ static void chr_read(void *opaque, const void *buf, size_t size) { VirtIORNG *vrng = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(vrng); - VirtQueueElement elem; + VirtQueueElement *elem; size_t len; int offset; @@ -56,15 +56,17 @@ static void chr_read(void *opaque, const void *buf, size_t size) offset = 0; while (offset < size) { - if (!virtqueue_pop(vrng->vq, &elem)) { + elem = virtqueue_pop(vrng->vq, sizeof(VirtQueueElement)); + if (!elem) { break; } - len = iov_from_buf(elem.in_sg, elem.in_num, + len = iov_from_buf(elem->in_sg, elem->in_num, 0, buf + offset, size - offset); offset += len; - virtqueue_push(vrng->vq, &elem, len); + virtqueue_push(vrng->vq, elem, len); trace_virtio_rng_pushed(vrng, len); + g_free(elem); } virtio_notify(vdev, vrng->vq); } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 0603793e34..229a092c83 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -501,16 +501,20 @@ void virtqueue_map(VirtQueueElement *elem) 0); } -int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) +void *virtqueue_pop(VirtQueue *vq, size_t sz) { unsigned int i, head, max; hwaddr desc_pa = vq->vring.desc; VirtIODevice *vdev = vq->vdev; + VirtQueueElement *elem; - if (!virtqueue_num_heads(vq, vq->last_avail_idx)) - return 0; + if (!virtqueue_num_heads(vq, vq->last_avail_idx)) { + return NULL; + } /* When we start there are none of either input nor output. */ + assert(sz >= sizeof(VirtQueueElement)); + elem = g_malloc(sz); elem->out_num = elem->in_num = 0; max = vq->vring.num; @@ -569,7 +573,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) vq->inuse++; trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num); - return elem->in_num + elem->out_num; + return elem; } /* virtio device */ |