ip6mr: Call fib_rules_unregister() without RTNL.

fib_rules_unregister() removes ops from net->rules_ops under
spinlock, calls ops->delete() for each rule, and frees the ops.

ip6mr_rules_ops_template does not have ->delete(), and any
operation does not require RTNL there.

Let's move fib_rules_unregister() from ip6mr_rules_exit() to
ip6mr_net_exit().

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260604224712.3209821-10-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Kuniyuki Iwashima 2026-06-04 22:46:27 +00:00 committed by Jakub Kicinski
parent 2c309a863d
commit 4becf01246

View File

@ -259,6 +259,11 @@ static int __net_init ip6mr_rules_init(struct net *net)
}
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)
{
struct mr_table *mrt, *next;
@ -267,7 +272,6 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
list_del_rcu(&mrt->list);
ip6mr_free_table(mrt);
}
fib_rules_unregister(net->ipv6.mr6_rules_ops);
}
static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb,
@ -328,6 +332,10 @@ static int __net_init ip6mr_rules_init(struct net *net)
}
static void __net_exit ip6mr_rules_exit(struct net *net)
{
}
static void __net_exit ip6mr_rules_exit_rtnl(struct net *net)
{
struct mr_table *mrt = rcu_dereference_protected(net->ipv6.mrt6, 1);
@ -1366,8 +1374,9 @@ static int __net_init ip6mr_net_init(struct net *net)
remove_proc_entry("ip6_mr_vif", net->proc_net);
proc_vif_fail:
rtnl_lock();
ip6mr_rules_exit(net);
ip6mr_rules_exit_rtnl(net);
rtnl_unlock();
ip6mr_rules_exit(net);
#endif
ip6mr_rules_fail:
ip6mr_notifier_exit(net);
@ -1380,6 +1389,7 @@ static void __net_exit ip6mr_net_exit(struct net *net)
remove_proc_entry("ip6_mr_cache", net->proc_net);
remove_proc_entry("ip6_mr_vif", net->proc_net);
#endif
ip6mr_rules_exit(net);
ip6mr_notifier_exit(net);
}
@ -1389,7 +1399,7 @@ static void __net_exit ip6mr_net_exit_batch(struct list_head *net_list)
rtnl_lock();
list_for_each_entry(net, net_list, exit_list)
ip6mr_rules_exit(net);
ip6mr_rules_exit_rtnl(net);
rtnl_unlock();
}