mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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>
This commit is contained in:
committed by
Jakub Kicinski
parent
8077b9a911
commit
8a402bbe54
@@ -476,7 +476,7 @@ INDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *,
|
||||
u32));
|
||||
static inline struct dst_entry *dst_check(struct dst_entry *dst, u32 cookie)
|
||||
{
|
||||
if (dst->obsolete)
|
||||
if (READ_ONCE(dst->obsolete))
|
||||
dst = INDIRECT_CALL_INET(dst->ops->check, ip6_dst_check,
|
||||
ipv4_dst_check, dst, cookie);
|
||||
return dst;
|
||||
|
||||
@@ -145,7 +145,7 @@ void dst_dev_put(struct dst_entry *dst)
|
||||
{
|
||||
struct net_device *dev = dst->dev;
|
||||
|
||||
dst->obsolete = DST_OBSOLETE_DEAD;
|
||||
WRITE_ONCE(dst->obsolete, DST_OBSOLETE_DEAD);
|
||||
if (dst->ops->ifdown)
|
||||
dst->ops->ifdown(dst, dev);
|
||||
dst->input = dst_discard;
|
||||
|
||||
@@ -52,7 +52,7 @@ static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache,
|
||||
|
||||
if (unlikely(!time_after(idst->refresh_ts,
|
||||
READ_ONCE(dst_cache->reset_ts)) ||
|
||||
(dst->obsolete && !dst->ops->check(dst, idst->cookie)))) {
|
||||
(READ_ONCE(dst->obsolete) && !dst->ops->check(dst, idst->cookie)))) {
|
||||
dst_cache_per_cpu_dst_set(idst, NULL, 0);
|
||||
dst_release(dst);
|
||||
goto fail;
|
||||
|
||||
@@ -1428,7 +1428,8 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
|
||||
* we can reinject the packet there.
|
||||
*/
|
||||
n2 = NULL;
|
||||
if (dst && dst->obsolete != DST_OBSOLETE_DEAD) {
|
||||
if (dst &&
|
||||
READ_ONCE(dst->obsolete) != DST_OBSOLETE_DEAD) {
|
||||
n2 = dst_neigh_lookup_skb(dst, skb);
|
||||
if (n2)
|
||||
n1 = n2;
|
||||
|
||||
@@ -602,7 +602,7 @@ struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie)
|
||||
{
|
||||
struct dst_entry *dst = __sk_dst_get(sk);
|
||||
|
||||
if (dst && dst->obsolete &&
|
||||
if (dst && READ_ONCE(dst->obsolete) &&
|
||||
INDIRECT_CALL_INET(dst->ops->check, ip6_dst_check, ipv4_dst_check,
|
||||
dst, cookie) == NULL) {
|
||||
sk_tx_queue_clear(sk);
|
||||
@@ -620,7 +620,7 @@ struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie)
|
||||
{
|
||||
struct dst_entry *dst = sk_dst_get(sk);
|
||||
|
||||
if (dst && dst->obsolete &&
|
||||
if (dst && READ_ONCE(dst->obsolete) &&
|
||||
INDIRECT_CALL_INET(dst->ops->check, ip6_dst_check, ipv4_dst_check,
|
||||
dst, cookie) == NULL) {
|
||||
sk_dst_reset(sk);
|
||||
|
||||
@@ -109,7 +109,7 @@ void ip4_datagram_release_cb(struct sock *sk)
|
||||
rcu_read_lock();
|
||||
|
||||
dst = __sk_dst_get(sk);
|
||||
if (!dst || !dst->obsolete || dst->ops->check(dst, 0)) {
|
||||
if (!dst || !READ_ONCE(dst->obsolete) || dst->ops->check(dst, 0)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -717,7 +717,7 @@ static void update_or_create_fnhe(struct fib_nh_common *nhc, __be32 daddr,
|
||||
*/
|
||||
rt = rcu_dereference(nhc->nhc_rth_input);
|
||||
if (rt)
|
||||
rt->dst.obsolete = DST_OBSOLETE_KILL;
|
||||
WRITE_ONCE(rt->dst.obsolete, DST_OBSOLETE_KILL);
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
struct rtable __rcu **prt;
|
||||
@@ -725,7 +725,7 @@ static void update_or_create_fnhe(struct fib_nh_common *nhc, __be32 daddr,
|
||||
prt = per_cpu_ptr(nhc->nhc_pcpu_rth_output, i);
|
||||
rt = rcu_dereference(*prt);
|
||||
if (rt)
|
||||
rt->dst.obsolete = DST_OBSOLETE_KILL;
|
||||
WRITE_ONCE(rt->dst.obsolete, DST_OBSOLETE_KILL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,7 +797,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow
|
||||
jiffies + ip_rt_gc_timeout);
|
||||
}
|
||||
if (kill_route)
|
||||
rt->dst.obsolete = DST_OBSOLETE_KILL;
|
||||
WRITE_ONCE(rt->dst.obsolete, DST_OBSOLETE_KILL);
|
||||
call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n);
|
||||
}
|
||||
neigh_release(n);
|
||||
@@ -842,7 +842,7 @@ static void ipv4_negative_advice(struct sock *sk,
|
||||
{
|
||||
struct rtable *rt = dst_rtable(dst);
|
||||
|
||||
if ((dst->obsolete > 0) ||
|
||||
if ((READ_ONCE(dst->obsolete) > 0) ||
|
||||
(rt->rt_flags & RTCF_REDIRECTED) ||
|
||||
rt->dst.expires)
|
||||
sk_dst_reset(sk);
|
||||
@@ -1136,7 +1136,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
|
||||
__build_flow_key(net, &fl4, sk, iph, 0, 0, 0, 0, 0);
|
||||
|
||||
rt = dst_rtable(odst);
|
||||
if (odst->obsolete && !odst->ops->check(odst, 0)) {
|
||||
if (READ_ONCE(odst->obsolete) && !odst->ops->check(odst, 0)) {
|
||||
rt = ip_route_output_flow(sock_net(sk), &fl4, sk);
|
||||
if (IS_ERR(rt))
|
||||
goto out;
|
||||
@@ -1211,7 +1211,8 @@ INDIRECT_CALLABLE_SCOPE struct dst_entry *ipv4_dst_check(struct dst_entry *dst,
|
||||
* this is indicated by setting obsolete to DST_OBSOLETE_KILL or
|
||||
* DST_OBSOLETE_DEAD.
|
||||
*/
|
||||
if (dst->obsolete != DST_OBSOLETE_FORCE_CHK || rt_is_expired(rt))
|
||||
if (READ_ONCE(dst->obsolete) != DST_OBSOLETE_FORCE_CHK ||
|
||||
rt_is_expired(rt))
|
||||
return NULL;
|
||||
return dst;
|
||||
}
|
||||
@@ -1571,7 +1572,7 @@ void rt_flush_dev(struct net_device *dev)
|
||||
static bool rt_cache_valid(const struct rtable *rt)
|
||||
{
|
||||
return rt &&
|
||||
rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
|
||||
READ_ONCE(rt->dst.obsolete) == DST_OBSOLETE_FORCE_CHK &&
|
||||
!rt_is_expired(rt);
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ void ip6_datagram_release_cb(struct sock *sk)
|
||||
|
||||
rcu_read_lock();
|
||||
dst = __sk_dst_get(sk);
|
||||
if (!dst || !dst->obsolete ||
|
||||
if (!dst || !READ_ONCE(dst->obsolete) ||
|
||||
dst->ops->check(dst, inet6_sk(sk)->dst_cookie)) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
|
||||
@@ -406,7 +406,7 @@ static bool rt6_check_expired(const struct rt6_info *rt)
|
||||
if (time_after(jiffies, rt->dst.expires))
|
||||
return true;
|
||||
} else if (from) {
|
||||
return rt->dst.obsolete != DST_OBSOLETE_FORCE_CHK ||
|
||||
return READ_ONCE(rt->dst.obsolete) != DST_OBSOLETE_FORCE_CHK ||
|
||||
fib6_check_expired(from);
|
||||
}
|
||||
return false;
|
||||
@@ -2777,11 +2777,10 @@ static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt,
|
||||
u32 cookie)
|
||||
{
|
||||
if (!__rt6_check_expired(rt) &&
|
||||
rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
|
||||
READ_ONCE(rt->dst.obsolete) == DST_OBSOLETE_FORCE_CHK &&
|
||||
fib6_check(from, cookie))
|
||||
return &rt->dst;
|
||||
else
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INDIRECT_CALLABLE_SCOPE struct dst_entry *ip6_dst_check(struct dst_entry *dst,
|
||||
@@ -3014,7 +3013,7 @@ void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu)
|
||||
sk_uid(sk));
|
||||
|
||||
dst = __sk_dst_get(sk);
|
||||
if (!dst || !dst->obsolete ||
|
||||
if (!dst || !READ_ONCE(dst->obsolete) ||
|
||||
dst->ops->check(dst, inet6_sk(sk)->dst_cookie))
|
||||
return;
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ __ip_vs_dst_check(struct ip_vs_dest *dest)
|
||||
if (!dest_dst)
|
||||
return NULL;
|
||||
dst = dest_dst->dst_cache;
|
||||
if (dst->obsolete &&
|
||||
if (READ_ONCE(dst->obsolete) &&
|
||||
dst->ops->check(dst, dest_dst->dst_cookie) == NULL)
|
||||
return NULL;
|
||||
return dest_dst;
|
||||
|
||||
@@ -240,7 +240,7 @@ void sctp_transport_set_owner(struct sctp_transport *transport,
|
||||
void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk)
|
||||
{
|
||||
/* If we don't have a fresh route, look one up */
|
||||
if (!transport->dst || transport->dst->obsolete) {
|
||||
if (!transport->dst || READ_ONCE(transport->dst->obsolete)) {
|
||||
sctp_transport_dst_release(transport);
|
||||
transport->af_specific->get_dst(transport, &transport->saddr,
|
||||
&transport->fl, sk);
|
||||
|
||||
@@ -3925,7 +3925,7 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
|
||||
* This will force stale_bundle() to fail on any xdst bundle with
|
||||
* this dst linked in it.
|
||||
*/
|
||||
if (dst->obsolete < 0 && !stale_bundle(dst))
|
||||
if (READ_ONCE(dst->obsolete) < 0 && !stale_bundle(dst))
|
||||
return dst;
|
||||
|
||||
return NULL;
|
||||
@@ -3953,7 +3953,7 @@ static void xfrm_link_failure(struct sk_buff *skb)
|
||||
|
||||
static void xfrm_negative_advice(struct sock *sk, struct dst_entry *dst)
|
||||
{
|
||||
if (dst->obsolete)
|
||||
if (READ_ONCE(dst->obsolete))
|
||||
sk_dst_reset(sk);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user