aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 827a3f5ff3bb..7df04d20a91f 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1245,6 +1245,7 @@ static int __ip6_append_data(struct sock *sk,
1245{ 1245{
1246 struct sk_buff *skb, *skb_prev = NULL; 1246 struct sk_buff *skb, *skb_prev = NULL;
1247 unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu; 1247 unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu;
1248 struct ubuf_info *uarg = NULL;
1248 int exthdrlen = 0; 1249 int exthdrlen = 0;
1249 int dst_exthdrlen = 0; 1250 int dst_exthdrlen = 0;
1250 int hh_len; 1251 int hh_len;
@@ -1322,6 +1323,19 @@ emsgsize:
1322 rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM)) 1323 rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
1323 csummode = CHECKSUM_PARTIAL; 1324 csummode = CHECKSUM_PARTIAL;
1324 1325
1326 if (flags & MSG_ZEROCOPY && length && sock_flag(sk, SOCK_ZEROCOPY)) {
1327 uarg = sock_zerocopy_realloc(sk, length, skb_zcopy(skb));
1328 if (!uarg)
1329 return -ENOBUFS;
1330 if (rt->dst.dev->features & NETIF_F_SG &&
1331 csummode == CHECKSUM_PARTIAL) {
1332 paged = true;
1333 } else {
1334 uarg->zerocopy = 0;
1335 skb_zcopy_set(skb, uarg);
1336 }
1337 }
1338
1325 /* 1339 /*
1326 * Let's try using as much space as possible. 1340 * Let's try using as much space as possible.
1327 * Use MTU if total length of the message fits into the MTU. 1341 * Use MTU if total length of the message fits into the MTU.
@@ -1445,6 +1459,7 @@ alloc_new_skb:
1445 cork->tx_flags = 0; 1459 cork->tx_flags = 0;
1446 skb_shinfo(skb)->tskey = tskey; 1460 skb_shinfo(skb)->tskey = tskey;
1447 tskey = 0; 1461 tskey = 0;
1462 skb_zcopy_set(skb, uarg);
1448 1463
1449 /* 1464 /*
1450 * Find where to start putting bytes 1465 * Find where to start putting bytes
@@ -1506,7 +1521,7 @@ alloc_new_skb:
1506 err = -EFAULT; 1521 err = -EFAULT;
1507 goto error; 1522 goto error;
1508 } 1523 }
1509 } else { 1524 } else if (!uarg || !uarg->zerocopy) {
1510 int i = skb_shinfo(skb)->nr_frags; 1525 int i = skb_shinfo(skb)->nr_frags;
1511 1526
1512 err = -ENOMEM; 1527 err = -ENOMEM;
@@ -1536,6 +1551,10 @@ alloc_new_skb:
1536 skb->data_len += copy; 1551 skb->data_len += copy;
1537 skb->truesize += copy; 1552 skb->truesize += copy;
1538 wmem_alloc_delta += copy; 1553 wmem_alloc_delta += copy;
1554 } else {
1555 err = skb_zerocopy_iter_dgram(skb, from, copy);
1556 if (err < 0)
1557 goto error;
1539 } 1558 }
1540 offset += copy; 1559 offset += copy;
1541 length -= copy; 1560 length -= copy;
@@ -1543,11 +1562,13 @@ alloc_new_skb:
1543 1562
1544 if (wmem_alloc_delta) 1563 if (wmem_alloc_delta)
1545 refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc); 1564 refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);
1565 sock_zerocopy_put(uarg);
1546 return 0; 1566 return 0;
1547 1567
1548error_efault: 1568error_efault:
1549 err = -EFAULT; 1569 err = -EFAULT;
1550error: 1570error:
1571 sock_zerocopy_put_abort(uarg);
1551 cork->length -= length; 1572 cork->length -= length;
1552 IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); 1573 IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1553 refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc); 1574 refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc);