diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 23 |
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 | ||
1548 | error_efault: | 1568 | error_efault: |
1549 | err = -EFAULT; | 1569 | err = -EFAULT; |
1550 | error: | 1570 | error: |
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); |