Skip to content

Commit

Permalink
virtio-net: fix page miscount during XDP linearizing
Browse files Browse the repository at this point in the history
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 <john.r.fastabend@intel.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Acked-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jason Wang authored and David S. Miller committed Dec 23, 2016
1 parent 275be06 commit 56a86f8
Showing 1 changed file with 11 additions and 8 deletions.
19 changes: 11 additions & 8 deletions drivers/net/virtio_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 56a86f8

Please sign in to comment.