tun: use netdev_alloc_frag() in tun_napi_alloc_frags()
authorEric Dumazet <edumazet@google.com>
Sun, 18 Nov 2018 15:37:33 +0000 (07:37 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 19 Nov 2018 03:01:11 +0000 (19:01 -0800)
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>
drivers/net/tun.c

index 36163a1..1e9da69 100644 (file)
@@ -1478,23 +1478,22 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile,
        skb->truesize += skb->data_len;
 
        for (i = 1; i < it->nr_segs; i++) {
-               struct page_frag *pfrag = &current->task_frag;
                size_t fragsz = it->iov[i].iov_len;
+               struct page *page;
+               void *frag;
 
                if (fragsz == 0 || fragsz > PAGE_SIZE) {
                        err = -EINVAL;
                        goto free;
                }
-
-               if (!skb_page_frag_refill(fragsz, pfrag, GFP_KERNEL)) {
+               frag = netdev_alloc_frag(fragsz);
+               if (!frag) {
                        err = -ENOMEM;
                        goto free;
                }
-
-               skb_fill_page_desc(skb, i - 1, pfrag->page,
-                                  pfrag->offset, fragsz);
-               page_ref_inc(pfrag->page);
-               pfrag->offset += fragsz;
+               page = virt_to_head_page(frag);
+               skb_fill_page_desc(skb, i - 1, page,
+                                  frag - page_address(page), fragsz);
        }
 
        return skb;