diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 16 |
1 files changed, 6 insertions, 10 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 81e6cc951e7f..b52258c327d2 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -1489,27 +1489,23 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile, | |||
1489 | skb->truesize += skb->data_len; | 1489 | skb->truesize += skb->data_len; |
1490 | 1490 | ||
1491 | for (i = 1; i < it->nr_segs; i++) { | 1491 | for (i = 1; i < it->nr_segs; i++) { |
1492 | struct page_frag *pfrag = ¤t->task_frag; | ||
1492 | size_t fragsz = it->iov[i].iov_len; | 1493 | size_t fragsz = it->iov[i].iov_len; |
1493 | unsigned long offset; | ||
1494 | struct page *page; | ||
1495 | void *data; | ||
1496 | 1494 | ||
1497 | if (fragsz == 0 || fragsz > PAGE_SIZE) { | 1495 | if (fragsz == 0 || fragsz > PAGE_SIZE) { |
1498 | err = -EINVAL; | 1496 | err = -EINVAL; |
1499 | goto free; | 1497 | goto free; |
1500 | } | 1498 | } |
1501 | 1499 | ||
1502 | local_bh_disable(); | 1500 | if (!skb_page_frag_refill(fragsz, pfrag, GFP_KERNEL)) { |
1503 | data = napi_alloc_frag(fragsz); | ||
1504 | local_bh_enable(); | ||
1505 | if (!data) { | ||
1506 | err = -ENOMEM; | 1501 | err = -ENOMEM; |
1507 | goto free; | 1502 | goto free; |
1508 | } | 1503 | } |
1509 | 1504 | ||
1510 | page = virt_to_head_page(data); | 1505 | skb_fill_page_desc(skb, i - 1, pfrag->page, |
1511 | offset = data - page_address(page); | 1506 | pfrag->offset, fragsz); |
1512 | skb_fill_page_desc(skb, i - 1, page, offset, fragsz); | 1507 | page_ref_inc(pfrag->page); |
1508 | pfrag->offset += fragsz; | ||
1513 | } | 1509 | } |
1514 | 1510 | ||
1515 | return skb; | 1511 | return skb; |