diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2009-10-28 04:48:11 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-10-29 01:13:53 -0700 |
commit | c871e664ea39363c2a1011ec2dc4bc172dc396a0 (patch) | |
tree | 90a83827b99c690e5380d6f2668d224c5a2bc534 /net | |
parent | 62808f91237181dbac74c2b5be4fa92adfbbbe40 (diff) | |
download | linux-stable-c871e664ea39363c2a1011ec2dc4bc172dc396a0.tar.gz linux-stable-c871e664ea39363c2a1011ec2dc4bc172dc396a0.tar.bz2 linux-stable-c871e664ea39363c2a1011ec2dc4bc172dc396a0.zip |
ip6mr: Optimize multiple unregistration
Speedup module unloading by factorizing synchronize_rcu() calls
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/ip6mr.c | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 85849b4f5a36..52e0f74fdfe0 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -477,7 +477,7 @@ failure: * Delete a VIF entry */ -static int mif6_delete(struct net *net, int vifi) +static int mif6_delete(struct net *net, int vifi, struct list_head *head) { struct mif_device *v; struct net_device *dev; @@ -519,7 +519,7 @@ static int mif6_delete(struct net *net, int vifi) in6_dev->cnf.mc_forwarding--; if (v->flags & MIFF_REGISTER) - unregister_netdevice(dev); + unregister_netdevice_queue(dev, head); dev_put(dev); return 0; @@ -976,6 +976,7 @@ static int ip6mr_device_event(struct notifier_block *this, struct net *net = dev_net(dev); struct mif_device *v; int ct; + LIST_HEAD(list); if (event != NETDEV_UNREGISTER) return NOTIFY_DONE; @@ -983,8 +984,10 @@ static int ip6mr_device_event(struct notifier_block *this, v = &net->ipv6.vif6_table[0]; for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) { if (v->dev == dev) - mif6_delete(net, ct); + mif6_delete(net, ct, &list); } + unregister_netdevice_many(&list); + return NOTIFY_DONE; } @@ -1188,14 +1191,16 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock) static void mroute_clean_tables(struct net *net) { int i; + LIST_HEAD(list); /* * Shut down all active vif entries */ for (i = 0; i < net->ipv6.maxvif; i++) { if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC)) - mif6_delete(net, i); + mif6_delete(net, i, &list); } + unregister_netdevice_many(&list); /* * Wipe the cache @@ -1325,7 +1330,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns if (copy_from_user(&mifi, optval, sizeof(mifi_t))) return -EFAULT; rtnl_lock(); - ret = mif6_delete(net, mifi); + ret = mif6_delete(net, mifi, NULL); rtnl_unlock(); return ret; |