]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ipmr: Convert ipmr_net_exit_batch() to ->exit_rtnl().
authorKuniyuki Iwashima <kuniyu@google.com>
Sat, 28 Feb 2026 22:17:27 +0000 (22:17 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 3 Mar 2026 02:49:40 +0000 (18:49 -0800)
ipmr_net_ops uses ->exit_batch() to acquire RTNL only once
for dying network namespaces.

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

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

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

Note that fib_rules_unregister() does not need RTNL and
we will remove RTNL and unregister_netdevice_many() in
ipmr_net_init().

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260228221800.1082070-10-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv4/ipmr.c

index 7e2aa2026f01ed2f03b97505e2ed9cd0a59b2035..72761c8b293059034eea32964834518af87ad90b 100644 (file)
@@ -285,18 +285,17 @@ err1:
        return err;
 }
 
-static void __net_exit ipmr_rules_exit(struct net *net)
+static void __net_exit ipmr_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->ipv4.mr_tables, list) {
                list_del(&mrt->list);
-               ipmr_free_table(mrt, &dev_kill_list);
+               ipmr_free_table(mrt, dev_kill_list);
        }
 
-       unregister_netdevice_many(&dev_kill_list);
        fib_rules_unregister(net->ipv4.mr_rules_ops);
 }
 
@@ -353,14 +352,12 @@ static int __net_init ipmr_rules_init(struct net *net)
        return 0;
 }
 
-static void __net_exit ipmr_rules_exit(struct net *net)
+static void __net_exit ipmr_rules_exit_rtnl(struct net *net,
+                                           struct list_head *dev_kill_list)
 {
-       LIST_HEAD(dev_kill_list);
-
        ASSERT_RTNL();
 
-       ipmr_free_table(net->ipv4.mrt, &dev_kill_list);
-       unregister_netdevice_many(&dev_kill_list);
+       ipmr_free_table(net->ipv4.mrt, dev_kill_list);
 
        net->ipv4.mrt = NULL;
 }
@@ -3264,6 +3261,7 @@ static void __net_exit ipmr_notifier_exit(struct net *net)
 /* Setup for IP multicast routing */
 static int __net_init ipmr_net_init(struct net *net)
 {
+       LIST_HEAD(dev_kill_list);
        int err;
 
        err = ipmr_notifier_init(net);
@@ -3290,7 +3288,8 @@ proc_cache_fail:
        remove_proc_entry("ip_mr_vif", net->proc_net);
 proc_vif_fail:
        rtnl_lock();
-       ipmr_rules_exit(net);
+       ipmr_rules_exit_rtnl(net, &dev_kill_list);
+       unregister_netdevice_many(&dev_kill_list);
        rtnl_unlock();
 #endif
 ipmr_rules_fail:
@@ -3308,20 +3307,16 @@ static void __net_exit ipmr_net_exit(struct net *net)
        ipmr_notifier_exit(net);
 }
 
-static void __net_exit ipmr_net_exit_batch(struct list_head *net_list)
+static void __net_exit ipmr_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)
-               ipmr_rules_exit(net);
-       rtnl_unlock();
+       ipmr_rules_exit_rtnl(net, dev_kill_list);
 }
 
 static struct pernet_operations ipmr_net_ops = {
        .init = ipmr_net_init,
        .exit = ipmr_net_exit,
-       .exit_batch = ipmr_net_exit_batch,
+       .exit_rtnl = ipmr_net_exit_rtnl,
 };
 
 static const struct rtnl_msg_handler ipmr_rtnl_msg_handlers[] __initconst = {