diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 620 | 
1 files changed, 465 insertions, 155 deletions
| diff --git a/net/core/dev.c b/net/core/dev.c index bf3ed413abaf..96afd464284a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -146,6 +146,7 @@  #include "net-sysfs.h"  #define MAX_GRO_SKBS 8 +#define MAX_NEST_DEV 8  /* This should be increased if a protocol with a bigger head is added. */  #define GRO_MAX_HEAD (MAX_HEADER + 128) @@ -276,88 +277,6 @@ static RAW_NOTIFIER_HEAD(netdev_chain);  DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data);  EXPORT_PER_CPU_SYMBOL(softnet_data); -#ifdef CONFIG_LOCKDEP -/* - * register_netdevice() inits txq->_xmit_lock and sets lockdep class - * according to dev->type - */ -static const unsigned short netdev_lock_type[] = { -	 ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_EETHER, ARPHRD_AX25, -	 ARPHRD_PRONET, ARPHRD_CHAOS, ARPHRD_IEEE802, ARPHRD_ARCNET, -	 ARPHRD_APPLETLK, ARPHRD_DLCI, ARPHRD_ATM, ARPHRD_METRICOM, -	 ARPHRD_IEEE1394, ARPHRD_EUI64, ARPHRD_INFINIBAND, ARPHRD_SLIP, -	 ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6, ARPHRD_RSRVD, -	 ARPHRD_ADAPT, ARPHRD_ROSE, ARPHRD_X25, ARPHRD_HWX25, -	 ARPHRD_PPP, ARPHRD_CISCO, ARPHRD_LAPB, ARPHRD_DDCMP, -	 ARPHRD_RAWHDLC, ARPHRD_TUNNEL, ARPHRD_TUNNEL6, ARPHRD_FRAD, -	 ARPHRD_SKIP, ARPHRD_LOOPBACK, ARPHRD_LOCALTLK, ARPHRD_FDDI, -	 ARPHRD_BIF, ARPHRD_SIT, ARPHRD_IPDDP, ARPHRD_IPGRE, -	 ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET, -	 ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, -	 ARPHRD_FCFABRIC, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM, -	 ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, ARPHRD_PHONET_PIPE, -	 ARPHRD_IEEE802154, ARPHRD_VOID, ARPHRD_NONE}; - -static const char *const netdev_lock_name[] = { -	"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25", -	"_xmit_PRONET", "_xmit_CHAOS", "_xmit_IEEE802", "_xmit_ARCNET", -	"_xmit_APPLETLK", "_xmit_DLCI", "_xmit_ATM", "_xmit_METRICOM", -	"_xmit_IEEE1394", "_xmit_EUI64", "_xmit_INFINIBAND", "_xmit_SLIP", -	"_xmit_CSLIP", "_xmit_SLIP6", "_xmit_CSLIP6", "_xmit_RSRVD", -	"_xmit_ADAPT", "_xmit_ROSE", "_xmit_X25", "_xmit_HWX25", -	"_xmit_PPP", "_xmit_CISCO", "_xmit_LAPB", "_xmit_DDCMP", -	"_xmit_RAWHDLC", "_xmit_TUNNEL", "_xmit_TUNNEL6", "_xmit_FRAD", -	"_xmit_SKIP", "_xmit_LOOPBACK", "_xmit_LOCALTLK", "_xmit_FDDI", -	"_xmit_BIF", "_xmit_SIT", "_xmit_IPDDP", "_xmit_IPGRE", -	"_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET", -	"_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", -	"_xmit_FCFABRIC", "_xmit_IEEE80211", "_xmit_IEEE80211_PRISM", -	"_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", "_xmit_PHONET_PIPE", -	"_xmit_IEEE802154", "_xmit_VOID", "_xmit_NONE"}; - -static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; -static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)]; - -static inline unsigned short netdev_lock_pos(unsigned short dev_type) -{ -	int i; - -	for (i = 0; i < ARRAY_SIZE(netdev_lock_type); i++) -		if (netdev_lock_type[i] == dev_type) -			return i; -	/* the last key is used by default */ -	return ARRAY_SIZE(netdev_lock_type) - 1; -} - -static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock, -						 unsigned short dev_type) -{ -	int i; - -	i = netdev_lock_pos(dev_type); -	lockdep_set_class_and_name(lock, &netdev_xmit_lock_key[i], -				   netdev_lock_name[i]); -} - -static inline void netdev_set_addr_lockdep_class(struct net_device *dev) -{ -	int i; - -	i = netdev_lock_pos(dev->type); -	lockdep_set_class_and_name(&dev->addr_list_lock, -				   &netdev_addr_lock_key[i], -				   netdev_lock_name[i]); -} -#else -static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock, -						 unsigned short dev_type) -{ -} -static inline void netdev_set_addr_lockdep_class(struct net_device *dev) -{ -} -#endif -  /*******************************************************************************   *   *		Protocol management and registration routines @@ -6489,6 +6408,9 @@ struct netdev_adjacent {  	/* upper master flag, there can only be one master device per list */  	bool master; +	/* lookup ignore flag */ +	bool ignore; +  	/* counter for the number of times this device was added to us */  	u16 ref_nr; @@ -6511,7 +6433,7 @@ 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, void *data)  {  	struct net_device *dev = data; @@ -6532,7 +6454,7 @@ bool netdev_has_upper_dev(struct net_device *dev,  {  	ASSERT_RTNL(); -	return netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, +	return netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,  					     upper_dev);  }  EXPORT_SYMBOL(netdev_has_upper_dev); @@ -6550,7 +6472,7 @@ EXPORT_SYMBOL(netdev_has_upper_dev);  bool netdev_has_upper_dev_all_rcu(struct net_device *dev,  				  struct net_device *upper_dev)  { -	return !!netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, +	return !!netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,  					       upper_dev);  }  EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu); @@ -6594,6 +6516,22 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev)  }  EXPORT_SYMBOL(netdev_master_upper_dev_get); +static struct net_device *__netdev_master_upper_dev_get(struct net_device *dev) +{ +	struct netdev_adjacent *upper; + +	ASSERT_RTNL(); + +	if (list_empty(&dev->adj_list.upper)) +		return NULL; + +	upper = list_first_entry(&dev->adj_list.upper, +				 struct netdev_adjacent, list); +	if (likely(upper->master) && !upper->ignore) +		return upper->dev; +	return NULL; +} +  /**   * netdev_has_any_lower_dev - Check if device is linked to some device   * @dev: device @@ -6644,6 +6582,23 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,  }  EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu); +static struct net_device *__netdev_next_upper_dev(struct net_device *dev, +						  struct list_head **iter, +						  bool *ignore) +{ +	struct netdev_adjacent *upper; + +	upper = list_entry((*iter)->next, struct netdev_adjacent, list); + +	if (&upper->list == &dev->adj_list.upper) +		return NULL; + +	*iter = &upper->list; +	*ignore = upper->ignore; + +	return upper->dev; +} +  static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,  						    struct list_head **iter)  { @@ -6661,34 +6616,111 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,  	return upper->dev;  } +static int __netdev_walk_all_upper_dev(struct net_device *dev, +				       int (*fn)(struct net_device *dev, +						 void *data), +				       void *data) +{ +	struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; +	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; +	int ret, cur = 0; +	bool ignore; + +	now = dev; +	iter = &dev->adj_list.upper; + +	while (1) { +		if (now != dev) { +			ret = fn(now, data); +			if (ret) +				return ret; +		} + +		next = NULL; +		while (1) { +			udev = __netdev_next_upper_dev(now, &iter, &ignore); +			if (!udev) +				break; +			if (ignore) +				continue; + +			next = udev; +			niter = &udev->adj_list.upper; +			dev_stack[cur] = now; +			iter_stack[cur++] = iter; +			break; +		} + +		if (!next) { +			if (!cur) +				return 0; +			next = dev_stack[--cur]; +			niter = iter_stack[cur]; +		} + +		now = next; +		iter = niter; +	} + +	return 0; +} +  int netdev_walk_all_upper_dev_rcu(struct net_device *dev,  				  int (*fn)(struct net_device *dev,  					    void *data),  				  void *data)  { -	struct net_device *udev; -	struct list_head *iter; -	int ret; +	struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; +	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; +	int ret, cur = 0; -	for (iter = &dev->adj_list.upper, -	     udev = netdev_next_upper_dev_rcu(dev, &iter); -	     udev; -	     udev = netdev_next_upper_dev_rcu(dev, &iter)) { -		/* first is the upper device itself */ -		ret = fn(udev, data); -		if (ret) -			return ret; +	now = dev; +	iter = &dev->adj_list.upper; -		/* then look at all of its upper devices */ -		ret = netdev_walk_all_upper_dev_rcu(udev, fn, data); -		if (ret) -			return ret; +	while (1) { +		if (now != dev) { +			ret = fn(now, data); +			if (ret) +				return ret; +		} + +		next = NULL; +		while (1) { +			udev = netdev_next_upper_dev_rcu(now, &iter); +			if (!udev) +				break; + +			next = udev; +			niter = &udev->adj_list.upper; +			dev_stack[cur] = now; +			iter_stack[cur++] = iter; +			break; +		} + +		if (!next) { +			if (!cur) +				return 0; +			next = dev_stack[--cur]; +			niter = iter_stack[cur]; +		} + +		now = next; +		iter = niter;  	}  	return 0;  }  EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu); +static bool __netdev_has_upper_dev(struct net_device *dev, +				   struct net_device *upper_dev) +{ +	ASSERT_RTNL(); + +	return __netdev_walk_all_upper_dev(dev, ____netdev_has_upper_dev, +					   upper_dev); +} +  /**   * netdev_lower_get_next_private - Get the next ->private from the   *				   lower neighbour list @@ -6785,34 +6817,119 @@ static struct net_device *netdev_next_lower_dev(struct net_device *dev,  	return lower->dev;  } +static struct net_device *__netdev_next_lower_dev(struct net_device *dev, +						  struct list_head **iter, +						  bool *ignore) +{ +	struct netdev_adjacent *lower; + +	lower = list_entry((*iter)->next, struct netdev_adjacent, list); + +	if (&lower->list == &dev->adj_list.lower) +		return NULL; + +	*iter = &lower->list; +	*ignore = lower->ignore; + +	return lower->dev; +} +  int netdev_walk_all_lower_dev(struct net_device *dev,  			      int (*fn)(struct net_device *dev,  					void *data),  			      void *data)  { -	struct net_device *ldev; -	struct list_head *iter; -	int ret; +	struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; +	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; +	int ret, cur = 0; -	for (iter = &dev->adj_list.lower, -	     ldev = netdev_next_lower_dev(dev, &iter); -	     ldev; -	     ldev = netdev_next_lower_dev(dev, &iter)) { -		/* first is the lower device itself */ -		ret = fn(ldev, data); -		if (ret) -			return ret; +	now = dev; +	iter = &dev->adj_list.lower; -		/* then look at all of its lower devices */ -		ret = netdev_walk_all_lower_dev(ldev, fn, data); -		if (ret) -			return ret; +	while (1) { +		if (now != dev) { +			ret = fn(now, data); +			if (ret) +				return ret; +		} + +		next = NULL; +		while (1) { +			ldev = netdev_next_lower_dev(now, &iter); +			if (!ldev) +				break; + +			next = ldev; +			niter = &ldev->adj_list.lower; +			dev_stack[cur] = now; +			iter_stack[cur++] = iter; +			break; +		} + +		if (!next) { +			if (!cur) +				return 0; +			next = dev_stack[--cur]; +			niter = iter_stack[cur]; +		} + +		now = next; +		iter = niter;  	}  	return 0;  }  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 net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; +	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; +	int ret, cur = 0; +	bool ignore; + +	now = dev; +	iter = &dev->adj_list.lower; + +	while (1) { +		if (now != dev) { +			ret = fn(now, data); +			if (ret) +				return ret; +		} + +		next = NULL; +		while (1) { +			ldev = __netdev_next_lower_dev(now, &iter, &ignore); +			if (!ldev) +				break; +			if (ignore) +				continue; + +			next = ldev; +			niter = &ldev->adj_list.lower; +			dev_stack[cur] = now; +			iter_stack[cur++] = iter; +			break; +		} + +		if (!next) { +			if (!cur) +				return 0; +			next = dev_stack[--cur]; +			niter = iter_stack[cur]; +		} + +		now = next; +		iter = niter; +	} + +	return 0; +} +  static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,  						    struct list_head **iter)  { @@ -6827,28 +6944,99 @@ static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,  	return lower->dev;  } -int netdev_walk_all_lower_dev_rcu(struct net_device *dev, -				  int (*fn)(struct net_device *dev, -					    void *data), -				  void *data) +static u8 __netdev_upper_depth(struct net_device *dev) +{ +	struct net_device *udev; +	struct list_head *iter; +	u8 max_depth = 0; +	bool ignore; + +	for (iter = &dev->adj_list.upper, +	     udev = __netdev_next_upper_dev(dev, &iter, &ignore); +	     udev; +	     udev = __netdev_next_upper_dev(dev, &iter, &ignore)) { +		if (ignore) +			continue; +		if (max_depth < udev->upper_level) +			max_depth = udev->upper_level; +	} + +	return max_depth; +} + +static u8 __netdev_lower_depth(struct net_device *dev)  {  	struct net_device *ldev;  	struct list_head *iter; -	int ret; +	u8 max_depth = 0; +	bool ignore;  	for (iter = &dev->adj_list.lower, -	     ldev = netdev_next_lower_dev_rcu(dev, &iter); +	     ldev = __netdev_next_lower_dev(dev, &iter, &ignore);  	     ldev; -	     ldev = netdev_next_lower_dev_rcu(dev, &iter)) { -		/* first is the lower device itself */ -		ret = fn(ldev, data); -		if (ret) -			return ret; +	     ldev = __netdev_next_lower_dev(dev, &iter, &ignore)) { +		if (ignore) +			continue; +		if (max_depth < ldev->lower_level) +			max_depth = ldev->lower_level; +	} -		/* then look at all of its lower devices */ -		ret = netdev_walk_all_lower_dev_rcu(ldev, fn, data); -		if (ret) -			return ret; +	return max_depth; +} + +static int __netdev_update_upper_level(struct net_device *dev, void *data) +{ +	dev->upper_level = __netdev_upper_depth(dev) + 1; +	return 0; +} + +static int __netdev_update_lower_level(struct net_device *dev, void *data) +{ +	dev->lower_level = __netdev_lower_depth(dev) + 1; +	return 0; +} + +int netdev_walk_all_lower_dev_rcu(struct net_device *dev, +				  int (*fn)(struct net_device *dev, +					    void *data), +				  void *data) +{ +	struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; +	struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; +	int ret, cur = 0; + +	now = dev; +	iter = &dev->adj_list.lower; + +	while (1) { +		if (now != dev) { +			ret = fn(now, data); +			if (ret) +				return ret; +		} + +		next = NULL; +		while (1) { +			ldev = netdev_next_lower_dev_rcu(now, &iter); +			if (!ldev) +				break; + +			next = ldev; +			niter = &ldev->adj_list.lower; +			dev_stack[cur] = now; +			iter_stack[cur++] = iter; +			break; +		} + +		if (!next) { +			if (!cur) +				return 0; +			next = dev_stack[--cur]; +			niter = iter_stack[cur]; +		} + +		now = next; +		iter = niter;  	}  	return 0; @@ -6952,6 +7140,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,  	adj->master = master;  	adj->ref_nr = 1;  	adj->private = private; +	adj->ignore = false;  	dev_hold(adj_dev);  	pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d; dev_hold on %s\n", @@ -7102,14 +7291,17 @@ static int __netdev_upper_dev_link(struct net_device *dev,  		return -EBUSY;  	/* To prevent loops, check if dev is not upper device to upper_dev. */ -	if (netdev_has_upper_dev(upper_dev, dev)) +	if (__netdev_has_upper_dev(upper_dev, dev))  		return -EBUSY; +	if ((dev->lower_level + upper_dev->upper_level) > MAX_NEST_DEV) +		return -EMLINK; +  	if (!master) { -		if (netdev_has_upper_dev(dev, upper_dev)) +		if (__netdev_has_upper_dev(dev, upper_dev))  			return -EEXIST;  	} else { -		master_dev = netdev_master_upper_dev_get(dev); +		master_dev = __netdev_master_upper_dev_get(dev);  		if (master_dev)  			return master_dev == upper_dev ? -EEXIST : -EBUSY;  	} @@ -7131,6 +7323,13 @@ static int __netdev_upper_dev_link(struct net_device *dev,  	if (ret)  		goto rollback; +	__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_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, +				    NULL); +  	return 0;  rollback: @@ -7213,9 +7412,96 @@ void netdev_upper_dev_unlink(struct net_device *dev,  	call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,  				      &changeupper_info.info); + +	__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_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, +				    NULL);  }  EXPORT_SYMBOL(netdev_upper_dev_unlink); +static void __netdev_adjacent_dev_set(struct net_device *upper_dev, +				      struct net_device *lower_dev, +				      bool val) +{ +	struct netdev_adjacent *adj; + +	adj = __netdev_find_adj(lower_dev, &upper_dev->adj_list.lower); +	if (adj) +		adj->ignore = val; + +	adj = __netdev_find_adj(upper_dev, &lower_dev->adj_list.upper); +	if (adj) +		adj->ignore = val; +} + +static void netdev_adjacent_dev_disable(struct net_device *upper_dev, +					struct net_device *lower_dev) +{ +	__netdev_adjacent_dev_set(upper_dev, lower_dev, true); +} + +static void netdev_adjacent_dev_enable(struct net_device *upper_dev, +				       struct net_device *lower_dev) +{ +	__netdev_adjacent_dev_set(upper_dev, lower_dev, false); +} + +int netdev_adjacent_change_prepare(struct net_device *old_dev, +				   struct net_device *new_dev, +				   struct net_device *dev, +				   struct netlink_ext_ack *extack) +{ +	int err; + +	if (!new_dev) +		return 0; + +	if (old_dev && new_dev != old_dev) +		netdev_adjacent_dev_disable(dev, old_dev); + +	err = netdev_upper_dev_link(new_dev, dev, extack); +	if (err) { +		if (old_dev && new_dev != old_dev) +			netdev_adjacent_dev_enable(dev, old_dev); +		return err; +	} + +	return 0; +} +EXPORT_SYMBOL(netdev_adjacent_change_prepare); + +void netdev_adjacent_change_commit(struct net_device *old_dev, +				   struct net_device *new_dev, +				   struct net_device *dev) +{ +	if (!new_dev || !old_dev) +		return; + +	if (new_dev == old_dev) +		return; + +	netdev_adjacent_dev_enable(dev, old_dev); +	netdev_upper_dev_unlink(old_dev, dev); +} +EXPORT_SYMBOL(netdev_adjacent_change_commit); + +void netdev_adjacent_change_abort(struct net_device *old_dev, +				  struct net_device *new_dev, +				  struct net_device *dev) +{ +	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); +} +EXPORT_SYMBOL(netdev_adjacent_change_abort); +  /**   * netdev_bonding_info_change - Dispatch event about slave change   * @dev: device @@ -7329,25 +7615,6 @@ void *netdev_lower_dev_get_private(struct net_device *dev,  EXPORT_SYMBOL(netdev_lower_dev_get_private); -int dev_get_nest_level(struct net_device *dev) -{ -	struct net_device *lower = NULL; -	struct list_head *iter; -	int max_nest = -1; -	int nest; - -	ASSERT_RTNL(); - -	netdev_for_each_lower_dev(dev, lower, iter) { -		nest = dev_get_nest_level(lower); -		if (max_nest < nest) -			max_nest = nest; -	} - -	return max_nest + 1; -} -EXPORT_SYMBOL(dev_get_nest_level); -  /**   * netdev_lower_change - Dispatch event about lower device state change   * @lower_dev: device @@ -8619,7 +8886,7 @@ static void netdev_init_one_queue(struct net_device *dev,  {  	/* Initialize queue lock */  	spin_lock_init(&queue->_xmit_lock); -	netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type); +	lockdep_set_class(&queue->_xmit_lock, &dev->qdisc_xmit_lock_key);  	queue->xmit_lock_owner = -1;  	netdev_queue_numa_node_write(queue, NUMA_NO_NODE);  	queue->dev = dev; @@ -8666,6 +8933,43 @@ void netif_tx_stop_all_queues(struct net_device *dev)  }  EXPORT_SYMBOL(netif_tx_stop_all_queues); +static void netdev_register_lockdep_key(struct net_device *dev) +{ +	lockdep_register_key(&dev->qdisc_tx_busylock_key); +	lockdep_register_key(&dev->qdisc_running_key); +	lockdep_register_key(&dev->qdisc_xmit_lock_key); +	lockdep_register_key(&dev->addr_list_lock_key); +} + +static void netdev_unregister_lockdep_key(struct net_device *dev) +{ +	lockdep_unregister_key(&dev->qdisc_tx_busylock_key); +	lockdep_unregister_key(&dev->qdisc_running_key); +	lockdep_unregister_key(&dev->qdisc_xmit_lock_key); +	lockdep_unregister_key(&dev->addr_list_lock_key); +} + +void netdev_update_lockdep_key(struct net_device *dev) +{ +	struct netdev_queue *queue; +	int i; + +	lockdep_unregister_key(&dev->qdisc_xmit_lock_key); +	lockdep_unregister_key(&dev->addr_list_lock_key); + +	lockdep_register_key(&dev->qdisc_xmit_lock_key); +	lockdep_register_key(&dev->addr_list_lock_key); + +	lockdep_set_class(&dev->addr_list_lock, &dev->addr_list_lock_key); +	for (i = 0; i < dev->num_tx_queues; i++) { +		queue = netdev_get_tx_queue(dev, i); + +		lockdep_set_class(&queue->_xmit_lock, +				  &dev->qdisc_xmit_lock_key); +	} +} +EXPORT_SYMBOL(netdev_update_lockdep_key); +  /**   *	register_netdevice	- register a network device   *	@dev: device to register @@ -8700,7 +9004,7 @@ int register_netdevice(struct net_device *dev)  	BUG_ON(!net);  	spin_lock_init(&dev->addr_list_lock); -	netdev_set_addr_lockdep_class(dev); +	lockdep_set_class(&dev->addr_list_lock, &dev->addr_list_lock_key);  	ret = dev_get_valid_name(net, dev, dev->name);  	if (ret < 0) @@ -9210,8 +9514,12 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,  	dev_net_set(dev, &init_net); +	netdev_register_lockdep_key(dev); +  	dev->gso_max_size = GSO_MAX_SIZE;  	dev->gso_max_segs = GSO_MAX_SEGS; +	dev->upper_level = 1; +	dev->lower_level = 1;  	INIT_LIST_HEAD(&dev->napi_list);  	INIT_LIST_HEAD(&dev->unreg_list); @@ -9292,6 +9600,8 @@ void free_netdev(struct net_device *dev)  	free_percpu(dev->pcpu_refcnt);  	dev->pcpu_refcnt = NULL; +	netdev_unregister_lockdep_key(dev); +  	/*  Compatibility with error handling in drivers */  	if (dev->reg_state == NETREG_UNINITIALIZED) {  		netdev_freemem(dev); @@ -9460,7 +9770,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char  	call_netdevice_notifiers(NETDEV_UNREGISTER, dev);  	rcu_barrier(); -	new_nsid = peernet2id_alloc(dev_net(dev), net); +	new_nsid = peernet2id_alloc(dev_net(dev), net, GFP_KERNEL);  	/* If there is an ifindex conflict assign a new one */  	if (__dev_get_by_index(net, dev->ifindex))  		new_ifindex = dev_new_index(net); | 

