diff options
| author | Vlad Yasevich <vyasevich@gmail.com> | 2015-01-31 10:40:17 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-02-02 22:28:04 -0500 |
| commit | 03485f2adcde0c2d4e9228b659be78e872486bbb (patch) | |
| tree | c5aa3c419911b8ea7a78f8e5e66d3d04147875a0 /net/ipv6 | |
| parent | d39d938c8228a4c5860138a53cf2b9ae4c4baec2 (diff) | |
udpv6: Add lockless sendmsg() support
This commit adds the same functionaliy to IPv6 that
commit 903ab86d195cca295379699299c5fc10beba31c7
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date: Tue Mar 1 02:36:48 2011 +0000
udp: Add lockless transmit path
added to IPv4.
UDP transmit path can now run without a socket lock,
thus allowing multiple threads to send to a single socket
more efficiently.
This is only used when corking/MSG_MORE is not used.
Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
| -rw-r--r-- | net/ipv6/udp.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 67a3d70f7ac4..d048d46779fc 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -1177,6 +1177,7 @@ do_udp_sendmsg: | |||
| 1177 | if (len > INT_MAX - sizeof(struct udphdr)) | 1177 | if (len > INT_MAX - sizeof(struct udphdr)) |
| 1178 | return -EMSGSIZE; | 1178 | return -EMSGSIZE; |
| 1179 | 1179 | ||
| 1180 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; | ||
| 1180 | if (up->pending) { | 1181 | if (up->pending) { |
| 1181 | /* | 1182 | /* |
| 1182 | * There are pending frames. | 1183 | * There are pending frames. |
| @@ -1307,6 +1308,20 @@ do_udp_sendmsg: | |||
| 1307 | goto do_confirm; | 1308 | goto do_confirm; |
| 1308 | back_from_confirm: | 1309 | back_from_confirm: |
| 1309 | 1310 | ||
| 1311 | /* Lockless fast path for the non-corking case */ | ||
| 1312 | if (!corkreq) { | ||
| 1313 | struct sk_buff *skb; | ||
| 1314 | |||
| 1315 | skb = ip6_make_skb(sk, getfrag, msg, ulen, | ||
| 1316 | sizeof(struct udphdr), hlimit, tclass, opt, | ||
| 1317 | &fl6, (struct rt6_info *)dst, | ||
| 1318 | msg->msg_flags, dontfrag); | ||
| 1319 | err = PTR_ERR(skb); | ||
| 1320 | if (!IS_ERR_OR_NULL(skb)) | ||
| 1321 | err = udp_v6_send_skb(skb, &fl6); | ||
| 1322 | goto release_dst; | ||
| 1323 | } | ||
| 1324 | |||
| 1310 | lock_sock(sk); | 1325 | lock_sock(sk); |
| 1311 | if (unlikely(up->pending)) { | 1326 | if (unlikely(up->pending)) { |
| 1312 | /* The socket is already corked while preparing it. */ | 1327 | /* The socket is already corked while preparing it. */ |
| @@ -1324,7 +1339,6 @@ do_append_data: | |||
| 1324 | if (dontfrag < 0) | 1339 | if (dontfrag < 0) |
| 1325 | dontfrag = np->dontfrag; | 1340 | dontfrag = np->dontfrag; |
| 1326 | up->len += ulen; | 1341 | up->len += ulen; |
| 1327 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; | ||
| 1328 | err = ip6_append_data(sk, getfrag, msg, ulen, | 1342 | err = ip6_append_data(sk, getfrag, msg, ulen, |
| 1329 | sizeof(struct udphdr), hlimit, tclass, opt, &fl6, | 1343 | sizeof(struct udphdr), hlimit, tclass, opt, &fl6, |
| 1330 | (struct rt6_info *)dst, | 1344 | (struct rt6_info *)dst, |
| @@ -1336,6 +1350,11 @@ do_append_data: | |||
| 1336 | else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) | 1350 | else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) |
| 1337 | up->pending = 0; | 1351 | up->pending = 0; |
| 1338 | 1352 | ||
| 1353 | if (err > 0) | ||
| 1354 | err = np->recverr ? net_xmit_errno(err) : 0; | ||
| 1355 | release_sock(sk); | ||
| 1356 | |||
| 1357 | release_dst: | ||
| 1339 | if (dst) { | 1358 | if (dst) { |
| 1340 | if (connected) { | 1359 | if (connected) { |
| 1341 | ip6_dst_store(sk, dst, | 1360 | ip6_dst_store(sk, dst, |
| @@ -1352,9 +1371,6 @@ do_append_data: | |||
| 1352 | dst = NULL; | 1371 | dst = NULL; |
| 1353 | } | 1372 | } |
| 1354 | 1373 | ||
| 1355 | if (err > 0) | ||
| 1356 | err = np->recverr ? net_xmit_errno(err) : 0; | ||
| 1357 | release_sock(sk); | ||
| 1358 | out: | 1374 | out: |
| 1359 | dst_release(dst); | 1375 | dst_release(dst); |
| 1360 | fl6_sock_release(flowlabel); | 1376 | fl6_sock_release(flowlabel); |
