]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: dst: add four helpers to annotate data-races around dst->dev
authorEric Dumazet <edumazet@google.com>
Mon, 30 Jun 2025 12:19:30 +0000 (12:19 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 15 Aug 2025 14:38:42 +0000 (16:38 +0200)
[ Upstream commit 88fe14253e181878c2ddb51a298ae8c468a63010 ]

dst->dev is read locklessly in many contexts,
and written in dst_dev_put().

Fixing all the races is going to need many changes.

We probably will have to add full RCU protection.

Add three helpers to ease this painful process.

static inline struct net_device *dst_dev(const struct dst_entry *dst)
{
       return READ_ONCE(dst->dev);
}

static inline struct net_device *skb_dst_dev(const struct sk_buff *skb)
{
       return dst_dev(skb_dst(skb));
}

static inline struct net *skb_dst_dev_net(const struct sk_buff *skb)
{
       return dev_net(skb_dst_dev(skb));
}

static inline struct net *skb_dst_dev_net_rcu(const struct sk_buff *skb)
{
       return dev_net_rcu(skb_dst_dev(skb));
}

Fixes: 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20250630121934.3399505-7-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/net/dst.h
net/core/dst.c
net/core/sock.c

index 2caf85e2ce864f83ab50d80cba81579f7ee512c1..32dafbab4cd0d63a17932d70ac77fd897b1a1908 100644 (file)
@@ -561,6 +561,26 @@ static inline void skb_dst_update_pmtu_no_confirm(struct sk_buff *skb, u32 mtu)
                dst->ops->update_pmtu(dst, NULL, skb, mtu, false);
 }
 
+static inline struct net_device *dst_dev(const struct dst_entry *dst)
+{
+       return READ_ONCE(dst->dev);
+}
+
+static inline struct net_device *skb_dst_dev(const struct sk_buff *skb)
+{
+       return dst_dev(skb_dst(skb));
+}
+
+static inline struct net *skb_dst_dev_net(const struct sk_buff *skb)
+{
+       return dev_net(skb_dst_dev(skb));
+}
+
+static inline struct net *skb_dst_dev_net_rcu(const struct sk_buff *skb)
+{
+       return dev_net_rcu(skb_dst_dev(skb));
+}
+
 struct dst_entry *dst_blackhole_check(struct dst_entry *dst, u32 cookie);
 void dst_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk,
                               struct sk_buff *skb, u32 mtu, bool confirm_neigh);
index e483daf17666e2e5a1f7fd3c5b8fe5011dfdff8e..b3a12c7c08af0c62b0d88eb4306164a2cc563433 100644 (file)
@@ -150,7 +150,7 @@ void dst_dev_put(struct dst_entry *dst)
                dst->ops->ifdown(dst, dev);
        WRITE_ONCE(dst->input, dst_discard);
        WRITE_ONCE(dst->output, dst_discard_out);
-       dst->dev = blackhole_netdev;
+       WRITE_ONCE(dst->dev, blackhole_netdev);
        netdev_ref_replace(dev, blackhole_netdev, &dst->dev_tracker,
                           GFP_ATOMIC);
 }
@@ -263,7 +263,7 @@ unsigned int dst_blackhole_mtu(const struct dst_entry *dst)
 {
        unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);
 
-       return mtu ? : dst->dev->mtu;
+       return mtu ? : dst_dev(dst)->mtu;
 }
 EXPORT_SYMBOL_GPL(dst_blackhole_mtu);
 
index 3b409bc8ef6d81828cef63bc828db932abb1cfab..9fae9239f939342b9562fd0aae00471f8addbb3e 100644 (file)
@@ -2602,8 +2602,8 @@ static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst)
                   !ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr));
 #endif
        /* pairs with the WRITE_ONCE() in netif_set_gso(_ipv4)_max_size() */
-       max_size = is_ipv6 ? READ_ONCE(dst->dev->gso_max_size) :
-                       READ_ONCE(dst->dev->gso_ipv4_max_size);
+       max_size = is_ipv6 ? READ_ONCE(dst_dev(dst)->gso_max_size) :
+                       READ_ONCE(dst_dev(dst)->gso_ipv4_max_size);
        if (max_size > GSO_LEGACY_MAX_SIZE && !sk_is_tcp(sk))
                max_size = GSO_LEGACY_MAX_SIZE;
 
@@ -2614,7 +2614,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
 {
        u32 max_segs = 1;
 
-       sk->sk_route_caps = dst->dev->features;
+       sk->sk_route_caps = dst_dev(dst)->features;
        if (sk_is_tcp(sk)) {
                struct inet_connection_sock *icsk = inet_csk(sk);
 
@@ -2632,7 +2632,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
                        sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
                        sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dst);
                        /* pairs with the WRITE_ONCE() in netif_set_gso_max_segs() */
-                       max_segs = max_t(u32, READ_ONCE(dst->dev->gso_max_segs), 1);
+                       max_segs = max_t(u32, READ_ONCE(dst_dev(dst)->gso_max_segs), 1);
                }
        }
        sk->sk_gso_max_segs = max_segs;