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

net: dst: annotate data-races around dst->obsolete

(dst_entry)->obsolete is read locklessly, add corresponding
annotations.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20250630121934.3399505-2-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Dumazet and committed by
Jakub Kicinski
8a402bbe 8077b9a9

+25 -24
+1 -1
include/net/dst.h
··· 476 476 u32)); 477 477 static inline struct dst_entry *dst_check(struct dst_entry *dst, u32 cookie) 478 478 { 479 - if (dst->obsolete) 479 + if (READ_ONCE(dst->obsolete)) 480 480 dst = INDIRECT_CALL_INET(dst->ops->check, ip6_dst_check, 481 481 ipv4_dst_check, dst, cookie); 482 482 return dst;
+1 -1
net/core/dst.c
··· 145 145 { 146 146 struct net_device *dev = dst->dev; 147 147 148 - dst->obsolete = DST_OBSOLETE_DEAD; 148 + WRITE_ONCE(dst->obsolete, DST_OBSOLETE_DEAD); 149 149 if (dst->ops->ifdown) 150 150 dst->ops->ifdown(dst, dev); 151 151 dst->input = dst_discard;
+1 -1
net/core/dst_cache.c
··· 52 52 53 53 if (unlikely(!time_after(idst->refresh_ts, 54 54 READ_ONCE(dst_cache->reset_ts)) || 55 - (dst->obsolete && !dst->ops->check(dst, idst->cookie)))) { 55 + (READ_ONCE(dst->obsolete) && !dst->ops->check(dst, idst->cookie)))) { 56 56 dst_cache_per_cpu_dst_set(idst, NULL, 0); 57 57 dst_release(dst); 58 58 goto fail;
+2 -1
net/core/neighbour.c
··· 1428 1428 * we can reinject the packet there. 1429 1429 */ 1430 1430 n2 = NULL; 1431 - if (dst && dst->obsolete != DST_OBSOLETE_DEAD) { 1431 + if (dst && 1432 + READ_ONCE(dst->obsolete) != DST_OBSOLETE_DEAD) { 1432 1433 n2 = dst_neigh_lookup_skb(dst, skb); 1433 1434 if (n2) 1434 1435 n1 = n2;
+2 -2
net/core/sock.c
··· 602 602 { 603 603 struct dst_entry *dst = __sk_dst_get(sk); 604 604 605 - if (dst && dst->obsolete && 605 + if (dst && READ_ONCE(dst->obsolete) && 606 606 INDIRECT_CALL_INET(dst->ops->check, ip6_dst_check, ipv4_dst_check, 607 607 dst, cookie) == NULL) { 608 608 sk_tx_queue_clear(sk); ··· 620 620 { 621 621 struct dst_entry *dst = sk_dst_get(sk); 622 622 623 - if (dst && dst->obsolete && 623 + if (dst && READ_ONCE(dst->obsolete) && 624 624 INDIRECT_CALL_INET(dst->ops->check, ip6_dst_check, ipv4_dst_check, 625 625 dst, cookie) == NULL) { 626 626 sk_dst_reset(sk);
+1 -1
net/ipv4/datagram.c
··· 109 109 rcu_read_lock(); 110 110 111 111 dst = __sk_dst_get(sk); 112 - if (!dst || !dst->obsolete || dst->ops->check(dst, 0)) { 112 + if (!dst || !READ_ONCE(dst->obsolete) || dst->ops->check(dst, 0)) { 113 113 rcu_read_unlock(); 114 114 return; 115 115 }
+8 -7
net/ipv4/route.c
··· 717 717 */ 718 718 rt = rcu_dereference(nhc->nhc_rth_input); 719 719 if (rt) 720 - rt->dst.obsolete = DST_OBSOLETE_KILL; 720 + WRITE_ONCE(rt->dst.obsolete, DST_OBSOLETE_KILL); 721 721 722 722 for_each_possible_cpu(i) { 723 723 struct rtable __rcu **prt; ··· 725 725 prt = per_cpu_ptr(nhc->nhc_pcpu_rth_output, i); 726 726 rt = rcu_dereference(*prt); 727 727 if (rt) 728 - rt->dst.obsolete = DST_OBSOLETE_KILL; 728 + WRITE_ONCE(rt->dst.obsolete, DST_OBSOLETE_KILL); 729 729 } 730 730 } 731 731 ··· 797 797 jiffies + ip_rt_gc_timeout); 798 798 } 799 799 if (kill_route) 800 - rt->dst.obsolete = DST_OBSOLETE_KILL; 800 + WRITE_ONCE(rt->dst.obsolete, DST_OBSOLETE_KILL); 801 801 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); 802 802 } 803 803 neigh_release(n); ··· 842 842 { 843 843 struct rtable *rt = dst_rtable(dst); 844 844 845 - if ((dst->obsolete > 0) || 845 + if ((READ_ONCE(dst->obsolete) > 0) || 846 846 (rt->rt_flags & RTCF_REDIRECTED) || 847 847 rt->dst.expires) 848 848 sk_dst_reset(sk); ··· 1136 1136 __build_flow_key(net, &fl4, sk, iph, 0, 0, 0, 0, 0); 1137 1137 1138 1138 rt = dst_rtable(odst); 1139 - if (odst->obsolete && !odst->ops->check(odst, 0)) { 1139 + if (READ_ONCE(odst->obsolete) && !odst->ops->check(odst, 0)) { 1140 1140 rt = ip_route_output_flow(sock_net(sk), &fl4, sk); 1141 1141 if (IS_ERR(rt)) 1142 1142 goto out; ··· 1211 1211 * this is indicated by setting obsolete to DST_OBSOLETE_KILL or 1212 1212 * DST_OBSOLETE_DEAD. 1213 1213 */ 1214 - if (dst->obsolete != DST_OBSOLETE_FORCE_CHK || rt_is_expired(rt)) 1214 + if (READ_ONCE(dst->obsolete) != DST_OBSOLETE_FORCE_CHK || 1215 + rt_is_expired(rt)) 1215 1216 return NULL; 1216 1217 return dst; 1217 1218 } ··· 1572 1571 static bool rt_cache_valid(const struct rtable *rt) 1573 1572 { 1574 1573 return rt && 1575 - rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && 1574 + READ_ONCE(rt->dst.obsolete) == DST_OBSOLETE_FORCE_CHK && 1576 1575 !rt_is_expired(rt); 1577 1576 } 1578 1577
+1 -1
net/ipv6/datagram.c
··· 127 127 128 128 rcu_read_lock(); 129 129 dst = __sk_dst_get(sk); 130 - if (!dst || !dst->obsolete || 130 + if (!dst || !READ_ONCE(dst->obsolete) || 131 131 dst->ops->check(dst, inet6_sk(sk)->dst_cookie)) { 132 132 rcu_read_unlock(); 133 133 return;
+4 -5
net/ipv6/route.c
··· 406 406 if (time_after(jiffies, rt->dst.expires)) 407 407 return true; 408 408 } else if (from) { 409 - return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK || 409 + return READ_ONCE(rt->dst.obsolete) != DST_OBSOLETE_FORCE_CHK || 410 410 fib6_check_expired(from); 411 411 } 412 412 return false; ··· 2777 2777 u32 cookie) 2778 2778 { 2779 2779 if (!__rt6_check_expired(rt) && 2780 - rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && 2780 + READ_ONCE(rt->dst.obsolete) == DST_OBSOLETE_FORCE_CHK && 2781 2781 fib6_check(from, cookie)) 2782 2782 return &rt->dst; 2783 - else 2784 - return NULL; 2783 + return NULL; 2785 2784 } 2786 2785 2787 2786 INDIRECT_CALLABLE_SCOPE struct dst_entry *ip6_dst_check(struct dst_entry *dst, ··· 3013 3014 sk_uid(sk)); 3014 3015 3015 3016 dst = __sk_dst_get(sk); 3016 - if (!dst || !dst->obsolete || 3017 + if (!dst || !READ_ONCE(dst->obsolete) || 3017 3018 dst->ops->check(dst, inet6_sk(sk)->dst_cookie)) 3018 3019 return; 3019 3020
+1 -1
net/netfilter/ipvs/ip_vs_xmit.c
··· 97 97 if (!dest_dst) 98 98 return NULL; 99 99 dst = dest_dst->dst_cache; 100 - if (dst->obsolete && 100 + if (READ_ONCE(dst->obsolete) && 101 101 dst->ops->check(dst, dest_dst->dst_cookie) == NULL) 102 102 return NULL; 103 103 return dest_dst;
+1 -1
net/sctp/transport.c
··· 240 240 void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) 241 241 { 242 242 /* If we don't have a fresh route, look one up */ 243 - if (!transport->dst || transport->dst->obsolete) { 243 + if (!transport->dst || READ_ONCE(transport->dst->obsolete)) { 244 244 sctp_transport_dst_release(transport); 245 245 transport->af_specific->get_dst(transport, &transport->saddr, 246 246 &transport->fl, sk);
+2 -2
net/xfrm/xfrm_policy.c
··· 3925 3925 * This will force stale_bundle() to fail on any xdst bundle with 3926 3926 * this dst linked in it. 3927 3927 */ 3928 - if (dst->obsolete < 0 && !stale_bundle(dst)) 3928 + if (READ_ONCE(dst->obsolete) < 0 && !stale_bundle(dst)) 3929 3929 return dst; 3930 3930 3931 3931 return NULL; ··· 3953 3953 3954 3954 static void xfrm_negative_advice(struct sock *sk, struct dst_entry *dst) 3955 3955 { 3956 - if (dst->obsolete) 3956 + if (READ_ONCE(dst->obsolete)) 3957 3957 sk_dst_reset(sk); 3958 3958 } 3959 3959