Excerpts from Dustin Kirkland's message of Thu Oct 29 03:22:43 +0800 2009: > We're tracking this issue at: > * https://bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/458521 > > I'll gladly review and test patches, or take pointers on where I might > look to solve this issue. Try the following patch against the stable-0.11 branch. I've only just started learning about the virtio-net code but hopefully this patch points you to the right direction. Note that this patch just drops the packets that would have caused virtio-net to call exit(1). >From d48af0377f359983bff67eb9296ba040def401ec Mon Sep 17 00:00:00 2001 From: Scott Tsai <scottt.tw@xxxxxxxxx> Date: Thu, 29 Oct 2009 10:56:12 +0800 Subject: [PATCH] virtio-net: drop large packets when no mergable_rx_bufs see: https://bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/458521 --- hw/virtio-net.c | 8 +++++++- hw/virtio.c | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index ce8e6cb..2e6725b 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -502,6 +502,8 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) return 0; } +int buffer_fits_in_virtqueue_top(VirtQueue *vq, int size); + static ssize_t virtio_net_receive2(VLANClientState *vc, const uint8_t *buf, size_t size, int raw) { VirtIONet *n = vc->opaque; @@ -518,6 +520,10 @@ static ssize_t virtio_net_receive2(VLANClientState *vc, const uint8_t *buf, size hdr_len = n->mergeable_rx_bufs ? sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr); + /* drop packet instead of truncating it */ + if (!n->mergeable_rx_bufs && !buffer_fits_in_virtqueue_top(n->rx_vq, hdr_len + size)) + return; + offset = i = 0; while (offset < size) { @@ -531,7 +537,7 @@ static ssize_t virtio_net_receive2(VLANClientState *vc, const uint8_t *buf, size virtqueue_pop(n->rx_vq, &elem) == 0) { if (i == 0) return -1; - fprintf(stderr, "virtio-net truncating packet\n"); + fprintf(stderr, "virtio-net truncating packet: mergable_rx_bufs: %d\n", n->mergeable_rx_bufs); exit(1); } diff --git a/hw/virtio.c b/hw/virtio.c index 41e7ca2..d6f5a12 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -356,6 +356,28 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) return 0; } +/* buffer_fits_in_virtqueue_top: returns true if a 'size' byte buffer could fit in the + * input descriptors that virtqueue_pop() would have returned + */ +int buffer_fits_in_virtqueue_top(VirtQueue *vq, int size); + +int buffer_fits_in_virtqueue_top(VirtQueue *vq, int size) +{ + unsigned int i; + int input_iov_len_sum; + + if (!virtqueue_num_heads(vq, vq->last_avail_idx)) + return 0; + + input_iov_len_sum = 0; + i = virtqueue_get_head(vq, vq->last_avail_idx); + do { + if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) + input_iov_len_sum += vring_desc_len(vq, i); + } while ((i = virtqueue_next_desc(vq, i)) != vq->vring.num); + return input_iov_len_sum >= size; +} + int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) { unsigned int i, head, max; -- 1.6.2.5 -- 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