diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 158 | 
1 files changed, 62 insertions, 96 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index c29f3e1db3ca..69a3e544676c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -758,29 +758,43 @@ struct net_device *dev_get_by_name_rcu(struct net *net, const char *name)  }  EXPORT_SYMBOL(dev_get_by_name_rcu); +/* Deprecated for new users, call netdev_get_by_name() instead */ +struct net_device *dev_get_by_name(struct net *net, const char *name) +{ +	struct net_device *dev; + +	rcu_read_lock(); +	dev = dev_get_by_name_rcu(net, name); +	dev_hold(dev); +	rcu_read_unlock(); +	return dev; +} +EXPORT_SYMBOL(dev_get_by_name); +  /** - *	dev_get_by_name		- find a device by its name + *	netdev_get_by_name() - find a device by its name   *	@net: the applicable net namespace   *	@name: name to find + *	@tracker: tracking object for the acquired reference + *	@gfp: allocation flags for the tracker   *   *	Find an interface by name. This can be called from any   *	context and does its own locking. The returned handle has - *	the usage count incremented and the caller must use dev_put() to + *	the usage count incremented and the caller must use netdev_put() to   *	release it when it is no longer needed. %NULL is returned if no   *	matching device is found.   */ - -struct net_device *dev_get_by_name(struct net *net, const char *name) +struct net_device *netdev_get_by_name(struct net *net, const char *name, +				      netdevice_tracker *tracker, gfp_t gfp)  {  	struct net_device *dev; -	rcu_read_lock(); -	dev = dev_get_by_name_rcu(net, name); -	dev_hold(dev); -	rcu_read_unlock(); +	dev = dev_get_by_name(net, name); +	if (dev) +		netdev_tracker_alloc(dev, tracker, gfp);  	return dev;  } -EXPORT_SYMBOL(dev_get_by_name); +EXPORT_SYMBOL(netdev_get_by_name);  /**   *	__dev_get_by_index - find a device by its ifindex @@ -831,29 +845,42 @@ struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex)  }  EXPORT_SYMBOL(dev_get_by_index_rcu); +/* Deprecated for new users, call netdev_get_by_index() instead */ +struct net_device *dev_get_by_index(struct net *net, int ifindex) +{ +	struct net_device *dev; + +	rcu_read_lock(); +	dev = dev_get_by_index_rcu(net, ifindex); +	dev_hold(dev); +	rcu_read_unlock(); +	return dev; +} +EXPORT_SYMBOL(dev_get_by_index);  /** - *	dev_get_by_index - find a device by its ifindex + *	netdev_get_by_index() - find a device by its ifindex   *	@net: the applicable net namespace   *	@ifindex: index of device + *	@tracker: tracking object for the acquired reference + *	@gfp: allocation flags for the tracker   *   *	Search for an interface by index. Returns NULL if the device   *	is not found or a pointer to the device. The device returned has   *	had a reference added and the pointer is safe until the user calls - *	dev_put to indicate they have finished with it. + *	netdev_put() to indicate they have finished with it.   */ - -struct net_device *dev_get_by_index(struct net *net, int ifindex) +struct net_device *netdev_get_by_index(struct net *net, int ifindex, +				       netdevice_tracker *tracker, gfp_t gfp)  {  	struct net_device *dev; -	rcu_read_lock(); -	dev = dev_get_by_index_rcu(net, ifindex); -	dev_hold(dev); -	rcu_read_unlock(); +	dev = dev_get_by_index(net, ifindex); +	if (dev) +		netdev_tracker_alloc(dev, tracker, gfp);  	return dev;  } -EXPORT_SYMBOL(dev_get_by_index); +EXPORT_SYMBOL(netdev_get_by_index);  /**   *	dev_get_by_napi_id - find a device by napi_id @@ -3209,7 +3236,7 @@ static u16 skb_tx_hash(const struct net_device *dev,  	return (u16) reciprocal_scale(skb_get_hash(skb), qcount) + qoffset;  } -static void skb_warn_bad_offload(const struct sk_buff *skb) +void skb_warn_bad_offload(const struct sk_buff *skb)  {  	static const netdev_features_t null_features;  	struct net_device *dev = skb->dev; @@ -3338,74 +3365,6 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth)  	return vlan_get_protocol_and_depth(skb, type, depth);  } -/* openvswitch calls this on rx path, so we need a different check. - */ -static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path) -{ -	if (tx_path) -		return skb->ip_summed != CHECKSUM_PARTIAL && -		       skb->ip_summed != CHECKSUM_UNNECESSARY; - -	return skb->ip_summed == CHECKSUM_NONE; -} - -/** - *	__skb_gso_segment - Perform segmentation on skb. - *	@skb: buffer to segment - *	@features: features for the output path (see dev->features) - *	@tx_path: whether it is called in TX path - * - *	This function segments the given skb and returns a list of segments. - * - *	It may return NULL if the skb requires no segmentation.  This is - *	only possible when GSO is used for verifying header integrity. - * - *	Segmentation preserves SKB_GSO_CB_OFFSET bytes of previous skb cb. - */ -struct sk_buff *__skb_gso_segment(struct sk_buff *skb, -				  netdev_features_t features, bool tx_path) -{ -	struct sk_buff *segs; - -	if (unlikely(skb_needs_check(skb, tx_path))) { -		int err; - -		/* We're going to init ->check field in TCP or UDP header */ -		err = skb_cow_head(skb, 0); -		if (err < 0) -			return ERR_PTR(err); -	} - -	/* Only report GSO partial support if it will enable us to -	 * support segmentation on this frame without needing additional -	 * work. -	 */ -	if (features & NETIF_F_GSO_PARTIAL) { -		netdev_features_t partial_features = NETIF_F_GSO_ROBUST; -		struct net_device *dev = skb->dev; - -		partial_features |= dev->features & dev->gso_partial_features; -		if (!skb_gso_ok(skb, features | partial_features)) -			features &= ~NETIF_F_GSO_PARTIAL; -	} - -	BUILD_BUG_ON(SKB_GSO_CB_OFFSET + -		     sizeof(*SKB_GSO_CB(skb)) > sizeof(skb->cb)); - -	SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb); -	SKB_GSO_CB(skb)->encap_level = 0; - -	skb_reset_mac_header(skb); -	skb_reset_mac_len(skb); - -	segs = skb_mac_gso_segment(skb, features); - -	if (segs != skb && unlikely(skb_needs_check(skb, tx_path) && !IS_ERR(segs))) -		skb_warn_bad_offload(skb); - -	return segs; -} -EXPORT_SYMBOL(__skb_gso_segment);  /* Take action when hardware reception checksum errors are detected. */  #ifdef CONFIG_BUG @@ -6199,7 +6158,8 @@ restart:  	if (!napi)  		goto out; -	preempt_disable(); +	if (!IS_ENABLED(CONFIG_PREEMPT_RT)) +		preempt_disable();  	for (;;) {  		int work = 0; @@ -6241,7 +6201,8 @@ count:  		if (unlikely(need_resched())) {  			if (napi_poll)  				busy_poll_stop(napi, have_poll_lock, prefer_busy_poll, budget); -			preempt_enable(); +			if (!IS_ENABLED(CONFIG_PREEMPT_RT)) +				preempt_enable();  			rcu_read_unlock();  			cond_resched();  			if (loop_end(loop_end_arg, start_time)) @@ -6252,7 +6213,8 @@ count:  	}  	if (napi_poll)  		busy_poll_stop(napi, have_poll_lock, prefer_busy_poll, budget); -	preempt_enable(); +	if (!IS_ENABLED(CONFIG_PREEMPT_RT)) +		preempt_enable();  out:  	rcu_read_unlock();  } @@ -8822,9 +8784,11 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa,  	err = dev_pre_changeaddr_notify(dev, sa->sa_data, extack);  	if (err)  		return err; -	err = ops->ndo_set_mac_address(dev, sa); -	if (err) -		return err; +	if (memcmp(dev->dev_addr, sa->sa_data, dev->addr_len)) { +		err = ops->ndo_set_mac_address(dev, sa); +		if (err) +			return err; +	}  	dev->addr_assign_type = NET_ADDR_SET;  	call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);  	add_device_randomness(dev->dev_addr, dev->addr_len); @@ -10570,8 +10534,10 @@ void netdev_sw_irq_coalesce_default_on(struct net_device *dev)  {  	WARN_ON(dev->reg_state == NETREG_REGISTERED); -	dev->gro_flush_timeout = 20000; -	dev->napi_defer_hard_irqs = 1; +	if (!IS_ENABLED(CONFIG_PREEMPT_RT)) { +		dev->gro_flush_timeout = 20000; +		dev->napi_defer_hard_irqs = 1; +	}  }  EXPORT_SYMBOL_GPL(netdev_sw_irq_coalesce_default_on); @@ -10632,7 +10598,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,  	dev = PTR_ALIGN(p, NETDEV_ALIGN);  	dev->padded = (char *)dev - (char *)p; -	ref_tracker_dir_init(&dev->refcnt_tracker, 128); +	ref_tracker_dir_init(&dev->refcnt_tracker, 128, name);  #ifdef CONFIG_PCPU_DEV_REFCNT  	dev->pcpu_refcnt = alloc_percpu(int);  	if (!dev->pcpu_refcnt)  |