diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2009-10-28 00:48:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-10-29 04:13:53 -0400 |
commit | c871e664ea39363c2a1011ec2dc4bc172dc396a0 (patch) | |
tree | 90a83827b99c690e5380d6f2668d224c5a2bc534 /net/ipv6 | |
parent | 62808f91237181dbac74c2b5be4fa92adfbbbe40 (diff) |
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/ipv6')
-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: | |||
477 | * Delete a VIF entry | 477 | * Delete a VIF entry |
478 | */ | 478 | */ |
479 | 479 | ||
480 | static int mif6_delete(struct net *net, int vifi) | 480 | static int mif6_delete(struct net *net, int vifi, struct list_head *head) |
481 | { | 481 | { |
482 | struct mif_device *v; | 482 | struct mif_device *v; |
483 | struct net_device *dev; | 483 | struct net_device *dev; |
@@ -519,7 +519,7 @@ static int mif6_delete(struct net *net, int vifi) | |||
519 | in6_dev->cnf.mc_forwarding--; | 519 | in6_dev->cnf.mc_forwarding--; |
520 | 520 | ||
521 | if (v->flags & MIFF_REGISTER) | 521 | if (v->flags & MIFF_REGISTER) |
522 | unregister_netdevice(dev); | 522 | unregister_netdevice_queue(dev, head); |
523 | 523 | ||
524 | dev_put(dev); | 524 | dev_put(dev); |
525 | return 0; | 525 | return 0; |
@@ -976,6 +976,7 @@ static int ip6mr_device_event(struct notifier_block *this, | |||
976 | struct net *net = dev_net(dev); | 976 | struct net *net = dev_net(dev); |
977 | struct mif_device *v; | 977 | struct mif_device *v; |
978 | int ct; | 978 | int ct; |
979 | LIST_HEAD(list); | ||
979 | 980 | ||
980 | if (event != NETDEV_UNREGISTER) | 981 | if (event != NETDEV_UNREGISTER) |
981 | return NOTIFY_DONE; | 982 | return NOTIFY_DONE; |
@@ -983,8 +984,10 @@ static int ip6mr_device_event(struct notifier_block *this, | |||
983 | v = &net->ipv6.vif6_table[0]; | 984 | v = &net->ipv6.vif6_table[0]; |
984 | for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) { | 985 | for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) { |
985 | if (v->dev == dev) | 986 | if (v->dev == dev) |
986 | mif6_delete(net, ct); | 987 | mif6_delete(net, ct, &list); |
987 | } | 988 | } |
989 | unregister_netdevice_many(&list); | ||
990 | |||
988 | return NOTIFY_DONE; | 991 | return NOTIFY_DONE; |
989 | } | 992 | } |
990 | 993 | ||
@@ -1188,14 +1191,16 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock) | |||
1188 | static void mroute_clean_tables(struct net *net) | 1191 | static void mroute_clean_tables(struct net *net) |
1189 | { | 1192 | { |
1190 | int i; | 1193 | int i; |
1194 | LIST_HEAD(list); | ||
1191 | 1195 | ||
1192 | /* | 1196 | /* |
1193 | * Shut down all active vif entries | 1197 | * Shut down all active vif entries |
1194 | */ | 1198 | */ |
1195 | for (i = 0; i < net->ipv6.maxvif; i++) { | 1199 | for (i = 0; i < net->ipv6.maxvif; i++) { |
1196 | if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC)) | 1200 | if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC)) |
1197 | mif6_delete(net, i); | 1201 | mif6_delete(net, i, &list); |
1198 | } | 1202 | } |
1203 | unregister_netdevice_many(&list); | ||
1199 | 1204 | ||
1200 | /* | 1205 | /* |
1201 | * Wipe the cache | 1206 | * Wipe the cache |
@@ -1325,7 +1330,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
1325 | if (copy_from_user(&mifi, optval, sizeof(mifi_t))) | 1330 | if (copy_from_user(&mifi, optval, sizeof(mifi_t))) |
1326 | return -EFAULT; | 1331 | return -EFAULT; |
1327 | rtnl_lock(); | 1332 | rtnl_lock(); |
1328 | ret = mif6_delete(net, mifi); | 1333 | ret = mif6_delete(net, mifi, NULL); |
1329 | rtnl_unlock(); | 1334 | rtnl_unlock(); |
1330 | return ret; | 1335 | return ret; |
1331 | 1336 | ||