summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/ipmr.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index d15e05662b09..7e2aa2026f01 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -102,7 +102,8 @@ static DEFINE_SPINLOCK(mfc_unres_lock);
static struct kmem_cache *mrt_cachep __ro_after_init;
static struct mr_table *ipmr_new_table(struct net *net, u32 id);
-static void ipmr_free_table(struct mr_table *mrt);
+static void ipmr_free_table(struct mr_table *mrt,
+ struct list_head *dev_kill_list);
static void ip_mr_forward(struct net *net, struct mr_table *mrt,
struct net_device *dev, struct sk_buff *skb,
@@ -251,6 +252,7 @@ static const struct fib_rules_ops __net_initconst ipmr_rules_ops_template = {
static int __net_init ipmr_rules_init(struct net *net)
{
struct fib_rules_ops *ops;
+ LIST_HEAD(dev_kill_list);
struct mr_table *mrt;
int err;
@@ -275,7 +277,8 @@ static int __net_init ipmr_rules_init(struct net *net)
err2:
rtnl_lock();
- ipmr_free_table(mrt);
+ ipmr_free_table(mrt, &dev_kill_list);
+ unregister_netdevice_many(&dev_kill_list);
rtnl_unlock();
err1:
fib_rules_unregister(ops);
@@ -285,12 +288,15 @@ err1:
static void __net_exit ipmr_rules_exit(struct net *net)
{
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);
+ ipmr_free_table(mrt, &dev_kill_list);
}
+
+ unregister_netdevice_many(&dev_kill_list);
fib_rules_unregister(net->ipv4.mr_rules_ops);
}
@@ -349,8 +355,13 @@ static int __net_init ipmr_rules_init(struct net *net)
static void __net_exit ipmr_rules_exit(struct net *net)
{
+ LIST_HEAD(dev_kill_list);
+
ASSERT_RTNL();
- ipmr_free_table(net->ipv4.mrt);
+
+ ipmr_free_table(net->ipv4.mrt, &dev_kill_list);
+ unregister_netdevice_many(&dev_kill_list);
+
net->ipv4.mrt = NULL;
}
@@ -425,18 +436,16 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
ipmr_expire_process, ipmr_new_table_set);
}
-static void ipmr_free_table(struct mr_table *mrt)
+static void ipmr_free_table(struct mr_table *mrt, struct list_head *dev_kill_list)
{
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,
- &dev_kill_list);
- unregister_netdevice_many(&dev_kill_list);
+ dev_kill_list);
rhltable_destroy(&mrt->mfc_hash);
kfree(mrt);
}