netlink: fix for too early rmmod
[safe/jmp/linux-2.6] / net / core / dev.c
index bb37ee1..be9924f 100644 (file)
@@ -4771,21 +4771,23 @@ static void net_set_todo(struct net_device *dev)
 
 static void rollback_registered_many(struct list_head *head)
 {
-       struct net_device *dev;
+       struct net_device *dev, *tmp;
 
        BUG_ON(dev_boot_phase);
        ASSERT_RTNL();
 
-       list_for_each_entry(dev, head, unreg_list) {
+       list_for_each_entry_safe(dev, tmp, head, unreg_list) {
                /* Some devices call without registering
-                * for initialization unwind.
+                * for initialization unwind. Remove those
+                * devices and proceed with the remaining.
                 */
                if (dev->reg_state == NETREG_UNINITIALIZED) {
                        pr_debug("unregister_netdevice: device %s/%p never "
                                 "was registered\n", dev->name, dev);
 
                        WARN_ON(1);
-                       return;
+                       list_del(&dev->unreg_list);
+                       continue;
                }
 
                BUG_ON(dev->reg_state != NETREG_REGISTERED);
@@ -4901,6 +4903,33 @@ unsigned long netdev_fix_features(unsigned long features, const char *name)
 EXPORT_SYMBOL(netdev_fix_features);
 
 /**
+ *     netif_stacked_transfer_operstate -      transfer operstate
+ *     @rootdev: the root or lower level device to transfer state from
+ *     @dev: the device to transfer operstate to
+ *
+ *     Transfer operational state from root to device. This is normally
+ *     called when a stacking relationship exists between the root
+ *     device and the device(a leaf device).
+ */
+void netif_stacked_transfer_operstate(const struct net_device *rootdev,
+                                       struct net_device *dev)
+{
+       if (rootdev->operstate == IF_OPER_DORMANT)
+               netif_dormant_on(dev);
+       else
+               netif_dormant_off(dev);
+
+       if (netif_carrier_ok(rootdev)) {
+               if (!netif_carrier_ok(dev))
+                       netif_carrier_on(dev);
+       } else {
+               if (netif_carrier_ok(dev))
+                       netif_carrier_off(dev);
+       }
+}
+EXPORT_SYMBOL(netif_stacked_transfer_operstate);
+
+/**
  *     register_netdevice      - register a network device
  *     @dev: device to register
  *
@@ -5006,6 +5035,11 @@ int register_netdevice(struct net_device *dev)
                rollback_registered(dev);
                dev->reg_state = NETREG_UNREGISTERED;
        }
+       /*
+        *      Prevent userspace races by waiting until the network
+        *      device is fully setup before sending notifications.
+        */
+       rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);
 
 out:
        return ret;
@@ -5568,6 +5602,12 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
        /* Notify protocols, that a new device appeared. */
        call_netdevice_notifiers(NETDEV_REGISTER, dev);
 
+       /*
+        *      Prevent userspace races by waiting until the network
+        *      device is fully setup before sending notifications.
+        */
+       rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);
+
        synchronize_net();
        err = 0;
 out:
@@ -5736,14 +5776,13 @@ static struct pernet_operations __net_initdata netdev_net_ops = {
 
 static void __net_exit default_device_exit(struct net *net)
 {
-       struct net_device *dev;
+       struct net_device *dev, *aux;
        /*
-        * Push all migratable of the network devices back to the
+        * Push all migratable network devices back to the
         * initial network namespace
         */
        rtnl_lock();
-restart:
-       for_each_netdev(net, dev) {
+       for_each_netdev_safe(net, dev, aux) {
                int err;
                char fb_name[IFNAMSIZ];
 
@@ -5751,11 +5790,9 @@ restart:
                if (dev->features & NETIF_F_NETNS_LOCAL)
                        continue;
 
-               /* Delete virtual devices */
-               if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) {
-                       dev->rtnl_link_ops->dellink(dev, NULL);
-                       goto restart;
-               }
+               /* Leave virtual devices for the generic cleanup */
+               if (dev->rtnl_link_ops)
+                       continue;
 
                /* Push remaing network devices to init_net */
                snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex);
@@ -5765,13 +5802,37 @@ restart:
                                __func__, dev->name, err);
                        BUG();
                }
-               goto restart;
        }
        rtnl_unlock();
 }
 
+static void __net_exit default_device_exit_batch(struct list_head *net_list)
+{
+       /* At exit all network devices most be removed from a network
+        * namespace.  Do this in the reverse order of registeration.
+        * Do this across as many network namespaces as possible to
+        * improve batching efficiency.
+        */
+       struct net_device *dev;
+       struct net *net;
+       LIST_HEAD(dev_kill_list);
+
+       rtnl_lock();
+       list_for_each_entry(net, net_list, exit_list) {
+               for_each_netdev_reverse(net, dev) {
+                       if (dev->rtnl_link_ops)
+                               dev->rtnl_link_ops->dellink(dev, &dev_kill_list);
+                       else
+                               unregister_netdevice_queue(dev, &dev_kill_list);
+               }
+       }
+       unregister_netdevice_many(&dev_kill_list);
+       rtnl_unlock();
+}
+
 static struct pernet_operations __net_initdata default_device_ops = {
        .exit = default_device_exit,
+       .exit_batch = default_device_exit_batch,
 };
 
 /*