From: Shirley Ma ipoib_put_ah() may call ipoib_free_ah(), which might take the device's lock. Therefore we need to make sure we don't call ipoib_put_ah() when holding the lock already. Signed-off-by: Shirley Ma Signed-off-by: Roland Dreier Signed-off-by: Andrew Morton --- 25-akpm/drivers/infiniband/ulp/ipoib/ipoib_main.c | 6 +++++- 25-akpm/drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff -puN drivers/infiniband/ulp/ipoib/ipoib_main.c~ib-ipoib-dont-call-ipoib_put_ah-with-lock-held drivers/infiniband/ulp/ipoib/ipoib_main.c --- 25/drivers/infiniband/ulp/ipoib/ipoib_main.c~ib-ipoib-dont-call-ipoib_put_ah-with-lock-held 2005-03-02 21:50:42.000000000 -0800 +++ 25-akpm/drivers/infiniband/ulp/ipoib/ipoib_main.c 2005-03-02 21:50:42.000000000 -0800 @@ -661,6 +661,7 @@ static void ipoib_neigh_destructor(struc struct ipoib_neigh *neigh = *to_ipoib_neigh(n); struct ipoib_dev_priv *priv = netdev_priv(n->dev); unsigned long flags; + struct ipoib_ah *ah = NULL; ipoib_dbg(priv, "neigh_destructor for %06x " IPOIB_GID_FMT "\n", @@ -671,13 +672,16 @@ static void ipoib_neigh_destructor(struc if (neigh) { if (neigh->ah) - ipoib_put_ah(neigh->ah); + ah = neigh->ah; list_del(&neigh->list); *to_ipoib_neigh(n) = NULL; kfree(neigh); } spin_unlock_irqrestore(&priv->lock, flags); + + if (ah) + ipoib_put_ah(ah); } static int ipoib_neigh_setup(struct neighbour *neigh) diff -puN drivers/infiniband/ulp/ipoib/ipoib_multicast.c~ib-ipoib-dont-call-ipoib_put_ah-with-lock-held drivers/infiniband/ulp/ipoib/ipoib_multicast.c --- 25/drivers/infiniband/ulp/ipoib/ipoib_multicast.c~ib-ipoib-dont-call-ipoib_put_ah-with-lock-held 2005-03-02 21:50:42.000000000 -0800 +++ 25-akpm/drivers/infiniband/ulp/ipoib/ipoib_multicast.c 2005-03-02 21:50:42.000000000 -0800 @@ -93,6 +93,8 @@ static void ipoib_mcast_free(struct ipoi struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_neigh *neigh, *tmp; unsigned long flags; + LIST_HEAD(ah_list); + struct ipoib_ah *ah, *tah; ipoib_dbg_mcast(netdev_priv(dev), "deleting multicast group " IPOIB_GID_FMT "\n", @@ -101,7 +103,8 @@ static void ipoib_mcast_free(struct ipoi spin_lock_irqsave(&priv->lock, flags); list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) { - ipoib_put_ah(neigh->ah); + if (neigh->ah) + list_add_tail(&neigh->ah->list, &ah_list); *to_ipoib_neigh(neigh->neighbour) = NULL; neigh->neighbour->ops->destructor = NULL; kfree(neigh); @@ -109,6 +112,9 @@ static void ipoib_mcast_free(struct ipoi spin_unlock_irqrestore(&priv->lock, flags); + list_for_each_entry_safe(ah, tah, &ah_list, list) + ipoib_put_ah(ah); + if (mcast->ah) ipoib_put_ah(mcast->ah); _