]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ip6mr: Convert ip6mr_net_exit_batch() to ->exit_rtnl().
authorKuniyuki Iwashima <kuniyu@google.com>
Thu, 4 Jun 2026 22:46:30 +0000 (22:46 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 9 Jun 2026 00:06:24 +0000 (17:06 -0700)
ip6mr_net_ops uses ->exit_batch() to acquire RTNL only once
for dying network namespaces.

ip6mr does not depend on the ordering of ->exit_rtnl() and
->exit_batch() of other pernet_operations (unlike fib_net_ops).

Once ip6mr_free_table() is called and all devices are
queued for destruction in ->exit_rtnl(), later during
NETDEV_UNREGISTER, ip6mr_device_event() will not see anything
in vif table and just do nothing.

Let's convert ip6mr_net_exit_batch() to ->exit_rtnl().

We will remove RTNL and unregister_netdevice_many() in
ip6mr_rules_init().

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260604224712.3209821-13-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv6/ip6mr.c

index f531c4a24ea13b36474575a58ed747187ad9ef48..e9560205b5477382a96bf599ee753421e20f5ce6 100644 (file)
@@ -267,18 +267,16 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
        fib_rules_unregister(net->ipv6.mr6_rules_ops);
 }
 
-static void __net_exit ip6mr_rules_exit_rtnl(struct net *net)
+static void __net_exit ip6mr_rules_exit_rtnl(struct net *net,
+                                            struct list_head *dev_kill_list)
 {
        struct mr_table *mrt, *next;
-       LIST_HEAD(dev_kill_list);
 
        ASSERT_RTNL();
        list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
                list_del_rcu(&mrt->list);
-               ip6mr_free_table(mrt, &dev_kill_list);
+               ip6mr_free_table(mrt, dev_kill_list);
        }
-
-       unregister_netdevice_many(&dev_kill_list);
 }
 
 static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb,
@@ -342,16 +340,15 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
 {
 }
 
-static void __net_exit ip6mr_rules_exit_rtnl(struct net *net)
+static void __net_exit ip6mr_rules_exit_rtnl(struct net *net,
+                                            struct list_head *dev_kill_list)
 {
        struct mr_table *mrt = rcu_dereference_protected(net->ipv6.mrt6, 1);
-       LIST_HEAD(dev_kill_list);
 
        ASSERT_RTNL();
 
        RCU_INIT_POINTER(net->ipv6.mrt6, NULL);
-       ip6mr_free_table(mrt, &dev_kill_list);
-       unregister_netdevice_many(&dev_kill_list);
+       ip6mr_free_table(mrt, dev_kill_list);
 }
 
 static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb,
@@ -1358,6 +1355,9 @@ static void __net_exit ip6mr_notifier_exit(struct net *net)
 /* Setup for IP multicast routing */
 static int __net_init ip6mr_net_init(struct net *net)
 {
+#ifdef CONFIG_PROC_FS
+       LIST_HEAD(dev_kill_list);
+#endif
        int err;
 
        err = ip6mr_notifier_init(net);
@@ -1385,7 +1385,8 @@ proc_cache_fail:
        remove_proc_entry("ip6_mr_vif", net->proc_net);
 proc_vif_fail:
        rtnl_lock();
-       ip6mr_rules_exit_rtnl(net);
+       ip6mr_rules_exit_rtnl(net, &dev_kill_list);
+       unregister_netdevice_many(&dev_kill_list);
        rtnl_unlock();
        ip6mr_rules_exit(net);
 #endif
@@ -1404,20 +1405,16 @@ static void __net_exit ip6mr_net_exit(struct net *net)
        ip6mr_notifier_exit(net);
 }
 
-static void __net_exit ip6mr_net_exit_batch(struct list_head *net_list)
+static void __net_exit ip6mr_net_exit_rtnl(struct net *net,
+                                          struct list_head *dev_kill_list)
 {
-       struct net *net;
-
-       rtnl_lock();
-       list_for_each_entry(net, net_list, exit_list)
-               ip6mr_rules_exit_rtnl(net);
-       rtnl_unlock();
+       ip6mr_rules_exit_rtnl(net, dev_kill_list);
 }
 
 static struct pernet_operations ip6mr_net_ops = {
        .init = ip6mr_net_init,
        .exit = ip6mr_net_exit,
-       .exit_batch = ip6mr_net_exit_batch,
+       .exit_rtnl = ip6mr_net_exit_rtnl,
 };
 
 static const struct rtnl_msg_handler ip6mr_rtnl_msg_handlers[] __initconst_or_module = {