aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/ulp
diff options
context:
space:
mode:
authorEli Cohen <eli@mellanox.co.il>2006-01-10 10:43:02 -0500
committerRoland Dreier <rolandd@cisco.com>2006-01-10 10:43:02 -0500
commit97460df37ea3335ca11562568932c9f9facfecdb (patch)
tree19955a4fe4dbead6f4ef2af9d47cdd1c0eb9339a /drivers/infiniband/ulp
parent70b4c8cdc168bb5d18e23fd205c4ede1b756a8b2 (diff)
IPoIB: Fix address handle refcounting for multicast groups
Multiple ipoib_neigh structures on mcast->neigh_list may point to the same ah. This means that ipoib_mcast_free() can't just make a list of ah structs to free, since this might end up trying to add the same ah to the list more than once. Handle this in ipoib_multicast.c in the same way as it is handled in ipoib_main.c for struct ipoib_path. Signed-off-by: Eli Cohen <eli@mellanox.co.il> Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/ulp')
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 6c6db759e79e..03b2ca64a40c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -97,8 +97,6 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
97 struct ipoib_dev_priv *priv = netdev_priv(dev); 97 struct ipoib_dev_priv *priv = netdev_priv(dev);
98 struct ipoib_neigh *neigh, *tmp; 98 struct ipoib_neigh *neigh, *tmp;
99 unsigned long flags; 99 unsigned long flags;
100 LIST_HEAD(ah_list);
101 struct ipoib_ah *ah, *tah;
102 100
103 ipoib_dbg_mcast(netdev_priv(dev), 101 ipoib_dbg_mcast(netdev_priv(dev),
104 "deleting multicast group " IPOIB_GID_FMT "\n", 102 "deleting multicast group " IPOIB_GID_FMT "\n",
@@ -107,8 +105,14 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
107 spin_lock_irqsave(&priv->lock, flags); 105 spin_lock_irqsave(&priv->lock, flags);
108 106
109 list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) { 107 list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) {
108 /*
109 * It's safe to call ipoib_put_ah() inside priv->lock
110 * here, because we know that mcast->ah will always
111 * hold one more reference, so ipoib_put_ah() will
112 * never do more than decrement the ref count.
113 */
110 if (neigh->ah) 114 if (neigh->ah)
111 list_add_tail(&neigh->ah->list, &ah_list); 115 ipoib_put_ah(neigh->ah);
112 *to_ipoib_neigh(neigh->neighbour) = NULL; 116 *to_ipoib_neigh(neigh->neighbour) = NULL;
113 neigh->neighbour->ops->destructor = NULL; 117 neigh->neighbour->ops->destructor = NULL;
114 kfree(neigh); 118 kfree(neigh);
@@ -116,9 +120,6 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
116 120
117 spin_unlock_irqrestore(&priv->lock, flags); 121 spin_unlock_irqrestore(&priv->lock, flags);
118 122
119 list_for_each_entry_safe(ah, tah, &ah_list, list)
120 ipoib_put_ah(ah);
121
122 if (mcast->ah) 123 if (mcast->ah)
123 ipoib_put_ah(mcast->ah); 124 ipoib_put_ah(mcast->ah);
124 125