diff options
Diffstat (limited to 'drivers/infiniband/ulp/ipoib/ipoib_multicast.c')
| -rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 55 | 
1 files changed, 18 insertions, 37 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 7cecb16d3d4..13f4aa7593c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -69,28 +69,13 @@ struct ipoib_mcast_iter {  static void ipoib_mcast_free(struct ipoib_mcast *mcast)  {  	struct net_device *dev = mcast->dev; -	struct ipoib_dev_priv *priv = netdev_priv(dev); -	struct ipoib_neigh *neigh, *tmp;  	int tx_dropped = 0;  	ipoib_dbg_mcast(netdev_priv(dev), "deleting multicast group %pI6\n",  			mcast->mcmember.mgid.raw); -	spin_lock_irq(&priv->lock); - -	list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) { -		/* -		 * It's safe to call ipoib_put_ah() inside priv->lock -		 * here, because we know that mcast->ah will always -		 * hold one more reference, so ipoib_put_ah() will -		 * never do more than decrement the ref count. -		 */ -		if (neigh->ah) -			ipoib_put_ah(neigh->ah); -		ipoib_neigh_free(dev, neigh); -	} - -	spin_unlock_irq(&priv->lock); +	/* remove all neigh connected to this mcast */ +	ipoib_del_neighs_by_gid(dev, mcast->mcmember.mgid.raw);  	if (mcast->ah)  		ipoib_put_ah(mcast->ah); @@ -655,17 +640,12 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast)  	return 0;  } -void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) +void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb)  {  	struct ipoib_dev_priv *priv = netdev_priv(dev); -	struct dst_entry *dst = skb_dst(skb);  	struct ipoib_mcast *mcast; -	struct neighbour *n;  	unsigned long flags; - -	n = NULL; -	if (dst) -		n = dst_neigh_lookup_skb(dst, skb); +	void *mgid = daddr + 4;  	spin_lock_irqsave(&priv->lock, flags); @@ -721,28 +701,29 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)  out:  	if (mcast && mcast->ah) { -		if (n) { -			if (!*to_ipoib_neigh(n)) { -				struct ipoib_neigh *neigh; +		struct ipoib_neigh *neigh; -				neigh = ipoib_neigh_alloc(n, skb->dev); -				if (neigh) { -					kref_get(&mcast->ah->ref); -					neigh->ah	= mcast->ah; -					list_add_tail(&neigh->list, -						      &mcast->neigh_list); -				} +		spin_unlock_irqrestore(&priv->lock, flags); +		neigh = ipoib_neigh_get(dev, daddr); +		spin_lock_irqsave(&priv->lock, flags); +		if (!neigh) { +			spin_unlock_irqrestore(&priv->lock, flags); +			neigh = ipoib_neigh_alloc(daddr, dev); +			spin_lock_irqsave(&priv->lock, flags); +			if (neigh) { +				kref_get(&mcast->ah->ref); +				neigh->ah	= mcast->ah; +				list_add_tail(&neigh->list, &mcast->neigh_list);  			} -			neigh_release(n);  		}  		spin_unlock_irqrestore(&priv->lock, flags);  		ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN); +		if (neigh) +			ipoib_neigh_put(neigh);  		return;  	}  unlock: -	if (n) -		neigh_release(n);  	spin_unlock_irqrestore(&priv->lock, flags);  }  |