diff options
author | Eric Dumazet <edumazet@google.com> | 2018-11-18 10:37:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-11-18 22:01:11 -0500 |
commit | aa6daacaa113cda96760c8d3157bae937908f6e3 (patch) | |
tree | d685971689336d09beeedd37662ca44f0f038a86 | |
parent | 05b0e1d6980f9d76a6e5c6184854141bc26c2b13 (diff) |
tun: use netdev_alloc_frag() in tun_napi_alloc_frags()
In order to cook skbs in the same way than Ethernet drivers,
it is probably better to not use GFP_KERNEL, but rather
use the GFP_ATOMIC and PFMEMALLOC mechanisms provided by
netdev_alloc_frag().
This would allow to use tun driver even in memory stress
situations, especially if swap is used over this tun channel.
Fixes: 90e33d459407 ("tun: enable napi_gro_frags() for TUN/TAP driver")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Petar Penkov <peterpenkov96@gmail.com>
Cc: Mahesh Bandewar <maheshb@google.com>
Cc: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/tun.c | 15 |
1 files changed, 7 insertions, 8 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 36163a147d39..1e9da697081d 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -1478,23 +1478,22 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile, | |||
1478 | skb->truesize += skb->data_len; | 1478 | skb->truesize += skb->data_len; |
1479 | 1479 | ||
1480 | for (i = 1; i < it->nr_segs; i++) { | 1480 | for (i = 1; i < it->nr_segs; i++) { |
1481 | struct page_frag *pfrag = ¤t->task_frag; | ||
1482 | size_t fragsz = it->iov[i].iov_len; | 1481 | size_t fragsz = it->iov[i].iov_len; |
1482 | struct page *page; | ||
1483 | void *frag; | ||
1483 | 1484 | ||
1484 | if (fragsz == 0 || fragsz > PAGE_SIZE) { | 1485 | if (fragsz == 0 || fragsz > PAGE_SIZE) { |
1485 | err = -EINVAL; | 1486 | err = -EINVAL; |
1486 | goto free; | 1487 | goto free; |
1487 | } | 1488 | } |
1488 | 1489 | frag = netdev_alloc_frag(fragsz); | |
1489 | if (!skb_page_frag_refill(fragsz, pfrag, GFP_KERNEL)) { | 1490 | if (!frag) { |
1490 | err = -ENOMEM; | 1491 | err = -ENOMEM; |
1491 | goto free; | 1492 | goto free; |
1492 | } | 1493 | } |
1493 | 1494 | page = virt_to_head_page(frag); | |
1494 | skb_fill_page_desc(skb, i - 1, pfrag->page, | 1495 | skb_fill_page_desc(skb, i - 1, page, |
1495 | pfrag->offset, fragsz); | 1496 | frag - page_address(page), fragsz); |
1496 | page_ref_inc(pfrag->page); | ||
1497 | pfrag->offset += fragsz; | ||
1498 | } | 1497 | } |
1499 | 1498 | ||
1500 | return skb; | 1499 | return skb; |