]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ipmr: Move unregister_netdevice_many() out of mroute_clean_tables().
authorKuniyuki Iwashima <kuniyu@google.com>
Sat, 28 Feb 2026 22:17:25 +0000 (22:17 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 3 Mar 2026 02:49:40 +0000 (18:49 -0800)
This is a prep commit to convert ipmr_net_exit_batch() to
->exit_rtnl().

Let's move unregister_netdevice_many() in mroute_clean_tables()
to its callers.

As a bonus, mrtsock_destruct() can do batching for all tables.

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

index 5c8508788fb64c6b8a372577ef72a883fb6945b8..d15e05662b0905cef676d9dabad7c43c490c0556 100644 (file)
@@ -112,7 +112,8 @@ static int ipmr_cache_report(const struct mr_table *mrt,
 static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
                                 int cmd);
 static void igmpmsg_netlink_event(const struct mr_table *mrt, struct sk_buff *pkt);
-static void mroute_clean_tables(struct mr_table *mrt, int flags);
+static void mroute_clean_tables(struct mr_table *mrt, int flags,
+                               struct list_head *dev_kill_list);
 static void ipmr_expire_process(struct timer_list *t);
 
 #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
@@ -427,12 +428,15 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
 static void ipmr_free_table(struct mr_table *mrt)
 {
        struct net *net = read_pnet(&mrt->net);
+       LIST_HEAD(dev_kill_list);
 
        WARN_ON_ONCE(!mr_can_free_table(net));
 
        timer_shutdown_sync(&mrt->ipmr_expire_timer);
        mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC |
-                                MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC);
+                           MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC,
+                           &dev_kill_list);
+       unregister_netdevice_many(&dev_kill_list);
        rhltable_destroy(&mrt->mfc_hash);
        kfree(mrt);
 }
@@ -1293,12 +1297,12 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
 }
 
 /* Close the multicast socket, and clear the vif tables etc */
-static void mroute_clean_tables(struct mr_table *mrt, int flags)
+static void mroute_clean_tables(struct mr_table *mrt, int flags,
+                               struct list_head *dev_kill_list)
 {
        struct net *net = read_pnet(&mrt->net);
-       struct mr_mfc *c, *tmp;
        struct mfc_cache *cache;
-       LIST_HEAD(list);
+       struct mr_mfc *c, *tmp;
        int i;
 
        /* Shut down all active vif entries */
@@ -1308,9 +1312,8 @@ static void mroute_clean_tables(struct mr_table *mrt, int flags)
                             !(flags & MRT_FLUSH_VIFS_STATIC)) ||
                            (!(mrt->vif_table[i].flags & VIFF_STATIC) && !(flags & MRT_FLUSH_VIFS)))
                                continue;
-                       vif_delete(mrt, i, 0, &list);
+                       vif_delete(mrt, i, 0, dev_kill_list);
                }
-               unregister_netdevice_many(&list);
        }
 
        /* Wipe the cache */
@@ -1349,9 +1352,11 @@ static void mroute_clean_tables(struct mr_table *mrt, int flags)
 static void mrtsock_destruct(struct sock *sk)
 {
        struct net *net = sock_net(sk);
+       LIST_HEAD(dev_kill_list);
        struct mr_table *mrt;
 
        rtnl_lock();
+
        ipmr_for_each_table(mrt, net) {
                if (sk == rtnl_dereference(mrt->mroute_sk)) {
                        IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
@@ -1360,9 +1365,13 @@ static void mrtsock_destruct(struct sock *sk)
                                                    NETCONFA_IFINDEX_ALL,
                                                    net->ipv4.devconf_all);
                        RCU_INIT_POINTER(mrt->mroute_sk, NULL);
-                       mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_MFC);
+                       mroute_clean_tables(mrt, MRT_FLUSH_VIFS | MRT_FLUSH_MFC,
+                                           &dev_kill_list);
                }
        }
+
+       unregister_netdevice_many(&dev_kill_list);
+
        rtnl_unlock();
 }
 
@@ -1485,7 +1494,9 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
                                           sk == rtnl_dereference(mrt->mroute_sk),
                                           parent);
                break;
-       case MRT_FLUSH:
+       case MRT_FLUSH: {
+               LIST_HEAD(dev_kill_list);
+
                if (optlen != sizeof(val)) {
                        ret = -EINVAL;
                        break;
@@ -1494,8 +1505,11 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
                        ret = -EFAULT;
                        break;
                }
-               mroute_clean_tables(mrt, val);
+
+               mroute_clean_tables(mrt, val, &dev_kill_list);
+               unregister_netdevice_many(&dev_kill_list);
                break;
+       }
        /* Control PIM assert. */
        case MRT_ASSERT:
                if (optlen != sizeof(val)) {