Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv6: lockless IPV6_RECVERR implemetation

np->recverr is moved to inet->inet_flags to fix data-races.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
3fa29971 1086ca7c

+25 -32
+1 -2
include/linux/ipv6.h
··· 243 243 } rxopt; 244 244 245 245 /* sockopt flags */ 246 - __u16 recverr:1, 247 - sndflow:1, 246 + __u16 sndflow:1, 248 247 repflow:1, 249 248 pmtudisc:3, 250 249 padding:1, /* 1 bit hole */
+1
include/net/inet_sock.h
··· 274 274 INET_FLAGS_AUTOFLOWLABEL_SET = 23, 275 275 INET_FLAGS_AUTOFLOWLABEL = 24, 276 276 INET_FLAGS_DONTFRAG = 25, 277 + INET_FLAGS_RECVERR6 = 26, 277 278 }; 278 279 279 280 /* cmsg flags for inet */
+1 -3
include/net/ipv6.h
··· 1303 1303 1304 1304 static inline void ip6_sock_set_recverr(struct sock *sk) 1305 1305 { 1306 - lock_sock(sk); 1307 - inet6_sk(sk)->recverr = true; 1308 - release_sock(sk); 1306 + inet6_set_bit(RECVERR6, sk); 1309 1307 } 1310 1308 1311 1309 static inline int __ip6_sock_set_addr_preferences(struct sock *sk, int val)
+1 -1
net/dccp/ipv6.c
··· 185 185 goto out; 186 186 } 187 187 188 - if (!sock_owned_by_user(sk) && np->recverr) { 188 + if (!sock_owned_by_user(sk) && inet6_test_bit(RECVERR6, sk)) { 189 189 sk->sk_err = err; 190 190 sk_error_report(sk); 191 191 } else {
+1 -1
net/ipv4/ping.c
··· 581 581 * 4.1.3.3. 582 582 */ 583 583 if ((family == AF_INET && !inet_test_bit(RECVERR, sk)) || 584 - (family == AF_INET6 && !inet6_sk(sk)->recverr)) { 584 + (family == AF_INET6 && !inet6_test_bit(RECVERR6, sk))) { 585 585 if (!harderr || sk->sk_state != TCP_ESTABLISHED) 586 586 goto out; 587 587 } else {
+2 -4
net/ipv6/datagram.c
··· 305 305 void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 306 306 __be16 port, u32 info, u8 *payload) 307 307 { 308 - struct ipv6_pinfo *np = inet6_sk(sk); 309 308 struct icmp6hdr *icmph = icmp6_hdr(skb); 310 309 struct sock_exterr_skb *serr; 311 310 312 - if (!np->recverr) 311 + if (!inet6_test_bit(RECVERR6, sk)) 313 312 return; 314 313 315 314 skb = skb_clone(skb, GFP_ATOMIC); ··· 343 344 344 345 void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info) 345 346 { 346 - const struct ipv6_pinfo *np = inet6_sk(sk); 347 347 struct sock_exterr_skb *serr; 348 348 struct ipv6hdr *iph; 349 349 struct sk_buff *skb; 350 350 351 - if (!np->recverr) 351 + if (!inet6_test_bit(RECVERR6, sk)) 352 352 return; 353 353 354 354 skb = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
+8 -9
net/ipv6/ipv6_sockglue.c
··· 481 481 case IPV6_DONTFRAG: 482 482 inet6_assign_bit(DONTFRAG, sk, valbool); 483 483 return 0; 484 + case IPV6_RECVERR: 485 + if (optlen < sizeof(int)) 486 + return -EINVAL; 487 + inet6_assign_bit(RECVERR6, sk, valbool); 488 + if (!val) 489 + skb_errqueue_purge(&sk->sk_error_queue); 490 + return 0; 484 491 } 485 492 if (needs_rtnl) 486 493 rtnl_lock(); ··· 950 943 np->pmtudisc = val; 951 944 retv = 0; 952 945 break; 953 - case IPV6_RECVERR: 954 - if (optlen < sizeof(int)) 955 - goto e_inval; 956 - np->recverr = valbool; 957 - if (!val) 958 - skb_errqueue_purge(&sk->sk_error_queue); 959 - retv = 0; 960 - break; 961 946 case IPV6_FLOWINFO_SEND: 962 947 if (optlen < sizeof(int)) 963 948 goto e_inval; ··· 1379 1380 break; 1380 1381 1381 1382 case IPV6_RECVERR: 1382 - val = np->recverr; 1383 + val = inet6_test_bit(RECVERR6, sk); 1383 1384 break; 1384 1385 1385 1386 case IPV6_FLOWINFO_SEND:
+5 -5
net/ipv6/raw.c
··· 291 291 struct inet6_skb_parm *opt, 292 292 u8 type, u8 code, int offset, __be32 info) 293 293 { 294 + bool recverr = inet6_test_bit(RECVERR6, sk); 294 295 struct ipv6_pinfo *np = inet6_sk(sk); 295 296 int err; 296 297 int harderr; ··· 301 300 2. Socket is connected (otherwise the error indication 302 301 is useless without recverr and error is hard. 303 302 */ 304 - if (!np->recverr && sk->sk_state != TCP_ESTABLISHED) 303 + if (!recverr && sk->sk_state != TCP_ESTABLISHED) 305 304 return; 306 305 307 306 harderr = icmpv6_err_convert(type, code, &err); ··· 313 312 ip6_sk_redirect(skb, sk); 314 313 return; 315 314 } 316 - if (np->recverr) { 315 + if (recverr) { 317 316 u8 *payload = skb->data; 318 317 if (!inet_test_bit(HDRINCL, sk)) 319 318 payload += offset; 320 319 ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload); 321 320 } 322 321 323 - if (np->recverr || harderr) { 322 + if (recverr || harderr) { 324 323 sk->sk_err = err; 325 324 sk_error_report(sk); 326 325 } ··· 588 587 struct flowi6 *fl6, struct dst_entry **dstp, 589 588 unsigned int flags, const struct sockcm_cookie *sockc) 590 589 { 591 - struct ipv6_pinfo *np = inet6_sk(sk); 592 590 struct net *net = sock_net(sk); 593 591 struct ipv6hdr *iph; 594 592 struct sk_buff *skb; ··· 668 668 error: 669 669 IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); 670 670 error_check: 671 - if (err == -ENOBUFS && !np->recverr) 671 + if (err == -ENOBUFS && !inet6_test_bit(RECVERR6, sk)) 672 672 err = 0; 673 673 return err; 674 674 }
+1 -1
net/ipv6/tcp_ipv6.c
··· 508 508 tcp_ld_RTO_revert(sk, seq); 509 509 } 510 510 511 - if (!sock_owned_by_user(sk) && np->recverr) { 511 + if (!sock_owned_by_user(sk) && inet6_test_bit(RECVERR6, sk)) { 512 512 WRITE_ONCE(sk->sk_err, err); 513 513 sk_error_report(sk); 514 514 } else {
+3 -3
net/ipv6/udp.c
··· 619 619 goto out; 620 620 } 621 621 622 - if (!np->recverr) { 622 + if (!inet6_test_bit(RECVERR6, sk)) { 623 623 if (!harderr || sk->sk_state != TCP_ESTABLISHED) 624 624 goto out; 625 625 } else { ··· 1283 1283 send: 1284 1284 err = ip6_send_skb(skb); 1285 1285 if (err) { 1286 - if (err == -ENOBUFS && !inet6_sk(sk)->recverr) { 1286 + if (err == -ENOBUFS && !inet6_test_bit(RECVERR6, sk)) { 1287 1287 UDP6_INC_STATS(sock_net(sk), 1288 1288 UDP_MIB_SNDBUFERRORS, is_udplite); 1289 1289 err = 0; ··· 1608 1608 up->pending = 0; 1609 1609 1610 1610 if (err > 0) 1611 - err = np->recverr ? net_xmit_errno(err) : 0; 1611 + err = inet6_test_bit(RECVERR6, sk) ? net_xmit_errno(err) : 0; 1612 1612 release_sock(sk); 1613 1613 1614 1614 out:
+1 -3
net/sctp/ipv6.c
··· 128 128 { 129 129 struct sctp_association *asoc = t->asoc; 130 130 struct sock *sk = asoc->base.sk; 131 - struct ipv6_pinfo *np; 132 131 int err = 0; 133 132 134 133 switch (type) { ··· 148 149 break; 149 150 } 150 151 151 - np = inet6_sk(sk); 152 152 icmpv6_err_convert(type, code, &err); 153 - if (!sock_owned_by_user(sk) && np->recverr) { 153 + if (!sock_owned_by_user(sk) && inet6_test_bit(RECVERR6, sk)) { 154 154 sk->sk_err = err; 155 155 sk_error_report(sk); 156 156 } else {