diff options
| author | Dave Airlie <[email protected]> | 2010-08-02 10:05:18 +1000 | 
|---|---|---|
| committer | Dave Airlie <[email protected]> | 2010-08-02 10:05:24 +1000 | 
| commit | d656ae53f64cb0f01dac8a02c4d31453d64ef97c (patch) | |
| tree | cf641d4e5828b8f7c430b42657237c5daf9571fd /net/core | |
| parent | 167ffc44caaee68ea60dadf6931a4d195a4ed1f0 (diff) | |
| parent | b37fa16e78d6f9790462b3181602a26b5af36260 (diff) | |
Merge tag 'v2.6.35-rc6' into drm-radeon-next
Need this to avoid conflicts with future radeon fixes
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/dev.c | 38 | ||||
| -rw-r--r-- | net/core/ethtool.c | 41 | ||||
| -rw-r--r-- | net/core/neighbour.c | 5 | 
3 files changed, 65 insertions, 19 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 2b3bf53bc687..0ea10f849be8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1553,6 +1553,24 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)  	rcu_read_unlock();  } +/* + * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues + * greater then real_num_tx_queues stale skbs on the qdisc must be flushed. + */ +void netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) +{ +	unsigned int real_num = dev->real_num_tx_queues; + +	if (unlikely(txq > dev->num_tx_queues)) +		; +	else if (txq > real_num) +		dev->real_num_tx_queues = txq; +	else if (txq < real_num) { +		dev->real_num_tx_queues = txq; +		qdisc_reset_all_tx_gt(dev, txq); +	} +} +EXPORT_SYMBOL(netif_set_real_num_tx_queues);  static inline void __netif_reschedule(struct Qdisc *q)  { @@ -1893,8 +1911,16 @@ static int dev_gso_segment(struct sk_buff *skb)   */  static inline void skb_orphan_try(struct sk_buff *skb)  { -	if (!skb_tx(skb)->flags) +	struct sock *sk = skb->sk; + +	if (sk && !skb_tx(skb)->flags) { +		/* skb_tx_hash() wont be able to get sk. +		 * We copy sk_hash into skb->rxhash +		 */ +		if (!skb->rxhash) +			skb->rxhash = sk->sk_hash;  		skb_orphan(skb); +	}  }  int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, @@ -1980,8 +2006,7 @@ u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb)  	if (skb->sk && skb->sk->sk_hash)  		hash = skb->sk->sk_hash;  	else -		hash = (__force u16) skb->protocol; - +		hash = (__force u16) skb->protocol ^ skb->rxhash;  	hash = jhash_1word(hash, hashrnd);  	return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32); @@ -2004,12 +2029,11 @@ static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)  static struct netdev_queue *dev_pick_tx(struct net_device *dev,  					struct sk_buff *skb)  { -	u16 queue_index; +	int queue_index;  	struct sock *sk = skb->sk; -	if (sk_tx_queue_recorded(sk)) { -		queue_index = sk_tx_queue_get(sk); -	} else { +	queue_index = sk_tx_queue_get(sk); +	if (queue_index < 0) {  		const struct net_device_ops *ops = dev->netdev_ops;  		if (ops->ndo_select_queue) { diff --git a/net/core/ethtool.c b/net/core/ethtool.c index a0f4964033d2..75e4ffeb8cc9 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -318,23 +318,33 @@ out:  }  static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, -						void __user *useraddr) +						u32 cmd, void __user *useraddr)  { -	struct ethtool_rxnfc cmd; +	struct ethtool_rxnfc info; +	size_t info_size = sizeof(info);  	if (!dev->ethtool_ops->set_rxnfc)  		return -EOPNOTSUPP; -	if (copy_from_user(&cmd, useraddr, sizeof(cmd))) +	/* struct ethtool_rxnfc was originally defined for +	 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data +	 * members.  User-space might still be using that +	 * definition. */ +	if (cmd == ETHTOOL_SRXFH) +		info_size = (offsetof(struct ethtool_rxnfc, data) + +			     sizeof(info.data)); + +	if (copy_from_user(&info, useraddr, info_size))  		return -EFAULT; -	return dev->ethtool_ops->set_rxnfc(dev, &cmd); +	return dev->ethtool_ops->set_rxnfc(dev, &info);  }  static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, -						void __user *useraddr) +						u32 cmd, void __user *useraddr)  {  	struct ethtool_rxnfc info; +	size_t info_size = sizeof(info);  	const struct ethtool_ops *ops = dev->ethtool_ops;  	int ret;  	void *rule_buf = NULL; @@ -342,13 +352,22 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,  	if (!ops->get_rxnfc)  		return -EOPNOTSUPP; -	if (copy_from_user(&info, useraddr, sizeof(info))) +	/* struct ethtool_rxnfc was originally defined for +	 * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data +	 * members.  User-space might still be using that +	 * definition. */ +	if (cmd == ETHTOOL_GRXFH) +		info_size = (offsetof(struct ethtool_rxnfc, data) + +			     sizeof(info.data)); + +	if (copy_from_user(&info, useraddr, info_size))  		return -EFAULT;  	if (info.cmd == ETHTOOL_GRXCLSRLALL) {  		if (info.rule_cnt > 0) { -			rule_buf = kmalloc(info.rule_cnt * sizeof(u32), -					   GFP_USER); +			if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32)) +				rule_buf = kmalloc(info.rule_cnt * sizeof(u32), +						   GFP_USER);  			if (!rule_buf)  				return -ENOMEM;  		} @@ -359,7 +378,7 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,  		goto err_out;  	ret = -EFAULT; -	if (copy_to_user(useraddr, &info, sizeof(info))) +	if (copy_to_user(useraddr, &info, info_size))  		goto err_out;  	if (rule_buf) { @@ -1516,12 +1535,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)  	case ETHTOOL_GRXCLSRLCNT:  	case ETHTOOL_GRXCLSRULE:  	case ETHTOOL_GRXCLSRLALL: -		rc = ethtool_get_rxnfc(dev, useraddr); +		rc = ethtool_get_rxnfc(dev, ethcmd, useraddr);  		break;  	case ETHTOOL_SRXFH:  	case ETHTOOL_SRXCLSRLDEL:  	case ETHTOOL_SRXCLSRLINS: -		rc = ethtool_set_rxnfc(dev, useraddr); +		rc = ethtool_set_rxnfc(dev, ethcmd, useraddr);  		break;  	case ETHTOOL_GGRO:  		rc = ethtool_get_gro(dev, useraddr); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 6ba1c0eece03..a4e0a7482c2b 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -949,7 +949,10 @@ static void neigh_update_hhs(struct neighbour *neigh)  {  	struct hh_cache *hh;  	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *) -		= neigh->dev->header_ops->cache_update; +		= NULL; + +	if (neigh->dev->header_ops) +		update = neigh->dev->header_ops->cache_update;  	if (update) {  		for (hh = neigh->hh; hh; hh = hh->hh_next) {  |