ip6mr: Optimize multiple unregistration
authorEric Dumazet <eric.dumazet@gmail.com>
Wed, 28 Oct 2009 04:48:11 +0000 (04:48 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 29 Oct 2009 08:13:53 +0000 (01:13 -0700)
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>
net/ipv6/ip6mr.c

index 85849b4..52e0f74 100644 (file)
@@ -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;