This is a note to let you know that I've just added the patch titled

    virtio_net: fix error handling for mergeable buffers

to the 3.10-stable tree which can be found at:
    
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     virtio_net-fix-error-handling-for-mergeable-buffers.patch
and it can be found in the queue-3.10 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <[email protected]> know about it.


>From foo@baz Mon Jan 13 09:39:01 PST 2014
From: "Michael S. Tsirkin" <[email protected]>
Date: Thu, 26 Dec 2013 15:32:47 +0200
Subject: virtio_net: fix error handling for mergeable buffers

From: "Michael S. Tsirkin" <[email protected]>

Eric Dumazet noticed that if we encounter an error
when processing a mergeable buffer, we don't
dequeue all of the buffers from this packet,
the result is almost sure to be loss of networking.

Fix this issue.

Cc: Rusty Russell <[email protected]>
Cc: Michael Dalton <[email protected]>
Acked-by: Michael Dalton <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Jason Wang <[email protected]>
Cc: David S. Miller <[email protected]>
Signed-off-by: Michael S. Tsirkin <[email protected]>
(cherry picked from commit 8fc3b9e9a229778e5af3aa453c44f1a3857ba769)
Acked-by: Jason Wang <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
 drivers/net/virtio_net.c |   66 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 46 insertions(+), 20 deletions(-)

--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -294,26 +294,33 @@ static struct sk_buff *page_to_skb(struc
        return skb;
 }
 
-static int receive_mergeable(struct receive_queue *rq, struct sk_buff *skb)
+static struct sk_buff *receive_mergeable(struct net_device *dev,
+                                        struct receive_queue *rq,
+                                        void *buf,
+                                        unsigned int len)
 {
-       struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
-       struct page *page;
-       int num_buf, i, len;
+       struct skb_vnet_hdr *hdr = page_address(buf);
+       int num_buf = hdr->mhdr.num_buffers;
+       struct page *page = buf;
+       struct sk_buff *skb = page_to_skb(rq, page, len);
+       int i;
+
+       if (unlikely(!skb))
+               goto err_skb;
 
-       num_buf = hdr->mhdr.num_buffers;
        while (--num_buf) {
                i = skb_shinfo(skb)->nr_frags;
                if (i >= MAX_SKB_FRAGS) {
                        pr_debug("%s: packet too long\n", skb->dev->name);
                        skb->dev->stats.rx_length_errors++;
-                       return -EINVAL;
+                       return NULL;
                }
                page = virtqueue_get_buf(rq->vq, &len);
                if (!page) {
-                       pr_debug("%s: rx error: %d buffers missing\n",
-                                skb->dev->name, hdr->mhdr.num_buffers);
-                       skb->dev->stats.rx_length_errors++;
-                       return -EINVAL;
+                       pr_debug("%s: rx error: %d buffers %d missing\n",
+                                dev->name, hdr->mhdr.num_buffers, num_buf);
+                       dev->stats.rx_length_errors++;
+                       goto err_buf;
                }
 
                if (len > PAGE_SIZE)
@@ -323,7 +330,25 @@ static int receive_mergeable(struct rece
 
                --rq->num;
        }
-       return 0;
+       return skb;
+err_skb:
+       give_pages(rq, page);
+       while (--num_buf) {
+               buf = virtqueue_get_buf(rq->vq, &len);
+               if (unlikely(!buf)) {
+                       pr_debug("%s: rx error: %d buffers missing\n",
+                                dev->name, num_buf);
+                       dev->stats.rx_length_errors++;
+                       break;
+               }
+               page = buf;
+               give_pages(rq, page);
+               --rq->num;
+       }
+err_buf:
+       dev->stats.rx_dropped++;
+       dev_kfree_skb(skb);
+       return NULL;
 }
 
 static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
@@ -351,17 +376,18 @@ static void receive_buf(struct receive_q
                skb_trim(skb, len);
        } else {
                page = buf;
-               skb = page_to_skb(rq, page, len);
-               if (unlikely(!skb)) {
-                       dev->stats.rx_dropped++;
-                       give_pages(rq, page);
-                       return;
-               }
-               if (vi->mergeable_rx_bufs)
-                       if (receive_mergeable(rq, skb)) {
-                               dev_kfree_skb(skb);
+               if (vi->mergeable_rx_bufs) {
+                       skb = receive_mergeable(dev, rq, page, len);
+                       if (unlikely(!skb))
+                               return;
+               } else {
+                       skb = page_to_skb(rq, page, len);
+                       if (unlikely(!skb)) {
+                               dev->stats.rx_dropped++;
+                               give_pages(rq, page);
                                return;
                        }
+               }
        }
 
        hdr = skb_vnet_hdr(skb);


Patches currently in stable-queue which might be from [email protected] are

queue-3.10/macvtap-signal-truncated-packets.patch
queue-3.10/virtio-net-make-all-rx-paths-handle-errors-consistently.patch
queue-3.10/virtio_net-fix-error-handling-for-mergeable-buffers.patch
queue-3.10/macvtap-do-not-double-count-received-packets.patch
queue-3.10/virtio-net-fix-refill-races-during-restore.patch
queue-3.10/virtio_net-don-t-leak-memory-or-block-when-too-many-frags.patch
queue-3.10/virtio-delete-napi-structures-from-netdev-before-releasing-memory.patch
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to