[openib-general] neigh destructor work-around

Michael S. Tsirkin mst at mellanox.co.il
Wed Mar 15 08:37:01 PST 2006


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



More information about the general mailing list