Roland, the following patch implements a work around for the
destructor issue for 2.6.16. Would you care to check it in, to svn only?

---

Work around for neighbour destructor issue for kernels < 2.6.17:
keep a global list of all ipoib neighbours. Use it in destructor to
1. Verify that this neighbour belongs to an ipoib device
2. Check that the neighbour is the last one to use the destructor,
   if so reset the destructor pointer

Index: linux-2.6.15/drivers/infiniband/ulp/ipoib/ipoib.h
===================================================================
--- linux-2.6.15.orig/drivers/infiniband/ulp/ipoib/ipoib.h      2006-03-13 
15:11:35.000000000 +0200
+++ linux-2.6.15/drivers/infiniband/ulp/ipoib/ipoib.h   2006-03-13 
15:26:41.000000000 +0200
@@ -222,6 +222,9 @@ struct ipoib_neigh {
 
        struct neighbour   *neighbour;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
+       struct list_head    all_neigh_list;
+#endif
        struct list_head    list;
        struct list_head    dev_neigh_list;
 };
Index: linux-2.6.15/drivers/infiniband/ulp/ipoib/ipoib_main.c
===================================================================
--- linux-2.6.15.orig/drivers/infiniband/ulp/ipoib/ipoib_main.c 2006-03-13 
15:26:14.000000000 +0200
+++ linux-2.6.15/drivers/infiniband/ulp/ipoib/ipoib_main.c      2006-03-13 
15:29:26.000000000 +0200
@@ -73,6 +73,11 @@ static const u8 ipv4_bcast_addr[] = {
 
 struct workqueue_struct *ipoib_workqueue;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
+static spinlock_t ipoib_all_neigh_list_lock;
+static LIST_HEAD(ipoib_all_neigh_list);
+#endif
+
 static void ipoib_add_one(struct ib_device *device);
 static void ipoib_remove_one(struct ib_device *device);
 
@@ -747,6 +752,19 @@ static void ipoib_neigh_destructor(struc
        unsigned long flags;
        struct ipoib_ah *ah = NULL;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
+       struct ipoib_neigh *tn, *nn = NULL;
+       spin_lock(&ipoib_all_neigh_list_lock);
+       list_for_each_entry(tn, &ipoib_all_neigh_list, all_neigh_list)
+               if (tn->neighbour == n) {
+                       nn = tn;
+                       break;
+               }
+       spin_unlock(&ipoib_all_neigh_list_lock);
+       if (!nn)
+               return;
+#endif
+
        ipoib_dbg(priv,
                  "neigh_destructor for %06x " IPOIB_GID_FMT "\n",
                  be32_to_cpup((__be32 *) n->ha),
@@ -782,7 +800,10 @@ struct ipoib_neigh *ipoib_neigh_alloc(st
        *to_ipoib_neigh(neighbour) = neigh;
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
+       spin_lock(&ipoib_all_neigh_list_lock);
+       list_add_tail(&neigh->all_neigh_list, &ipoib_all_neigh_list);
        neigh->neighbour->ops->destructor = ipoib_neigh_destructor;
+       spin_unlock(&ipoib_all_neigh_list_lock);
 #endif
 
        return neigh;
@@ -791,7 +812,16 @@ struct ipoib_neigh *ipoib_neigh_alloc(st
 void ipoib_neigh_free(struct ipoib_neigh *neigh)
 {
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
+       struct ipoib_neigh *nn;
+       spin_lock(&ipoib_all_neigh_list_lock);
+       list_del(&neigh->all_neigh_list);
+       list_for_each_entry(nn, &ipoib_all_neigh_list, all_neigh_list)
+               if (nn->neighbour->ops == neigh->neighbour->ops)
+                       goto found;
+
        neigh->neighbour->ops->destructor = NULL;
+found:
+       spin_unlock(&ipoib_all_neigh_list_lock);
 #endif
 
        *to_ipoib_neigh(neigh->neighbour) = NULL;
@@ -1168,6 +1198,10 @@ static int __init ipoib_init_module(void
                goto err_fs;
        }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
+       spin_lock_init(&ipoib_all_neigh_list_lock);
+#endif
+
        ret = ib_register_client(&ipoib_client);
        if (ret)
                goto err_wq;

-- 
Michael S. Tsirkin
Staff Engineer, Mellanox Technologies
_______________________________________________
openib-general mailing list
[email protected]
http://openib.org/mailman/listinfo/openib-general

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

Reply via email to