aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/ulp/ipoib/ipoib_multicast.c')
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c57
1 files changed, 19 insertions, 38 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 7cecb16d3d48..13f4aa7593c8 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 {
69static void ipoib_mcast_free(struct ipoib_mcast *mcast) 69static void ipoib_mcast_free(struct ipoib_mcast *mcast)
70{ 70{
71 struct net_device *dev = mcast->dev; 71 struct net_device *dev = mcast->dev;
72 struct ipoib_dev_priv *priv = netdev_priv(dev);
73 struct ipoib_neigh *neigh, *tmp;
74 int tx_dropped = 0; 72 int tx_dropped = 0;
75 73
76 ipoib_dbg_mcast(netdev_priv(dev), "deleting multicast group %pI6\n", 74 ipoib_dbg_mcast(netdev_priv(dev), "deleting multicast group %pI6\n",
77 mcast->mcmember.mgid.raw); 75 mcast->mcmember.mgid.raw);
78 76
79 spin_lock_irq(&priv->lock); 77 /* remove all neigh connected to this mcast */
80 78 ipoib_del_neighs_by_gid(dev, mcast->mcmember.mgid.raw);
81 list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) {
82 /*
83 * It's safe to call ipoib_put_ah() inside priv->lock
84 * here, because we know that mcast->ah will always
85 * hold one more reference, so ipoib_put_ah() will
86 * never do more than decrement the ref count.
87 */
88 if (neigh->ah)
89 ipoib_put_ah(neigh->ah);
90 ipoib_neigh_free(dev, neigh);
91 }
92
93 spin_unlock_irq(&priv->lock);
94 79
95 if (mcast->ah) 80 if (mcast->ah)
96 ipoib_put_ah(mcast->ah); 81 ipoib_put_ah(mcast->ah);
@@ -655,17 +640,12 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast)
655 return 0; 640 return 0;
656} 641}
657 642
658void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) 643void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb)
659{ 644{
660 struct ipoib_dev_priv *priv = netdev_priv(dev); 645 struct ipoib_dev_priv *priv = netdev_priv(dev);
661 struct dst_entry *dst = skb_dst(skb);
662 struct ipoib_mcast *mcast; 646 struct ipoib_mcast *mcast;
663 struct neighbour *n;
664 unsigned long flags; 647 unsigned long flags;
665 648 void *mgid = daddr + 4;
666 n = NULL;
667 if (dst)
668 n = dst_neigh_lookup_skb(dst, skb);
669 649
670 spin_lock_irqsave(&priv->lock, flags); 650 spin_lock_irqsave(&priv->lock, flags);
671 651
@@ -721,28 +701,29 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
721 701
722out: 702out:
723 if (mcast && mcast->ah) { 703 if (mcast && mcast->ah) {
724 if (n) { 704 struct ipoib_neigh *neigh;
725 if (!*to_ipoib_neigh(n)) { 705
726 struct ipoib_neigh *neigh; 706 spin_unlock_irqrestore(&priv->lock, flags);
727 707 neigh = ipoib_neigh_get(dev, daddr);
728 neigh = ipoib_neigh_alloc(n, skb->dev); 708 spin_lock_irqsave(&priv->lock, flags);
729 if (neigh) { 709 if (!neigh) {
730 kref_get(&mcast->ah->ref); 710 spin_unlock_irqrestore(&priv->lock, flags);
731 neigh->ah = mcast->ah; 711 neigh = ipoib_neigh_alloc(daddr, dev);
732 list_add_tail(&neigh->list, 712 spin_lock_irqsave(&priv->lock, flags);
733 &mcast->neigh_list); 713 if (neigh) {
734 } 714 kref_get(&mcast->ah->ref);
715 neigh->ah = mcast->ah;
716 list_add_tail(&neigh->list, &mcast->neigh_list);
735 } 717 }
736 neigh_release(n);
737 } 718 }
738 spin_unlock_irqrestore(&priv->lock, flags); 719 spin_unlock_irqrestore(&priv->lock, flags);
739 ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN); 720 ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN);
721 if (neigh)
722 ipoib_neigh_put(neigh);
740 return; 723 return;
741 } 724 }
742 725
743unlock: 726unlock:
744 if (n)
745 neigh_release(n);
746 spin_unlock_irqrestore(&priv->lock, flags); 727 spin_unlock_irqrestore(&priv->lock, flags);
747} 728}
748 729