diff options
Diffstat (limited to 'drivers/infiniband/ulp/ipoib/ipoib_main.c')
| -rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 93 | 
1 files changed, 44 insertions, 49 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 3e2085a3ee4..1e19b5ae7c4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -546,15 +546,15 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,  	struct ipoib_neigh *neigh;  	unsigned long flags; +	spin_lock_irqsave(&priv->lock, flags);  	neigh = ipoib_neigh_alloc(daddr, dev);  	if (!neigh) { +		spin_unlock_irqrestore(&priv->lock, flags);  		++dev->stats.tx_dropped;  		dev_kfree_skb_any(skb);  		return;  	} -	spin_lock_irqsave(&priv->lock, flags); -  	path = __path_find(dev, daddr + 4);  	if (!path) {  		path = path_rec_create(dev, daddr + 4); @@ -863,10 +863,10 @@ static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv)  	if (test_bit(IPOIB_STOP_NEIGH_GC, &priv->flags))  		return; -	write_lock_bh(&ntbl->rwlock); +	spin_lock_irqsave(&priv->lock, flags);  	htbl = rcu_dereference_protected(ntbl->htbl, -					 lockdep_is_held(&ntbl->rwlock)); +					 lockdep_is_held(&priv->lock));  	if (!htbl)  		goto out_unlock; @@ -883,16 +883,14 @@ static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv)  		struct ipoib_neigh __rcu **np = &htbl->buckets[i];  		while ((neigh = rcu_dereference_protected(*np, -							  lockdep_is_held(&ntbl->rwlock))) != NULL) { +							  lockdep_is_held(&priv->lock))) != NULL) {  			/* was the neigh idle for two GC periods */  			if (time_after(neigh_obsolete, neigh->alive)) {  				rcu_assign_pointer(*np,  						   rcu_dereference_protected(neigh->hnext, -									     lockdep_is_held(&ntbl->rwlock))); +									     lockdep_is_held(&priv->lock)));  				/* remove from path/mc list */ -				spin_lock_irqsave(&priv->lock, flags);  				list_del(&neigh->list); -				spin_unlock_irqrestore(&priv->lock, flags);  				call_rcu(&neigh->rcu, ipoib_neigh_reclaim);  			} else {  				np = &neigh->hnext; @@ -902,7 +900,7 @@ static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv)  	}  out_unlock: -	write_unlock_bh(&ntbl->rwlock); +	spin_unlock_irqrestore(&priv->lock, flags);  }  static void ipoib_reap_neigh(struct work_struct *work) @@ -947,10 +945,8 @@ struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr,  	struct ipoib_neigh *neigh;  	u32 hash_val; -	write_lock_bh(&ntbl->rwlock); -  	htbl = rcu_dereference_protected(ntbl->htbl, -					 lockdep_is_held(&ntbl->rwlock)); +					 lockdep_is_held(&priv->lock));  	if (!htbl) {  		neigh = NULL;  		goto out_unlock; @@ -961,10 +957,10 @@ struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr,  	 */  	hash_val = ipoib_addr_hash(htbl, daddr);  	for (neigh = rcu_dereference_protected(htbl->buckets[hash_val], -					       lockdep_is_held(&ntbl->rwlock)); +					       lockdep_is_held(&priv->lock));  	     neigh != NULL;  	     neigh = rcu_dereference_protected(neigh->hnext, -					       lockdep_is_held(&ntbl->rwlock))) { +					       lockdep_is_held(&priv->lock))) {  		if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) {  			/* found, take one ref on behalf of the caller */  			if (!atomic_inc_not_zero(&neigh->refcnt)) { @@ -987,12 +983,11 @@ struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr,  	/* put in hash */  	rcu_assign_pointer(neigh->hnext,  			   rcu_dereference_protected(htbl->buckets[hash_val], -						     lockdep_is_held(&ntbl->rwlock))); +						     lockdep_is_held(&priv->lock)));  	rcu_assign_pointer(htbl->buckets[hash_val], neigh);  	atomic_inc(&ntbl->entries);  out_unlock: -	write_unlock_bh(&ntbl->rwlock);  	return neigh;  } @@ -1040,35 +1035,29 @@ void ipoib_neigh_free(struct ipoib_neigh *neigh)  	struct ipoib_neigh *n;  	u32 hash_val; -	write_lock_bh(&ntbl->rwlock); -  	htbl = rcu_dereference_protected(ntbl->htbl, -					lockdep_is_held(&ntbl->rwlock)); +					lockdep_is_held(&priv->lock));  	if (!htbl) -		goto out_unlock; +		return;  	hash_val = ipoib_addr_hash(htbl, neigh->daddr);  	np = &htbl->buckets[hash_val];  	for (n = rcu_dereference_protected(*np, -					    lockdep_is_held(&ntbl->rwlock)); +					    lockdep_is_held(&priv->lock));  	     n != NULL;  	     n = rcu_dereference_protected(*np, -					lockdep_is_held(&ntbl->rwlock))) { +					lockdep_is_held(&priv->lock))) {  		if (n == neigh) {  			/* found */  			rcu_assign_pointer(*np,  					   rcu_dereference_protected(neigh->hnext, -								     lockdep_is_held(&ntbl->rwlock))); +								     lockdep_is_held(&priv->lock)));  			call_rcu(&neigh->rcu, ipoib_neigh_reclaim); -			goto out_unlock; +			return;  		} else {  			np = &n->hnext;  		}  	} - -out_unlock: -	write_unlock_bh(&ntbl->rwlock); -  }  static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) @@ -1080,7 +1069,6 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv)  	clear_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags);  	ntbl->htbl = NULL; -	rwlock_init(&ntbl->rwlock);  	htbl = kzalloc(sizeof(*htbl), GFP_KERNEL);  	if (!htbl)  		return -ENOMEM; @@ -1095,6 +1083,7 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv)  	htbl->mask = (size - 1);  	htbl->buckets = buckets;  	ntbl->htbl = htbl; +	htbl->ntbl = ntbl;  	atomic_set(&ntbl->entries, 0);  	/* start garbage collection */ @@ -1111,9 +1100,11 @@ static void neigh_hash_free_rcu(struct rcu_head *head)  						    struct ipoib_neigh_hash,  						    rcu);  	struct ipoib_neigh __rcu **buckets = htbl->buckets; +	struct ipoib_neigh_table *ntbl = htbl->ntbl;  	kfree(buckets);  	kfree(htbl); +	complete(&ntbl->deleted);  }  void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid) @@ -1125,10 +1116,10 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid)  	int i;  	/* remove all neigh connected to a given path or mcast */ -	write_lock_bh(&ntbl->rwlock); +	spin_lock_irqsave(&priv->lock, flags);  	htbl = rcu_dereference_protected(ntbl->htbl, -					 lockdep_is_held(&ntbl->rwlock)); +					 lockdep_is_held(&priv->lock));  	if (!htbl)  		goto out_unlock; @@ -1138,16 +1129,14 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid)  		struct ipoib_neigh __rcu **np = &htbl->buckets[i];  		while ((neigh = rcu_dereference_protected(*np, -							  lockdep_is_held(&ntbl->rwlock))) != NULL) { +							  lockdep_is_held(&priv->lock))) != NULL) {  			/* delete neighs belong to this parent */  			if (!memcmp(gid, neigh->daddr + 4, sizeof (union ib_gid))) {  				rcu_assign_pointer(*np,  						   rcu_dereference_protected(neigh->hnext, -									     lockdep_is_held(&ntbl->rwlock))); +									     lockdep_is_held(&priv->lock)));  				/* remove from parent list */ -				spin_lock_irqsave(&priv->lock, flags);  				list_del(&neigh->list); -				spin_unlock_irqrestore(&priv->lock, flags);  				call_rcu(&neigh->rcu, ipoib_neigh_reclaim);  			} else {  				np = &neigh->hnext; @@ -1156,7 +1145,7 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid)  		}  	}  out_unlock: -	write_unlock_bh(&ntbl->rwlock); +	spin_unlock_irqrestore(&priv->lock, flags);  }  static void ipoib_flush_neighs(struct ipoib_dev_priv *priv) @@ -1164,37 +1153,44 @@ static void ipoib_flush_neighs(struct ipoib_dev_priv *priv)  	struct ipoib_neigh_table *ntbl = &priv->ntbl;  	struct ipoib_neigh_hash *htbl;  	unsigned long flags; -	int i; +	int i, wait_flushed = 0; -	write_lock_bh(&ntbl->rwlock); +	init_completion(&priv->ntbl.flushed); + +	spin_lock_irqsave(&priv->lock, flags);  	htbl = rcu_dereference_protected(ntbl->htbl, -					lockdep_is_held(&ntbl->rwlock)); +					lockdep_is_held(&priv->lock));  	if (!htbl)  		goto out_unlock; +	wait_flushed = atomic_read(&priv->ntbl.entries); +	if (!wait_flushed) +		goto free_htbl; +  	for (i = 0; i < htbl->size; i++) {  		struct ipoib_neigh *neigh;  		struct ipoib_neigh __rcu **np = &htbl->buckets[i];  		while ((neigh = rcu_dereference_protected(*np, -							  lockdep_is_held(&ntbl->rwlock))) != NULL) { +				       lockdep_is_held(&priv->lock))) != NULL) {  			rcu_assign_pointer(*np,  					   rcu_dereference_protected(neigh->hnext, -								     lockdep_is_held(&ntbl->rwlock))); +								     lockdep_is_held(&priv->lock)));  			/* remove from path/mc list */ -			spin_lock_irqsave(&priv->lock, flags);  			list_del(&neigh->list); -			spin_unlock_irqrestore(&priv->lock, flags);  			call_rcu(&neigh->rcu, ipoib_neigh_reclaim);  		}  	} +free_htbl:  	rcu_assign_pointer(ntbl->htbl, NULL);  	call_rcu(&htbl->rcu, neigh_hash_free_rcu);  out_unlock: -	write_unlock_bh(&ntbl->rwlock); +	spin_unlock_irqrestore(&priv->lock, flags); +	if (wait_flushed) +		wait_for_completion(&priv->ntbl.flushed);  }  static void ipoib_neigh_hash_uninit(struct net_device *dev) @@ -1203,7 +1199,7 @@ static void ipoib_neigh_hash_uninit(struct net_device *dev)  	int stopped;  	ipoib_dbg(priv, "ipoib_neigh_hash_uninit\n"); -	init_completion(&priv->ntbl.flushed); +	init_completion(&priv->ntbl.deleted);  	set_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags);  	/* Stop GC if called at init fail need to cancel work */ @@ -1211,10 +1207,9 @@ static void ipoib_neigh_hash_uninit(struct net_device *dev)  	if (!stopped)  		cancel_delayed_work(&priv->neigh_reap_task); -	if (atomic_read(&priv->ntbl.entries)) { -		ipoib_flush_neighs(priv); -		wait_for_completion(&priv->ntbl.flushed); -	} +	ipoib_flush_neighs(priv); + +	wait_for_completion(&priv->ntbl.deleted);  }  |