From: Jason Wang <jasowang@redhat.com>
To: "Michael S. Tsirkin" <mst@redhat.com>, netdev@vger.kernel.org
Cc: Michael Dalton <mwdalton@google.com>,
linux-kernel@vger.kernel.org,
virtualization@lists.linux-foundation.org,
Eric Dumazet <edumazet@google.com>,
David Miller <davem@davemloft.net>
Subject: Re: [PATCH stable 1/2] virtio_net: fix error handling for mergeable buffers
Date: Thu, 26 Dec 2013 15:28:26 +0800 [thread overview]
Message-ID: <52BBDA9A.3030706@redhat.com> (raw)
In-Reply-To: <1387983339-1172-2-git-send-email-mst@redhat.com>
On 12/25/2013 10:56 PM, Michael S. Tsirkin wrote:
> 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.
>
> Jason Wang noticed that we also leak a page and that we don't decrement
> the rq buf count, so we won't repost buffers (a resource leak).
This issue does not existed in stable tree.
> Fix both issues.
>
> Cc: Rusty Russell <rusty@rustcorp.com.au>
> Cc: Michael Dalton <mwdalton@google.com>
> Cc: Eric Dumazet <edumazet@google.com>
> Cc: Jason Wang <jasowang@redhat.com>
> Cc: Jason Wang <jasowang@redhat.com>
> Cc: David S. Miller <davem@davemloft.net>
>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
>
> (cherry picked from commit 8fc3b9e9a229778e5af3aa453c44f1a3857ba769)
> ---
> drivers/net/virtio_net.c | 66 +++++++++++++++++++++++++++++++++---------------
> 1 file changed, 46 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 9fbdfcd..435076f 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -297,26 +297,33 @@ static struct sk_buff *page_to_skb(struct receive_queue *rq,
> 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)
> @@ -326,7 +333,25 @@ static int receive_mergeable(struct receive_queue *rq, struct sk_buff *skb)
>
> --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)
> @@ -354,17 +379,18 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
> 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);
WARNING: multiple messages have this Message-ID (diff)
From: Jason Wang <jasowang@redhat.com>
To: "Michael S. Tsirkin" <mst@redhat.com>, netdev@vger.kernel.org
Cc: David Miller <davem@davemloft.net>,
Rusty Russell <rusty@rustcorp.com.au>,
Michael Dalton <mwdalton@google.com>,
Eric Dumazet <edumazet@google.com>,
virtualization@lists.linux-foundation.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH stable 1/2] virtio_net: fix error handling for mergeable buffers
Date: Thu, 26 Dec 2013 15:28:26 +0800 [thread overview]
Message-ID: <52BBDA9A.3030706@redhat.com> (raw)
In-Reply-To: <1387983339-1172-2-git-send-email-mst@redhat.com>
On 12/25/2013 10:56 PM, Michael S. Tsirkin wrote:
> 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.
>
> Jason Wang noticed that we also leak a page and that we don't decrement
> the rq buf count, so we won't repost buffers (a resource leak).
This issue does not existed in stable tree.
> Fix both issues.
>
> Cc: Rusty Russell <rusty@rustcorp.com.au>
> Cc: Michael Dalton <mwdalton@google.com>
> Cc: Eric Dumazet <edumazet@google.com>
> Cc: Jason Wang <jasowang@redhat.com>
> Cc: Jason Wang <jasowang@redhat.com>
> Cc: David S. Miller <davem@davemloft.net>
>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
>
> (cherry picked from commit 8fc3b9e9a229778e5af3aa453c44f1a3857ba769)
> ---
> drivers/net/virtio_net.c | 66 +++++++++++++++++++++++++++++++++---------------
> 1 file changed, 46 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 9fbdfcd..435076f 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -297,26 +297,33 @@ static struct sk_buff *page_to_skb(struct receive_queue *rq,
> 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)
> @@ -326,7 +333,25 @@ static int receive_mergeable(struct receive_queue *rq, struct sk_buff *skb)
>
> --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)
> @@ -354,17 +379,18 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
> 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);
next prev parent reply other threads:[~2013-12-26 7:28 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-12-25 14:56 [PATCH stable 0/2] virtio-net: backport error handling bugfix Michael S. Tsirkin
2013-12-25 14:56 ` [PATCH stable 1/2] virtio_net: fix error handling for mergeable buffers Michael S. Tsirkin
2013-12-25 14:56 ` Michael S. Tsirkin
2013-12-25 18:33 ` Michael Dalton
2013-12-25 18:33 ` Michael Dalton
2013-12-25 19:19 ` Michael S. Tsirkin
2013-12-25 19:19 ` Michael S. Tsirkin
2013-12-26 6:35 ` Michael Dalton
2013-12-26 6:35 ` Michael Dalton
2013-12-26 7:28 ` Jason Wang [this message]
2013-12-26 7:28 ` Jason Wang
2013-12-25 14:56 ` [PATCH stable 2/2] virtio-net: make all RX paths handle erors consistently Michael S. Tsirkin
2013-12-25 14:56 ` Michael S. Tsirkin
2013-12-26 7:28 ` Jason Wang
2013-12-26 7:28 ` Jason Wang
2013-12-26 7:31 ` Zhi Yong Wu
2013-12-26 7:31 ` Zhi Yong Wu
2013-12-25 20:13 ` [PATCH stable] virtio_net: don't leak memory or block when too many frags Michael S. Tsirkin
2013-12-25 20:13 ` Michael S. Tsirkin
2013-12-26 6:35 ` Michael Dalton
2013-12-26 6:35 ` Michael Dalton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52BBDA9A.3030706@redhat.com \
--to=jasowang@redhat.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mst@redhat.com \
--cc=mwdalton@google.com \
--cc=netdev@vger.kernel.org \
--cc=virtualization@lists.linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.