Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / net / core / dev.c
index 9d55bf5..a146bac 100644 (file)
@@ -6874,9 +6874,10 @@ static struct netdev_adjacent *__netdev_find_adj(struct net_device *adj_dev,
        return NULL;
 }
 
-static int ____netdev_has_upper_dev(struct net_device *upper_dev, void *data)
+static int ____netdev_has_upper_dev(struct net_device *upper_dev,
+                                   struct netdev_nested_priv *priv)
 {
-       struct net_device *dev = data;
+       struct net_device *dev = (struct net_device *)priv->data;
 
        return upper_dev == dev;
 }
@@ -6893,10 +6894,14 @@ static int ____netdev_has_upper_dev(struct net_device *upper_dev, void *data)
 bool netdev_has_upper_dev(struct net_device *dev,
                          struct net_device *upper_dev)
 {
+       struct netdev_nested_priv priv = {
+               .data = (void *)upper_dev,
+       };
+
        ASSERT_RTNL();
 
        return netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,
-                                            upper_dev);
+                                            &priv);
 }
 EXPORT_SYMBOL(netdev_has_upper_dev);
 
@@ -6913,8 +6918,12 @@ EXPORT_SYMBOL(netdev_has_upper_dev);
 bool netdev_has_upper_dev_all_rcu(struct net_device *dev,
                                  struct net_device *upper_dev)
 {
+       struct netdev_nested_priv priv = {
+               .data = (void *)upper_dev,
+       };
+
        return !!netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,
-                                              upper_dev);
+                                              &priv);
 }
 EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu);
 
