diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 164 | 
1 files changed, 122 insertions, 42 deletions
| diff --git a/net/core/dev.c b/net/core/dev.c index 266073e300b5..4906b44af850 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6812,9 +6812,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;  } @@ -6831,10 +6832,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); @@ -6851,8 +6856,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); @@ -6997,8 +7006,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]; @@ -7010,7 +7019,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;  		} @@ -7046,8 +7055,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]; @@ -7058,7 +7067,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;  		} @@ -7094,10 +7103,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);  }  /** @@ -7215,8 +7229,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]; @@ -7227,7 +7241,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;  		} @@ -7262,8 +7276,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]; @@ -7275,7 +7289,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;  		} @@ -7364,22 +7378,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]; @@ -7390,7 +7416,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;  		} @@ -7650,6 +7676,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 = { @@ -7706,9 +7733,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; @@ -7733,8 +7760,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); @@ -7757,21 +7789,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 = { @@ -7796,9 +7826,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); @@ -7834,6 +7883,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) @@ -7841,8 +7894,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); @@ -7857,6 +7910,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; @@ -7864,7 +7922,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); @@ -7872,13 +7930,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); @@ -10062,6 +10125,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); @@ -10274,6 +10350,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); |