There is a race between the neighbour cleanup code, and some uses 
of the closely related ipoib_neigh structure when using IPoIB-CM. 
To prevent the race, take a reference to the neighbour before the 
connection is established, and release the reference when the 
connection is destroyed. Also, defer the cleanup and release 
of the ipoib_neigh structure until the connection is destroyed.

Signed-off-by: Arthur Kepner <[email protected]>
---
 ipoib_cm.c   |   40 ++++++++++++++++++++++++++++++++--------
 ipoib_main.c |    7 +++++--
 2 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c 
b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 47d588b..ed22a37 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -810,9 +810,6 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct 
ib_wc *wc)
                        list_del(&neigh->list);
                        if (neigh->ah)
                                ipoib_put_ah(neigh->ah);
-                       ipoib_neigh_free(dev, neigh);
-
-                       tx->neigh = NULL;
                }
 
                if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
@@ -1230,9 +1227,6 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
                        list_del(&neigh->list);
                        if (neigh->ah)
                                ipoib_put_ah(neigh->ah);
-                       ipoib_neigh_free(dev, neigh);
-
-                       tx->neigh = NULL;
                }
 
                if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
@@ -1278,7 +1272,6 @@ void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx)
                queue_work(ipoib_workqueue, &priv->cm.reap_task);
                ipoib_dbg(priv, "Reap connection for gid %pI6\n",
                          tx->neigh->dgid.raw);
-               tx->neigh = NULL;
        }
 }
 
@@ -1302,6 +1295,10 @@ static void ipoib_cm_tx_start(struct work_struct *work)
                p = list_entry(priv->cm.start_list.next, typeof(*p), list);
                list_del_init(&p->list);
                neigh = p->neigh;
+               ipoib_dbg(priv, "%s: holding ref to %pI6 (refcnt: %d)\n",
+                         __func__, neigh->dgid.raw,
+                         atomic_read(&neigh->neighbour->refcnt));
+               neigh_hold(neigh->neighbour);
                qpn = IPOIB_QPN(neigh->neighbour->ha);
                memcpy(&pathrec, &p->path->pathrec, sizeof pathrec);
 
@@ -1316,11 +1313,22 @@ static void ipoib_cm_tx_start(struct work_struct *work)
                if (ret) {
                        neigh = p->neigh;
                        if (neigh) {
+                               struct sk_buff *skb;
                                neigh->cm = NULL;
                                list_del(&neigh->list);
                                if (neigh->ah)
                                        ipoib_put_ah(neigh->ah);
-                               ipoib_neigh_free(dev, neigh);
+                               *to_ipoib_neigh(neigh->neighbour) = NULL;
+                               ipoib_dbg(priv, "%s: releasing ref to %pI6 "
+                                         "(refcnt: %d)\n", __func__,
+                                         neigh->dgid.raw,
+                                         
atomic_read(&neigh->neighbour->refcnt));
+                               neigh_release(neigh->neighbour);
+                               while ((skb = __skb_dequeue(&neigh->queue))) {
+                                       ++dev->stats.tx_dropped;
+                                       dev_kfree_skb_any(skb);
+                               }
+                               kfree(neigh);
                        }
                        list_del(&p->list);
                        kfree(p);
@@ -1343,7 +1351,23 @@ static void ipoib_cm_tx_reap(struct work_struct *work)
        spin_lock_irqsave(&priv->lock, flags);
 
        while (!list_empty(&priv->cm.reap_list)) {
+               struct ipoib_neigh *neigh;
+               struct sk_buff *skb;
                p = list_entry(priv->cm.reap_list.next, typeof(*p), list);
+               neigh = p->neigh;
+               if (neigh) {
+                       *to_ipoib_neigh(neigh->neighbour) = NULL;
+                       ipoib_dbg(priv, "%s: releasing ref to %pI6 "
+                                 "(refcnt: %d)\n", __func__, neigh->dgid.raw,
+                                 atomic_read(&neigh->neighbour->refcnt));
+                       neigh_release(neigh->neighbour);
+                       while ((skb = __skb_dequeue(&neigh->queue))) {
+                               ++dev->stats.tx_dropped;
+                               dev_kfree_skb_any(skb);
+                       }
+                       kfree(neigh);
+               }
+               p->neigh = NULL;
                list_del(&p->list);
                spin_unlock_irqrestore(&priv->lock, flags);
                netif_tx_unlock_bh(dev);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c 
b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index ab2c192..8841160 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -889,13 +889,16 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour 
*neighbour,
 void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh)
 {
        struct sk_buff *skb;
+       if (ipoib_cm_get(neigh)) {
+               ipoib_cm_destroy_tx(ipoib_cm_get(neigh));
+               return;
+       }
+
        *to_ipoib_neigh(neigh->neighbour) = NULL;
        while ((skb = __skb_dequeue(&neigh->queue))) {
                ++dev->stats.tx_dropped;
                dev_kfree_skb_any(skb);
        }
-       if (ipoib_cm_get(neigh))
-               ipoib_cm_destroy_tx(ipoib_cm_get(neigh));
        kfree(neigh);
 }
 
_______________________________________________
general mailing list
[email protected]
http://lists.openfabrics.org/cgi-bin/mailman/listinfo/general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to