@@ -7059,8 +7068,8 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
 
 static int __netdev_walk_all_upper_dev(struct net_device *dev,
                                       int (*fn)(struct net_device *dev,
-                                                void *data),
-                                      void *data)
+                                        struct netdev_nested_priv *priv),
+                                      struct netdev_nested_priv *priv)
 {
        struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
        struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
@@ -7072,7 +7081,7 @@ static int __netdev_walk_all_upper_dev(struct net_device *dev,
 
        while (1) {
                if (now != dev) {
-                       ret = fn(now, data);
+                       ret = fn(now, priv);
                        if (ret)
                                return ret;
                }
@@ -7108,8 +7117,8 @@ static int __netdev_walk_all_upper_dev(struct net_device *dev,
 
 int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
                                  int (*fn)(struct net_device *dev,
-                                           void *data),
-                                 void *data)
+                                           struct netdev_nested_priv *priv),
+                                 struct netdev_nested_priv *priv)
 {
        struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
        struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
@@ -7120,7 +7129,7 @@ int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
 
        while (1) {
                if (now != dev) {
-                       ret = fn(now, data);
+                       ret = fn(now, priv);
                        if (ret)
                                return ret;
                }
@@ -7156,10 +7165,15 @@ EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu);
 static bool __netdev_has_upper_dev(struct net_device *dev,
                                   struct net_device *upper_dev)
 {
+       struct netdev_nested_priv priv = {
+               .flags = 0,
+               .data = (void *)upper_dev,
+       };
+
        ASSERT_RTNL();
 
        return __netdev_walk_all_upper_dev(dev, ____netdev_has_upper_dev,
-                                          upper_dev);
+                                          &priv);
 }
 
 /**
@@ -7277,8 +7291,8 @@ static struct net_device *__netdev_next_lower_dev(struct net_device *dev,
 
 int netdev_walk_all_lower_dev(struct net_device *dev,
                              int (*fn)(struct net_device *dev,
-                                       void *data),
-                             void *data)
+                                       struct netdev_nested_priv *priv),
+                             struct netdev_nested_priv *priv)
 {
        struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
        struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
@@ -7289,7 +7303,7 @@ int netdev_walk_all_lower_dev(struct net_device *dev,
 
        while (1) {
                if (now != dev) {
-                       ret = fn(now, data);
+                       ret = fn(now, priv);
                        if (ret)
                                return ret;
                }
@@ -7324,8 +7338,8 @@ EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev);
 
 static int __netdev_walk_all_lower_dev(struct net_device *dev,
                                       int (*fn)(struct net_device *dev,
-                                                void *data),
-                                      void *data)
+                                        struct netdev_nested_priv *priv),
+                                      struct netdev_nested_priv *priv)
 {
        struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
        struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
@@ -7337,7 +7351,7 @@ static int __netdev_walk_all_lower_dev(struct net_device *dev,
 
        while (1) {
                if (now != dev) {
-                       ret = fn(now, data);
+                       ret = fn(now, priv);
                        if (ret)
                                return ret;
                }
@@ -7426,22 +7440,34 @@ static u8 __netdev_lower_depth(struct net_device *dev)
        return max_depth;
 }
 
-static int __netdev_update_upper_level(struct net_device *dev, void *data)
+static int __netdev_update_upper_level(struct net_device *dev,
+                                      struct netdev_nested_priv *__unused)
 {
        dev->upper_level = __netdev_upper_depth(dev) + 1;
        return 0;
 }
 
-static int __netdev_update_lower_level(struct net_device *dev, void *data)
+static int __netdev_update_lower_level(struct net_device *dev,
+                                      struct netdev_nested_priv *priv)
 {
        dev->lower_level = __netdev_lower_depth(dev) + 1;
+
+#ifdef CONFIG_LOCKDEP
+       if (!priv)
+               return 0;
+
+       if (priv->flags & NESTED_SYNC_IMM)
+               dev->nested_level = dev->lower_level - 1;
+       if (priv->flags & NESTED_SYNC_TODO)
+               net_unlink_todo(dev);
+#endif
        return 0;
 }
 
 int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
                                  int (*fn)(struct net_device *dev,
-                                           void *data),
-                                 void *data)
+                                           struct netdev_nested_priv *priv),
+                                 struct netdev_nested_priv *priv)
 {
        struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
        struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
@@ -7452,7 +7478,7 @@ int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
 
        while (1) {
                if (now != dev) {
-                       ret = fn(now, data);
+                       ret = fn(now, priv);
                        if (ret)
                                return ret;
                }
@@ -7712,6 +7738,7 @@ static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
 static int __netdev_upper_dev_link(struct net_device *dev,
                                   struct net_device *upper_dev, bool master,
                                   void *upper_priv, void *upper_info,
+                                  struct netdev_nested_priv *priv,
                                   struct netlink_ext_ack *extack)
 {
        struct netdev_notifier_changeupper_info changeupper_info = {
@@ -7768,9 +7795,9 @@ static int __netdev_upper_dev_link(struct net_device *dev,
        __netdev_update_upper_level(dev, NULL);
        __netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
 
-       __netdev_update_lower_level(upper_dev, NULL);
+       __netdev_update_lower_level(upper_dev, priv);
        __netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level,
-                                   NULL);
+                                   priv);
 
        return 0;
 
@@ -7795,8 +7822,13 @@ int netdev_upper_dev_link(struct net_device *dev,
                          struct net_device *upper_dev,
                          struct netlink_ext_ack *extack)
 {
+       struct netdev_nested_priv priv = {
+               .flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO,
+               .data = NULL,
+       };
+
        return __netdev_upper_dev_link(dev, upper_dev, false,
-                                      NULL, NULL, extack);
+                                      NULL, NULL, &priv, extack);
 }
 EXPORT_SYMBOL(netdev_upper_dev_link);
 
@@ -7819,21 +7851,19 @@ int netdev_master_upper_dev_link(struct net_device *dev,
                                 void *upper_priv, void *upper_info,
                                 struct netlink_ext_ack *extack)
 {
+       struct netdev_nested_priv priv = {
+               .flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO,
+               .data = NULL,
+       };
+
        return __netdev_upper_dev_link(dev, upper_dev, true,
-                                      upper_priv, upper_info, extack);
+                                      upper_priv, upper_info, &priv, extack);
 }
 EXPORT_SYMBOL(netdev_master_upper_dev_link);
 
-/**
- * netdev_upper_dev_unlink - Removes a link to upper device
- * @dev: device
- * @upper_dev: new upper device
- *
- * Removes a link to device which is upper to this one. The caller must hold
- * the RTNL lock.
- */
-void netdev_upper_dev_unlink(struct net_device *dev,
-                            struct net_device *upper_dev)
+static void __netdev_upper_dev_unlink(struct net_device *dev,
+                                     struct net_device *upper_dev,
+                                     struct netdev_nested_priv *priv)
 {
        struct netdev_notifier_changeupper_info changeupper_info = {
                .info = {
@@ -7858,9 +7888,28 @@ void netdev_upper_dev_unlink(struct net_device *dev,
        __netdev_update_upper_level(dev, NULL);
        __netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
 
-       __netdev_update_lower_level(upper_dev, NULL);
+       __netdev_update_lower_level(upper_dev, priv);
        __netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level,
-                                   NULL);
+                                   priv);
+}
+
+/**
+ * netdev_upper_dev_unlink - Removes a link to upper device
+ * @dev: device
+ * @upper_dev: new upper device
+ *
+ * Removes a link to device which is upper to this one. The caller must hold
+ * the RTNL lock.
+ */
+void netdev_upper_dev_unlink(struct net_device *dev,
+                            struct net_device *upper_dev)
+{
+       struct netdev_nested_priv priv = {
+               .flags = NESTED_SYNC_TODO,
+               .data = NULL,
+       };
+
+       __netdev_upper_dev_unlink(dev, upper_dev, &priv);
 }
 EXPORT_SYMBOL(netdev_upper_dev_unlink);
 
@@ -7896,6 +7945,10 @@ int netdev_adjacent_change_prepare(struct net_device *old_dev,
                                   struct net_device *dev,
                                   struct netlink_ext_ack *extack)
 {
+       struct netdev_nested_priv priv = {
+               .flags = 0,
+               .data = NULL,
+       };
        int err;
 
        if (!new_dev)
@@ -7903,8 +7956,8 @@ int netdev_adjacent_change_prepare(struct net_device *old_dev,
 
        if (old_dev && new_dev != old_dev)
                netdev_adjacent_dev_disable(dev, old_dev);
-
-       err = netdev_upper_dev_link(new_dev, dev, extack);
+       err = __netdev_upper_dev_link(new_dev, dev, false, NULL, NULL, &priv,
+                                     extack);
        if (err) {
                if (old_dev && new_dev != old_dev)
                        netdev_adjacent_dev_enable(dev, old_dev);
@@ -7919,6 +7972,11 @@ void netdev_adjacent_change_commit(struct net_device *old_dev,
                                   struct net_device *new_dev,
                                   struct net_device *dev)
 {
+       struct netdev_nested_priv priv = {
+               .flags = NESTED_SYNC_IMM | NESTED_SYNC_TODO,
+               .data = NULL,
+       };
+
        if (!new_dev || !old_dev)
                return;
 
@@ -7926,7 +7984,7 @@ void netdev_adjacent_change_commit(struct net_device *old_dev,
                return;
 
        netdev_adjacent_dev_enable(dev, old_dev);
-       netdev_upper_dev_unlink(old_dev, dev);
+       __netdev_upper_dev_unlink(old_dev, dev, &priv);
 }
 EXPORT_SYMBOL(netdev_adjacent_change_commit);
 
@@ -7934,13 +7992,18 @@ void netdev_adjacent_change_abort(struct net_device *old_dev,
                                  struct net_device *new_dev,
                                  struct net_device *dev)
 {
+       struct netdev_nested_priv priv = {
+               .flags = 0,
+               .data = NULL,
+       };
+
        if (!new_dev)
                return;
 
        if (old_dev && new_dev != old_dev)
                netdev_adjacent_dev_enable(dev, old_dev);
 
-       netdev_upper_dev_unlink(new_dev, dev);
+       __netdev_upper_dev_unlink(new_dev, dev, &priv);
 }
 EXPORT_SYMBOL(netdev_adjacent_change_abort);
 
@@ -10132,6 +10195,19 @@ static void netdev_wait_allrefs(struct net_device *dev)
 void netdev_run_todo(void)
 {
        struct list_head list;
+#ifdef CONFIG_LOCKDEP
+       struct list_head unlink_list;
+
+       list_replace_init(&net_unlink_list, &unlink_list);
+
+       while (!list_empty(&unlink_list)) {
+               struct net_device *dev = list_first_entry(&unlink_list,
+                                                         struct net_device,
+                                                         unlink_list);
+               list_del(&dev->unlink_list);
+               dev->nested_level = dev->lower_level - 1;
+       }
+#endif
 
        /* Snapshot list, allow later requests */
        list_replace_init(&net_todo_list, &list);
@@ -10344,6 +10420,10 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
        dev->gso_max_segs = GSO_MAX_SEGS;
        dev->upper_level = 1;
        dev->lower_level = 1;
+#ifdef CONFIG_LOCKDEP
+       dev->nested_level = 0;
+       INIT_LIST_HEAD(&dev->unlink_list);
+#endif
 
        INIT_LIST_HEAD(&dev->napi_list);
        INIT_LIST_HEAD(&dev->unreg_list);