]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ipmr/ip6mr: Convert net->ipv[46].ipmr_seq to atomic_t.
authorKuniyuki Iwashima <kuniyu@google.com>
Sat, 28 Feb 2026 22:17:31 +0000 (22:17 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 3 Mar 2026 02:49:41 +0000 (18:49 -0800)
We will no longer hold RTNL for ipmr_mfc_add() and ipmr_mfc_delete().

MFC entry can be loosely connected with VIF by its index for
mrt->vif_table[] (stored in mfc_parent), but the two tables are
not synchronised.  i.e. Even if VIF 1 is removed, MFC for VIF 1
is not automatically removed.

The only field that the MFC/VIF interfaces share is
net->ipv[46].ipmr_seq, which is protected by RTNL.

Adding a new mutex for both just to protect a single field is overkill.

Let's convert the field to atomic_t.

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260228221800.1082070-14-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/linux/mroute_base.h
include/net/netns/ipv4.h
include/net/netns/ipv6.h
net/ipv4/ipmr.c
net/ipv6/ip6mr.c

index 0075f6e5c3da9d38ca49bdb57ab2a7fd8a18f573..0baa6f994da9e3ff58d591225164da4e01dd9ea8 100644 (file)
@@ -76,7 +76,7 @@ static inline int mr_call_vif_notifiers(struct net *net,
                                        struct vif_device *vif,
                                        struct net_device *vif_dev,
                                        unsigned short vif_index, u32 tb_id,
-                                       unsigned int *ipmr_seq)
+                                       atomic_t *ipmr_seq)
 {
        struct vif_entry_notifier_info info = {
                .info = {
@@ -89,7 +89,7 @@ static inline int mr_call_vif_notifiers(struct net *net,
        };
 
        ASSERT_RTNL();
-       (*ipmr_seq)++;
+       atomic_inc(ipmr_seq);
        return call_fib_notifiers(net, event_type, &info.info);
 }
 
@@ -198,7 +198,7 @@ static inline int mr_call_mfc_notifiers(struct net *net,
                                        unsigned short family,
                                        enum fib_event_type event_type,
                                        struct mr_mfc *mfc, u32 tb_id,
-                                       unsigned int *ipmr_seq)
+                                       atomic_t *ipmr_seq)
 {
        struct mfc_entry_notifier_info info = {
                .info = {
@@ -209,7 +209,7 @@ static inline int mr_call_mfc_notifiers(struct net *net,
        };
 
        ASSERT_RTNL();
-       (*ipmr_seq)++;
+       atomic_inc(ipmr_seq);
        return call_fib_notifiers(net, event_type, &info.info);
 }
 
index 380ff34c023320a37eb6d8e4d24b6018f8d565a1..94dca64fec416946eb2367067240344f44c12764 100644 (file)
@@ -280,7 +280,7 @@ struct netns_ipv4 {
        struct fib_rules_ops    *mr_rules_ops;
 #endif
        struct fib_notifier_ops *ipmr_notifier_ops;
-       unsigned int            ipmr_seq;       /* protected by rtnl_mutex */
+       atomic_t                ipmr_seq;
 #endif
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
        struct sysctl_fib_multipath_hash_seed sysctl_fib_multipath_hash_seed;
index 34bdb1308e8ff85f04130ed25f40a4f8a24db083..499e4288170fc6c59039614addcc82267a317d6b 100644 (file)
@@ -118,7 +118,7 @@ struct netns_ipv6 {
        struct seg6_pernet_data *seg6_data;
        struct fib_notifier_ops *notifier_ops;
        struct fib_notifier_ops *ip6mr_notifier_ops;
-       unsigned int ipmr_seq; /* protected by rtnl_mutex */
+       atomic_t                ipmr_seq;
        struct {
                struct hlist_head head;
                spinlock_t      lock;
index 07f2d4f8dcbe030d12cdca11dbbc1ae659bd369f..6ec73796d84da81d0621b0f9bbeed10d83589113 100644 (file)
@@ -3226,7 +3226,7 @@ static const struct net_protocol pim_protocol = {
 
 static unsigned int ipmr_seq_read(const struct net *net)
 {
-       return READ_ONCE(net->ipv4.ipmr_seq) + ipmr_rules_seq_read(net);
+       return atomic_read(&net->ipv4.ipmr_seq) + ipmr_rules_seq_read(net);
 }
 
 static int ipmr_dump(struct net *net, struct notifier_block *nb,
@@ -3247,7 +3247,7 @@ static int __net_init ipmr_notifier_init(struct net *net)
 {
        struct fib_notifier_ops *ops;
 
-       net->ipv4.ipmr_seq = 0;
+       atomic_set(&net->ipv4.ipmr_seq, 0);
 
        ops = fib_notifier_ops_register(&ipmr_notifier_ops_template, net);
        if (IS_ERR(ops))
index e047a4680ab0e0fd06b81451bdfd0ebd47459f2e..85010ff21c981913e2a5e6096819d55c91f5d714 100644 (file)
@@ -1280,7 +1280,7 @@ static int ip6mr_device_event(struct notifier_block *this,
 
 static unsigned int ip6mr_seq_read(const struct net *net)
 {
-       return READ_ONCE(net->ipv6.ipmr_seq) + ip6mr_rules_seq_read(net);
+       return atomic_read(&net->ipv6.ipmr_seq) + ip6mr_rules_seq_read(net);
 }
 
 static int ip6mr_dump(struct net *net, struct notifier_block *nb,
@@ -1305,7 +1305,7 @@ static int __net_init ip6mr_notifier_init(struct net *net)
 {
        struct fib_notifier_ops *ops;
 
-       net->ipv6.ipmr_seq = 0;
+       atomic_set(&net->ipv6.ipmr_seq, 0);
 
        ops = fib_notifier_ops_register(&ip6mr_notifier_ops_template, net);
        if (IS_ERR(ops))