Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758464AbcLWOib (ORCPT ); Fri, 23 Dec 2016 09:38:31 -0500 Received: from mx1.redhat.com ([209.132.183.28]:50208 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1760456AbcLWOiZ (ORCPT ); Fri, 23 Dec 2016 09:38:25 -0500 From: Jason Wang To: mst@redhat.com, virtualization@lists.linux-foundation.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Cc: john.r.fastabend@intel.com, Jason Wang Subject: [PATCH net 3/9] virtio-net: fix page miscount during XDP linearizing Date: Fri, 23 Dec 2016 22:37:26 +0800 Message-Id: <1482503852-12438-4-git-send-email-jasowang@redhat.com> In-Reply-To: <1482503852-12438-1-git-send-email-jasowang@redhat.com> References: <1482503852-12438-1-git-send-email-jasowang@redhat.com> X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Fri, 23 Dec 2016 14:37:55 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 2427 Lines: 74 We don't put page during linearizing, the would cause leaking when xmit through XDP_TX or the packet exceeds PAGE_SIZE. Fix them by put page accordingly. Also decrease the number of buffers during linearizing to make sure caller can free buffers correctly when packet exceeds PAGE_SIZE. With this patch, we won't get OOM after linearize huge number of packets. Cc: John Fastabend Signed-off-by: Jason Wang --- drivers/net/virtio_net.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index fe4562d..58ad40e 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -483,7 +483,7 @@ static struct sk_buff *receive_big(struct net_device *dev, * anymore. */ static struct page *xdp_linearize_page(struct receive_queue *rq, - u16 num_buf, + u16 *num_buf, struct page *p, int offset, unsigned int *len) @@ -497,7 +497,7 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, memcpy(page_address(page) + page_off, page_address(p) + offset, *len); page_off += *len; - while (--num_buf) { + while (--*num_buf) { unsigned int buflen; unsigned long ctx; void *buf; @@ -507,19 +507,22 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, if (unlikely(!ctx)) goto err_buf; + buf = mergeable_ctx_to_buf_address(ctx); + p = virt_to_head_page(buf); + off = buf - page_address(p); + /* guard against a misconfigured or uncooperative backend that * is sending packet larger than the MTU. */ - if ((page_off + buflen) > PAGE_SIZE) + if ((page_off + buflen) > PAGE_SIZE) { + put_page(p); goto err_buf; - - buf = mergeable_ctx_to_buf_address(ctx); - p = virt_to_head_page(buf); - off = buf - page_address(p); + } memcpy(page_address(page) + page_off, page_address(p) + off, buflen); page_off += buflen; + put_page(p); } *len = page_off; @@ -555,7 +558,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, /* This happens when rx buffer size is underestimated */ if (unlikely(num_buf > 1)) { /* linearize data for XDP */ - xdp_page = xdp_linearize_page(rq, num_buf, + xdp_page = xdp_linearize_page(rq, &num_buf, page, offset, &len); if (!xdp_page) goto err_xdp; -- 2.7.4