aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorVlad Yasevich <vyasevich@gmail.com>2015-01-31 10:40:17 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-02 22:28:04 -0500
commit03485f2adcde0c2d4e9228b659be78e872486bbb (patch)
treec5aa3c419911b8ea7a78f8e5e66d3d04147875a0 /net/ipv6
parentd39d938c8228a4c5860138a53cf2b9ae4c4baec2 (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.c24
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;
1308back_from_confirm: 1309back_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
1357release_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);
1358out: 1374out:
1359 dst_release(dst); 1375 dst_release(dst);
1360 fl6_sock_release(flowlabel); 1376 fl6_sock_release(flowlabel);