mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 07:51:31 -04:00
ipmr: Remove RTNL in ipmr_rules_init() and ipmr_net_init().
When ipmr_free_table() is called from ipmr_rules_init() or ipmr_net_init(), the netns is not yet published. Thus, no device should have been registered, and mroute_clean_tables() will not call vif_delete(), so unregister_netdevice_many() is unnecessary. unregister_netdevice_many() does nothing if the list is empty, but it requires RTNL due to the unconditional ASSERT_RTNL() at the entry of unregister_netdevice_many_notify(). Let's remove unnecessary RTNL and ASSERT_RTNL() and instead add WARN_ON_ONCE() in ipmr_free_table(). Note that we use a local list for the new WARN_ON_ONCE() because dev_kill_list passed from ipmr_rules_exit_rtnl() may have some devices when other ops->init() fails after ipmr durnig setup_net(). Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260228221800.1082070-11-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
b22b018674
commit
4a11adcd9e
@@ -276,10 +276,7 @@ static int __net_init ipmr_rules_init(struct net *net)
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
rtnl_lock();
|
||||
ipmr_free_table(mrt, &dev_kill_list);
|
||||
unregister_netdevice_many(&dev_kill_list);
|
||||
rtnl_unlock();
|
||||
err1:
|
||||
fib_rules_unregister(ops);
|
||||
return err;
|
||||
@@ -290,7 +287,6 @@ static void __net_exit ipmr_rules_exit_rtnl(struct net *net,
|
||||
{
|
||||
struct mr_table *mrt, *next;
|
||||
|
||||
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);
|
||||
@@ -355,8 +351,6 @@ static int __net_init ipmr_rules_init(struct net *net)
|
||||
static void __net_exit ipmr_rules_exit_rtnl(struct net *net,
|
||||
struct list_head *dev_kill_list)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
ipmr_free_table(net->ipv4.mrt, dev_kill_list);
|
||||
|
||||
net->ipv4.mrt = NULL;
|
||||
@@ -436,15 +430,19 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
|
||||
static void ipmr_free_table(struct mr_table *mrt, struct list_head *dev_kill_list)
|
||||
{
|
||||
struct net *net = read_pnet(&mrt->net);
|
||||
LIST_HEAD(ipmr_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,
|
||||
dev_kill_list);
|
||||
&ipmr_dev_kill_list);
|
||||
rhltable_destroy(&mrt->mfc_hash);
|
||||
kfree(mrt);
|
||||
|
||||
WARN_ON_ONCE(!net_initialized(net) && !list_empty(&ipmr_dev_kill_list));
|
||||
list_splice(&ipmr_dev_kill_list, dev_kill_list);
|
||||
}
|
||||
|
||||
/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
|
||||
@@ -3287,10 +3285,7 @@ static int __net_init ipmr_net_init(struct net *net)
|
||||
proc_cache_fail:
|
||||
remove_proc_entry("ip_mr_vif", net->proc_net);
|
||||
proc_vif_fail:
|
||||
rtnl_lock();
|
||||
ipmr_rules_exit_rtnl(net, &dev_kill_list);
|
||||
unregister_netdevice_many(&dev_kill_list);
|
||||
rtnl_unlock();
|
||||
#endif
|
||||
ipmr_rules_fail:
|
||||
ipmr_notifier_exit(net);
|
||||
|
||||
Reference in New Issue
Block a user