[openib-general] [PATCH] hotplug support: selective removal notification

Michael S. Tsirkin mst at mellanox.co.il
Wed Aug 31 09:20:20 PDT 2005


Hi!
As Sean pointed out, in the existing client registration
the client gets removal events even from devices which it
may not be interested in.

As a way of solving this, I propose the following patch.
The idea is that instead of setting client context separately
with ib_set_client_data, client's add method will return
ib_client_data object which is then kept in a per-device list.
Returning NULL signals that the client will not be interested
in this device.

Removing the device walks this list and only calls the clients
that returned non-NULL object on add.

In this way most ulps can now use container_of to get their
context in the remove method, instead of scanning the client list
each time, which in my opinion is very nice.

I updated sdp,srp,ipoib for this API change.
I can split ULPs to separate patches if needed.

Let me know,
MST

---

Add a way to client to avoid getting notifications for some
devices. Make it possible to use container_of to get per device
data instead of a list walk.

Signed-off-by: Michael S. Tsirkin <mst at mellanox.co.il>

 core/cache.c            |   18 +++++--
 core/cm.c               |   19 +++----
 core/device.c           |  122 ++++++++++++++++--------------------------------
 core/mad.c              |   18 +++++--
 core/ping.c             |   15 ++++-
 core/sa_query.c         |   36 +++++++-------
 core/user_mad.c         |   29 +++++------
 core/uverbs.h           |    1
 core/uverbs_main.c      |   26 ++++------
 include/rdma/ib_verbs.h |   16 ++++--
 ulp/ipoib/ipoib_main.c  |   32 +++++++-----
 ulp/sdp/sdp_conn.c      |   31 +++++-------
 ulp/sdp/sdp_dev.h       |    1
 ulp/srp/ib_srp.c        |   31 +++++++-----
 14 files changed, 203 insertions(+), 192 deletions(-)

Index: linux-2.6.12.2/drivers/infiniband/core/device.c
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/core/device.c	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/core/device.c	2005-08-31 21:07:15.000000000 +0300
@@ -47,12 +47,6 @@ MODULE_AUTHOR("Roland Dreier");
 MODULE_DESCRIPTION("core kernel InfiniBand API");
 MODULE_LICENSE("Dual BSD/GPL");
 
-struct ib_client_data {
-	struct list_head  list;
-	struct ib_client *client;
-	void *            data;
-};
-
 static LIST_HEAD(device_list);
 static LIST_HEAD(client_list);
 
@@ -194,28 +188,6 @@ void ib_dealloc_device(struct ib_device 
 }
 EXPORT_SYMBOL(ib_dealloc_device);
 
-static int add_client_context(struct ib_device *device, struct ib_client *client)
-{
-	struct ib_client_data *context;
-	unsigned long flags;
-
-	context = kmalloc(sizeof *context, GFP_KERNEL);
-	if (!context) {
-		printk(KERN_WARNING "Couldn't allocate client context for %s/%s\n",
-		       device->name, client->name);
-		return -ENOMEM;
-	}
-
-	context->client = client;
-	context->data   = NULL;
-
-	spin_lock_irqsave(&device->client_data_lock, flags);
-	list_add(&context->list, &device->client_data_list);
-	spin_unlock_irqrestore(&device->client_data_lock, flags);
-
-	return 0;
-}
-
 /**
  * ib_register_device - Register an IB device with IB core
  * @device:Device to register
@@ -259,11 +231,17 @@ int ib_register_device(struct ib_device 
 	device->reg_state = IB_DEV_REGISTERED;
 
 	{
+		struct ib_client_data *context;
 		struct ib_client *client;
+		unsigned long flags;
 
 		list_for_each_entry(client, &client_list, list)
-			if (client->add && !add_client_context(device, client))
-				client->add(device);
+			if (client->add && (context = client->add(device))) {
+				context->client = client;
+				spin_lock_irqsave(&device->client_data_lock, flags);
+				list_add(&context->list, &device->client_data_list);
+				spin_unlock_irqrestore(&device->client_data_lock, flags);
+			}
 	}
 
  out:
@@ -280,26 +258,29 @@ EXPORT_SYMBOL(ib_register_device);
  */
 void ib_unregister_device(struct ib_device *device)
 {
-	struct ib_client *client;
-	struct ib_client_data *context, *tmp;
+	struct ib_client_data *context;
 	unsigned long flags;
 
 	down(&device_sem);
 
-	list_for_each_entry_reverse(client, &client_list, list)
-		if (client->remove)
-			client->remove(device);
-
 	list_del(&device->core_list);
 
-	up(&device_sem);
-
 	spin_lock_irqsave(&device->client_data_lock, flags);
-	list_for_each_entry_safe(context, tmp, &device->client_data_list, list)
-		kfree(context);
+	for (;;) {
+		if (list_empty(&device->client_data_list))
+			break;
+		context = list_entry(device->client_data_list.next,
+					typeof(*context), list);
+		list_del(&context->list);
+		spin_unlock_irqrestore(&device->client_data_lock, flags);
+		if (context->client->remove)
+			context->client->remove(device, context);
+		spin_lock_irqsave(&device->client_data_lock, flags);
+	}
 	spin_unlock_irqrestore(&device->client_data_lock, flags);
 
 	device->reg_state = IB_DEV_UNREGISTERED;
+	up(&device_sem);
 }
 EXPORT_SYMBOL(ib_unregister_device);
 
@@ -318,14 +299,20 @@ EXPORT_SYMBOL(ib_unregister_device);
  */
 int ib_register_client(struct ib_client *client)
 {
+	struct ib_client_data *context;
 	struct ib_device *device;
+	unsigned long flags;
 
 	down(&device_sem);
 
 	list_add_tail(&client->list, &client_list);
 	list_for_each_entry(device, &device_list, core_list)
-		if (client->add && !add_client_context(device, client))
-			client->add(device);
+		if (client->add && (context = client->add(device))) {
+			context->client = client;
+			spin_lock_irqsave(&device->client_data_lock, flags);
+			list_add(&context->list, &device->client_data_list);
+			spin_unlock_irqrestore(&device->client_data_lock, flags);
+		}
 
 	up(&device_sem);
 
@@ -343,23 +330,25 @@ EXPORT_SYMBOL(ib_register_client);
  */
 void ib_unregister_client(struct ib_client *client)
 {
-	struct ib_client_data *context, *tmp;
+	struct ib_client_data *context;
 	struct ib_device *device;
 	unsigned long flags;
 
 	down(&device_sem);
 
 	list_for_each_entry(device, &device_list, core_list) {
-		if (client->remove)
-			client->remove(device);
-
 		spin_lock_irqsave(&device->client_data_lock, flags);
-		list_for_each_entry_safe(context, tmp, &device->client_data_list, list)
+		list_for_each_entry(context, &device->client_data_list, list)
 			if (context->client == client) {
 				list_del(&context->list);
-				kfree(context);
+				spin_unlock_irqrestore(&device->client_data_lock, flags);
+				if (client->remove)
+					client->remove(device, context);
+				spin_lock_irqsave(&device->client_data_lock, flags);
+				break;
 			}
 		spin_unlock_irqrestore(&device->client_data_lock, flags);
+
 	}
 	list_del(&client->list);
 
@@ -375,16 +364,17 @@ EXPORT_SYMBOL(ib_unregister_client);
  * ib_get_client_data() returns client context set with
  * ib_set_client_data().
  */
-void *ib_get_client_data(struct ib_device *device, struct ib_client *client)
+struct ib_client_data *ib_get_client_data(struct ib_device *device,
+					  struct ib_client *client)
 {
 	struct ib_client_data *context;
-	void *ret = NULL;
+	struct ib_client_data *ret = NULL;
 	unsigned long flags;
 
 	spin_lock_irqsave(&device->client_data_lock, flags);
 	list_for_each_entry(context, &device->client_data_list, list)
 		if (context->client == client) {
-			ret = context->data;
+			ret = context;
 			break;
 		}
 	spin_unlock_irqrestore(&device->client_data_lock, flags);
@@ -394,36 +384,6 @@ void *ib_get_client_data(struct ib_devic
 EXPORT_SYMBOL(ib_get_client_data);
 
 /**
- * ib_set_client_data - Get IB client context
- * @device:Device to set context for
- * @client:Client to set context for
- * @data:Context to set
- *
- * ib_set_client_data() sets client context that can be retrieved with
- * ib_get_client_data().
- */
-void ib_set_client_data(struct ib_device *device, struct ib_client *client,
-			void *data)
-{
-	struct ib_client_data *context;
-	unsigned long flags;
-
-	spin_lock_irqsave(&device->client_data_lock, flags);
-	list_for_each_entry(context, &device->client_data_list, list)
-		if (context->client == client) {
-			context->data = data;
-			goto out;
-		}
-
-	printk(KERN_WARNING "No client context found for %s/%s\n",
-	       device->name, client->name);
-
-out:
-	spin_unlock_irqrestore(&device->client_data_lock, flags);
-}
-EXPORT_SYMBOL(ib_set_client_data);
-
-/**
  * ib_register_event_handler - Register an IB event handler
  * @event_handler:Handler to register
  *
Index: linux-2.6.12.2/drivers/infiniband/include/rdma/ib_verbs.h
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/include/rdma/ib_verbs.h	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/include/rdma/ib_verbs.h	2005-08-31 21:07:15.000000000 +0300
@@ -956,14 +956,21 @@ struct ib_device {
 	u8                           phys_port_cnt;
 };
 
+struct ib_client_data;
+
 struct ib_client {
 	char  *name;
-	void (*add)   (struct ib_device *);
-	void (*remove)(struct ib_device *);
+	struct ib_client_data *(*add) (struct ib_device *);
+	void (*remove)(struct ib_device *, struct ib_client_data *);
 
 	struct list_head list;
 };
 
+struct ib_client_data {
+	struct list_head  list;
+	struct ib_client *client;
+};
+
 struct ib_device *ib_alloc_device(size_t size);
 void ib_dealloc_device(struct ib_device *device);
 
@@ -973,9 +980,8 @@ void ib_unregister_device(struct ib_devi
 int ib_register_client   (struct ib_client *client);
 void ib_unregister_client(struct ib_client *client);
 
-void *ib_get_client_data(struct ib_device *device, struct ib_client *client);
-void  ib_set_client_data(struct ib_device *device, struct ib_client *client,
-			 void *data);
+struct ib_client_data *ib_get_client_data(struct ib_device *device,
+					  struct ib_client *client);
 
 static inline int ib_copy_from_udata(void *dest, struct ib_udata *udata, size_t len)
 {
Index: linux-2.6.12.2/drivers/infiniband/core/user_mad.c
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/core/user_mad.c	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/core/user_mad.c	2005-08-31 21:07:15.000000000 +0300
@@ -80,9 +80,10 @@ struct ib_umad_port {
 };
 
 struct ib_umad_device {
-	int                  start_port, end_port;
-	struct kref          ref;
-	struct ib_umad_port  port[0];
+	struct ib_client_data data;
+	int                   start_port, end_port;
+	struct kref           ref;
+	struct ib_umad_port   port[0];
 };
 
 struct ib_umad_file {
@@ -108,8 +109,9 @@ static const dev_t base_dev = MKDEV(IB_U
 static spinlock_t map_lock;
 static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS * 2);
 
-static void ib_umad_add_one(struct ib_device *device);
-static void ib_umad_remove_one(struct ib_device *device);
+static struct ib_client_data *ib_umad_add_one(struct ib_device *device);
+static void ib_umad_remove_one(struct ib_device *device,
+			       struct ib_client_data *);
 
 static int queue_packet(struct ib_umad_file *file,
 			struct ib_mad_agent *agent,
@@ -819,7 +821,7 @@ err_cdev:
 	return -1;
 }
 
-static void ib_umad_add_one(struct ib_device *device)
+static struct ib_client_data *ib_umad_add_one(struct ib_device *device)
 {
 	struct ib_umad_device *umad_dev;
 	int s, e, i;
@@ -835,7 +837,7 @@ static void ib_umad_add_one(struct ib_de
 			   (e - s + 1) * sizeof (struct ib_umad_port),
 			   GFP_KERNEL);
 	if (!umad_dev)
-		return;
+		return NULL;
 
 	memset(umad_dev, 0, sizeof *umad_dev +
 	       (e - s + 1) * sizeof (struct ib_umad_port));
@@ -852,9 +854,7 @@ static void ib_umad_add_one(struct ib_de
 			goto err;
 	}
 
-	ib_set_client_data(device, &umad_client, umad_dev);
-
-	return;
+	return &umad_dev->data;
 
 err:
 	while (--i >= s) {
@@ -863,15 +863,16 @@ err:
 	}
 
 	kref_put(&umad_dev->ref, ib_umad_release_dev);
+	return NULL;
 }
 
-static void ib_umad_remove_one(struct ib_device *device)
+static void ib_umad_remove_one(struct ib_device *device,
+			       struct ib_client_data *data)
 {
-	struct ib_umad_device *umad_dev = ib_get_client_data(device, &umad_client);
+	struct ib_umad_device *umad_dev;
 	int i;
 
-	if (!umad_dev)
-		return;
+ 	umad_dev = container_of(data, struct ib_umad_device, data);
 
 	for (i = 0; i <= umad_dev->end_port - umad_dev->start_port; ++i) {
 		class_device_unregister(&umad_dev->port[i].class_dev);
Index: linux-2.6.12.2/drivers/infiniband/core/cm.c
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/core/cm.c	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/core/cm.c	2005-08-31 21:07:15.000000000 +0300
@@ -51,8 +51,8 @@ MODULE_AUTHOR("Sean Hefty");
 MODULE_DESCRIPTION("InfiniBand CM");
 MODULE_LICENSE("Dual BSD/GPL");
 
-static void cm_add_one(struct ib_device *device);
-static void cm_remove_one(struct ib_device *device);
+static struct ib_client_data *cm_add_one(struct ib_device *device);
+static void cm_remove_one(struct ib_device *device, struct ib_client_data *);
 
 static struct ib_client cm_client = {
 	.name   = "cm",
@@ -81,6 +81,7 @@ struct cm_port {
 };
 
 struct cm_device {
+	struct ib_client_data data;
 	struct list_head list;
 	struct ib_device *device;
 	__be64 ca_guid;
@@ -3194,7 +3195,7 @@ static __be64 cm_get_ca_guid(struct ib_d
 	return guid;
 }
 
-static void cm_add_one(struct ib_device *device)
+static struct ib_client_data *cm_add_one(struct ib_device *device)
 {
 	struct cm_device *cm_dev;
 	struct cm_port *port;
@@ -3212,7 +3213,7 @@ static void cm_add_one(struct ib_device 
 	cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) *
 			 device->phys_port_cnt, GFP_KERNEL);
 	if (!cm_dev)
-		return;
+		return NULL;
 
 	cm_dev->device = device;
 	cm_dev->ca_guid = cm_get_ca_guid(device);
@@ -3238,12 +3239,11 @@ static void cm_add_one(struct ib_device 
 		if (ret)
 			goto error3;
 	}
-	ib_set_client_data(device, &cm_client, cm_dev);
 
 	write_lock_irqsave(&cm.device_lock, flags);
 	list_add_tail(&cm_dev->list, &cm.device_list);
 	write_unlock_irqrestore(&cm.device_lock, flags);
-	return;
+	return &cm_dev->data;
 
 error3:
 	ib_unregister_mad_agent(port->mad_agent);
@@ -3257,9 +3257,10 @@ error2:
 	}
 error1:
 	kfree(cm_dev);
+	return NULL;
 }
 
-static void cm_remove_one(struct ib_device *device)
+static void cm_remove_one(struct ib_device *device, struct ib_client_data *data)
 {
 	struct cm_device *cm_dev;
 	struct cm_port *port;
@@ -3269,9 +3270,7 @@ static void cm_remove_one(struct ib_devi
 	unsigned long flags;
 	int i;
 
-	cm_dev = ib_get_client_data(device, &cm_client);
-	if (!cm_dev)
-		return;
+	cm_dev = container_of(data, struct cm_device, data);
 
 	write_lock_irqsave(&cm.device_lock, flags);
 	list_del(&cm_dev->list);
Index: linux-2.6.12.2/drivers/infiniband/core/sa_query.c
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/core/sa_query.c	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/core/sa_query.c	2005-08-31 21:07:15.000000000 +0300
@@ -65,6 +65,7 @@ struct ib_sa_port {
 };
 
 struct ib_sa_device {
+	struct ib_client_data   data;
 	int                     start_port, end_port;
 	struct ib_event_handler event_handler;
 	struct ib_sa_port port[0];
@@ -98,8 +99,8 @@ struct ib_sa_mcmember_query {
 	struct ib_sa_query sa_query;
 };
 
-static void ib_sa_add_one(struct ib_device *device);
-static void ib_sa_remove_one(struct ib_device *device);
+static struct ib_client_data *ib_sa_add_one(struct ib_device *device);
+static void ib_sa_remove_one(struct ib_device *device, struct ib_client_data *data);
 
 static struct ib_client sa_client = {
 	.name   = "sa",
@@ -426,13 +427,14 @@ static void update_sm_ah(void *port_ptr)
 
 static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event)
 {
+	struct ib_sa_device *sa_dev;
+
 	if (event->event == IB_EVENT_PORT_ERR    ||
 	    event->event == IB_EVENT_PORT_ACTIVE ||
 	    event->event == IB_EVENT_LID_CHANGE  ||
 	    event->event == IB_EVENT_PKEY_CHANGE ||
 	    event->event == IB_EVENT_SM_CHANGE) {
-		struct ib_sa_device *sa_dev =
-			ib_get_client_data(event->device, &sa_client);
+		sa_dev = container_of(handler, struct ib_sa_device, event_handler);
 
 		schedule_work(&sa_dev->port[event->element.port_num -
 					    sa_dev->start_port].update_task);
@@ -608,7 +610,8 @@ int ib_sa_path_rec_get(struct ib_device 
 		       struct ib_sa_query **sa_query)
 {
 	struct ib_sa_path_query *query;
-	struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client);
+	struct ib_client_data *data = ib_get_client_data(device, &sa_client);
+	struct ib_sa_device *sa_dev = container_of(data, struct ib_sa_device, data);
 	struct ib_sa_port   *port   = &sa_dev->port[port_num - sa_dev->start_port];
 	struct ib_mad_agent *agent  = port->agent;
 	int ret;
@@ -710,7 +713,8 @@ int ib_sa_service_rec_query(struct ib_de
 			    struct ib_sa_query **sa_query)
 {
 	struct ib_sa_service_query *query;
-	struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client);
+	struct ib_client_data *data = ib_get_client_data(device, &sa_client);
+	struct ib_sa_device *sa_dev = container_of(data, struct ib_sa_device, data);
 	struct ib_sa_port   *port   = &sa_dev->port[port_num - sa_dev->start_port];
 	struct ib_mad_agent *agent  = port->agent;
 	int ret;
@@ -793,7 +797,8 @@ int ib_sa_mcmember_rec_query(struct ib_d
 			     struct ib_sa_query **sa_query)
 {
 	struct ib_sa_mcmember_query *query;
-	struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client);
+	struct ib_client_data *data = ib_get_client_data(device, &sa_client);
+	struct ib_sa_device *sa_dev = container_of(data, struct ib_sa_device, data);
 	struct ib_sa_port   *port   = &sa_dev->port[port_num - sa_dev->start_port];
 	struct ib_mad_agent *agent  = port->agent;
 	int ret;
@@ -900,7 +905,7 @@ static void recv_handler(struct ib_mad_a
 	ib_free_recv_mad(mad_recv_wc);
 }
 
-static void ib_sa_add_one(struct ib_device *device)
+static struct ib_client_data *ib_sa_add_one(struct ib_device *device)
 {
 	struct ib_sa_device *sa_dev;
 	int s, e, i;
@@ -916,7 +921,7 @@ static void ib_sa_add_one(struct ib_devi
 			 (e - s + 1) * sizeof (struct ib_sa_port),
 			 GFP_KERNEL);
 	if (!sa_dev)
-		return;
+		return NULL;
 
 	sa_dev->start_port = s;
 	sa_dev->end_port   = e;
@@ -937,8 +942,6 @@ static void ib_sa_add_one(struct ib_devi
 			  update_sm_ah, &sa_dev->port[i]);
 	}
 
-	ib_set_client_data(device, &sa_client, sa_dev);
-
 	/*
 	 * We register our event handler after everything is set up,
 	 * and then update our cached info after the event handler is
@@ -953,7 +956,7 @@ static void ib_sa_add_one(struct ib_devi
 	for (i = 0; i <= e - s; ++i)
 		update_sm_ah(&sa_dev->port[i]);
 
-	return;
+	return &sa_dev->data;
 
 err:
 	while (--i >= 0)
@@ -961,17 +964,14 @@ err:
 
 	kfree(sa_dev);
 
-	return;
+	return NULL;
 }
 
-static void ib_sa_remove_one(struct ib_device *device)
+static void ib_sa_remove_one(struct ib_device *device, struct ib_client_data *data)
 {
-	struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client);
+	struct ib_sa_device *sa_dev = container_of(data, struct ib_sa_device, data);
 	int i;
 
-	if (!sa_dev)
-		return;
-
 	ib_unregister_event_handler(&sa_dev->event_handler);
 
 	for (i = 0; i <= sa_dev->end_port - sa_dev->start_port; ++i) {
Index: linux-2.6.12.2/drivers/infiniband/ulp/sdp/sdp_conn.c
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/ulp/sdp/sdp_conn.c	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/ulp/sdp/sdp_conn.c	2005-08-31 21:07:15.000000000 +0300
@@ -37,8 +37,9 @@
 
 static struct sdev_root dev_root_s;
 
-static void sdp_device_init_one(struct ib_device *device);
-static void sdp_device_remove_one(struct ib_device *device);
+static struct ib_client_data *sdp_device_init_one(struct ib_device *device);
+static void sdp_device_remove_one(struct ib_device *device,
+				  struct ib_client_data *data);
 
 static struct ib_client sdp_client = {
 	.name   = "sdp",
@@ -959,6 +960,7 @@ static void sdp_conn_lock_init(struct sd
 int sdp_conn_alloc_ib(struct sdp_sock *conn, struct ib_device *device,
 		      u8 hw_port, u16 pkey)
 {
+	struct ib_client_data *data;
 	struct ib_qp_init_attr *init_attr;
 	struct ib_qp_attr     *qp_attr;
 	struct sdev_hca_port  *port;
@@ -969,10 +971,12 @@ int sdp_conn_alloc_ib(struct sdp_sock *c
 	/*
 	 * look up correct HCA and port
 	 */
-	hca = ib_get_client_data(device, &sdp_client);
-	if (!hca)
+	data = ib_get_client_data(device, &sdp_client);
+	if (!data)
 		return -ERANGE;
 
+	hca = container_of(data, struct sdev_hca, data);
+
 	list_for_each_entry(port, &hca->port_list, list)
 		if (hw_port == port->index) {
 			result = 1;
@@ -1706,7 +1710,7 @@ int sdp_proc_dump_device(char *buffer, i
 /*
  * sdp_device_init_one - add a device to the list
  */
-static void sdp_device_init_one(struct ib_device *device)
+static struct ib_client_data *sdp_device_init_one(struct ib_device *device)
 {
 	struct ib_fmr_pool_param fmr_param_s;
 	struct sdev_hca_port *port, *tmp;
@@ -1719,7 +1723,7 @@ static void sdp_device_init_one(struct i
 	hca = kmalloc(sizeof *hca, GFP_KERNEL);
 	if (!hca) {
 		sdp_warn("Error allocating HCA <%s> memory.", device->name);
-		return;
+		return NULL;
 	}
 	/*
 	 * init and insert into list.
@@ -1801,9 +1805,7 @@ static void sdp_device_init_one(struct i
 		}
 	}
 
-	ib_set_client_data(device, &sdp_client, hca);
-
-	return;
+	return &hca->data;
 
 error:
 	list_for_each_entry_safe(port, tmp, &hca->port_list, list) {
@@ -1821,22 +1823,19 @@ error:
 		(void)ib_dealloc_pd(hca->pd);
 
 	kfree(hca);
+	return NULL;
 }
 
 /*
  * sdp_device_remove_one - remove a device from the hca list
  */
-static void sdp_device_remove_one(struct ib_device *device)
+static void sdp_device_remove_one(struct ib_device *device,
+				  struct ib_client_data *data)
 {
 	struct sdev_hca_port *port, *tmp;
 	struct sdev_hca *hca;
 
-	hca = ib_get_client_data(device, &sdp_client);
-
-	if (!hca) {
-		sdp_warn("Device <%s> has no HCA info.", device->name);
-		return;
-	}
+	hca = container_of(data, struct sdev_hca, data);
 
 	list_for_each_entry_safe(port, tmp, &hca->port_list, list) {
 		list_del(&port->list);
Index: linux-2.6.12.2/drivers/infiniband/ulp/srp/ib_srp.c
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/ulp/srp/ib_srp.c	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/ulp/srp/ib_srp.c	2005-08-31 21:09:37.000000000 +0300
@@ -59,6 +59,11 @@ MODULE_AUTHOR("Roland Dreier");
 MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol driver");
 MODULE_LICENSE("Dual BSD/GPL");
 
+struct ib_srp_client_data {
+	struct ib_client_data data;
+	struct list_head list;
+};
+
 static int topspin_workarounds = 1;
 
 module_param(topspin_workarounds, int, 0444);
@@ -67,8 +72,8 @@ MODULE_PARM_DESC(topspin_workarounds,
 
 static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad };
 
-static void srp_add_one(struct ib_device *device);
-static void srp_remove_one(struct ib_device *device);
+static struct ib_client_data *srp_add_one(struct ib_device *device);
+static void srp_remove_one(struct ib_device *device, struct ib_client_data *data);
 
 static struct ib_client srp_client = {
 	.name   = "srp",
@@ -1335,16 +1340,16 @@ err_free:
 	return NULL;
 }
 
-static void srp_add_one(struct ib_device *device)
+static struct ib_client_data *srp_add_one(struct ib_device *device)
 {
-	struct list_head *dev_list;
+	struct ib_srp_client_data *dev_list = NULL;
 	struct srp_host *host;
 	struct ib_device_attr *dev_attr;
 	int s, e, p;
 
 	dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL);
 	if (!dev_attr)
-		return;
+		return NULL;
 
 	if (ib_query_device(device, dev_attr)) {
 		printk(KERN_WARNING PFX "Couldn't query node GUID for %s.\n",
@@ -1356,7 +1361,7 @@ static void srp_add_one(struct ib_device
 	if (!dev_list)
 		goto out;
 
-	INIT_LIST_HEAD(dev_list);
+	INIT_LIST_HEAD(&dev_list->list);
 
 	if (device->node_type == IB_NODE_SWITCH) {
 		s = 0;
@@ -1369,24 +1374,23 @@ static void srp_add_one(struct ib_device
 	for (p = s; p <= e; ++p) {
 		host = srp_add_port(device, dev_attr->node_guid, p);
 		if (host)
-			list_add_tail(&host->list, dev_list);
+			list_add_tail(&host->list, &dev_list->list);
 	}
 
-	ib_set_client_data(device, &srp_client, dev_list);
-
 out:
 	kfree(dev_attr);
+ 	return dev_list ? &dev_list->data : NULL;
 }
 
-static void srp_remove_one(struct ib_device *device)
+static void srp_remove_one(struct ib_device *device, struct ib_client_data *data)
 {
-	struct list_head *dev_list;
+ 	struct ib_srp_client_data *dev_list;
 	struct srp_host *host, *tmp_host;
 	struct srp_target_port *target, *tmp_target;
 
-	dev_list = ib_get_client_data(device, &srp_client);
+ 	dev_list = container_of(data, struct ib_srp_client_data, data);
 
-	list_for_each_entry_safe(host, tmp_host, dev_list, list) {
+	list_for_each_entry_safe(host, tmp_host, &dev_list->list, list) {
 		class_device_unregister(&host->class_dev);
 		wait_for_completion(&host->released);
 
@@ -1405,6 +1409,7 @@ static void srp_remove_one(struct ib_dev
 		ib_dealloc_pd(host->pd);
 		kfree(host);
 	}
+	kfree(dev_list);
 }
 
 static int __init srp_init_module(void)
Index: linux-2.6.12.2/drivers/infiniband/core/uverbs.h
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/core/uverbs.h	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/core/uverbs.h	2005-08-31 21:07:15.000000000 +0300
@@ -49,6 +49,7 @@
 #include <rdma/ib_user_verbs.h>
 
 struct ib_uverbs_device {
+	struct ib_client_data			data;
 	int					devnum;
 	struct cdev				dev;
 	struct class_device			class_dev;
Index: linux-2.6.12.2/drivers/infiniband/core/mad.c
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/core/mad.c	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/core/mad.c	2005-08-31 21:07:15.000000000 +0300
@@ -2681,10 +2681,18 @@ static int ib_mad_port_close(struct ib_d
 	return 0;
 }
 
-static void ib_mad_init_device(struct ib_device *device)
+static struct ib_client_data *ib_mad_init_device(struct ib_device *device)
 {
+	struct ib_client_data *data;
 	int num_ports, cur_port, i;
 
+	data = kmalloc(sizeof *data, GFP_KERNEL);
+	if (!data) {
+		printk(KERN_ERR PFX "Couldn't allocate memory for device %s\n",
+		       device->name);
+		return NULL;
+	}
+
 	if (device->node_type == IB_NODE_SWITCH) {
 		num_ports = 1;
 		cur_port = 0;
@@ -2705,7 +2713,7 @@ static void ib_mad_init_device(struct ib
 			goto error_device_open;
 		}
 	}
-	return;
+	return data;
 
 error_device_open:
 	while (i > 0) {
@@ -2719,11 +2727,15 @@ error_device_open:
 			       device->name, cur_port);
 		i--;
 	}
+	kfree(data);
+	return NULL;
 }
 
-static void ib_mad_remove_device(struct ib_device *device)
+static void ib_mad_remove_device(struct ib_device *device,
+				 struct ib_client_data *data)
 {
 	int i, num_ports, cur_port;
+	kfree(data);
 
 	if (device->node_type == IB_NODE_SWITCH) {
 		num_ports = 1;
Index: linux-2.6.12.2/drivers/infiniband/ulp/sdp/sdp_dev.h
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/ulp/sdp/sdp_dev.h	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/ulp/sdp/sdp_dev.h	2005-08-31 21:07:15.000000000 +0300
@@ -154,6 +154,7 @@ struct sdev_hca_port {
 };
 
 struct sdev_hca {
+	struct ib_client_data data;
 	struct ib_device     *ca;        /* HCA */
 	struct ib_pd         *pd;        /* protection domain for this HCA */
 	struct ib_mr         *mem_h;     /* registered memory region */
Index: linux-2.6.12.2/drivers/infiniband/ulp/ipoib/ipoib_main.c
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/ulp/ipoib/ipoib_main.c	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/ulp/ipoib/ipoib_main.c	2005-08-31 21:07:15.000000000 +0300
@@ -51,6 +51,11 @@ MODULE_AUTHOR("Roland Dreier");
 MODULE_DESCRIPTION("IP-over-InfiniBand net driver");
 MODULE_LICENSE("Dual BSD/GPL");
 
+struct ipoib_client_data {
+	struct ib_client_data data;
+	struct list_head list;
+};
+
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
 int ipoib_debug_level;
 
@@ -67,8 +72,9 @@ static const u8 ipv4_bcast_addr[] = {
 struct workqueue_struct *ipoib_workqueue;
 struct workqueue_struct *ipoib_event_workqueue;
 
-static void ipoib_add_one(struct ib_device *device);
-static void ipoib_remove_one(struct ib_device *device);
+static struct ib_client_data *ipoib_add_one(struct ib_device *device);
+static void ipoib_remove_one(struct ib_device *device,
+			     struct ib_client_data *data);
 
 static struct ib_client ipoib_client = {
 	.name   = "ipoib",
@@ -1018,18 +1024,18 @@ alloc_mem_failed:
 	return ERR_PTR(result);
 }
 
-static void ipoib_add_one(struct ib_device *device)
+static struct ib_client_data *ipoib_add_one(struct ib_device *device)
 {
-	struct list_head *dev_list;
+	struct ipoib_client_data *dev_list;
 	struct net_device *dev;
 	struct ipoib_dev_priv *priv;
 	int s, e, p;
 
 	dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL);
 	if (!dev_list)
-		return;
+		return NULL;
 
-	INIT_LIST_HEAD(dev_list);
+	INIT_LIST_HEAD(&dev_list->list);
 
 	if (device->node_type == IB_NODE_SWITCH) {
 		s = 0;
@@ -1043,21 +1049,22 @@ static void ipoib_add_one(struct ib_devi
 		dev = ipoib_add_port("ib%d", device, p);
 		if (!IS_ERR(dev)) {
 			priv = netdev_priv(dev);
-			list_add_tail(&priv->list, dev_list);
+			list_add_tail(&priv->list, &dev_list->list);
 		}
 	}
 
-	ib_set_client_data(device, &ipoib_client, dev_list);
+	return &dev_list->data;
 }
 
-static void ipoib_remove_one(struct ib_device *device)
+static void ipoib_remove_one(struct ib_device *device,
+			     struct ib_client_data *data)
 {
 	struct ipoib_dev_priv *priv, *tmp;
-	struct list_head *dev_list;
+	struct ipoib_client_data *dev_list;
 
-	dev_list = ib_get_client_data(device, &ipoib_client);
+	dev_list = container_of(data, struct ipoib_client_data, data);
 
-	list_for_each_entry_safe(priv, tmp, dev_list, list) {
+	list_for_each_entry_safe(priv, tmp, &dev_list->list, list) {
 		ib_unregister_event_handler(&priv->event_handler);
 		flush_workqueue(ipoib_event_workqueue);
 
@@ -1065,6 +1072,7 @@ static void ipoib_remove_one(struct ib_d
 		ipoib_dev_cleanup(priv->dev);
 		free_netdev(priv->dev);
 	}
+	kfree(dev_list);
 }
 
 static int __init ipoib_init_module(void)
Index: linux-2.6.12.2/drivers/infiniband/core/cache.c
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/core/cache.c	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/core/cache.c	2005-08-31 21:07:15.000000000 +0300
@@ -291,10 +291,18 @@ static void ib_cache_event(struct ib_eve
 	}
 }
 
-static void ib_cache_setup_one(struct ib_device *device)
+static struct ib_client_data *ib_cache_setup_one(struct ib_device *device)
 {
+	struct ib_client_data *data;
 	int p;
 
+	data = kmalloc(sizeof *data, GFP_KERNEL);
+	if (!data) {
+		printk(KERN_WARNING "Couldn't allocate client data "
+		       "for %s\n", device->name);
+		return NULL;
+	}
+
 	rwlock_init(&device->cache.lock);
 
 	device->cache.pkey_cache =
@@ -321,7 +329,7 @@ static void ib_cache_setup_one(struct ib
 	if (ib_register_event_handler(&device->cache.event_handler))
 		goto err_cache;
 
-	return;
+	return data;
 
 err_cache:
 	for (p = 0; p <= end_port(device) - start_port(device); ++p) {
@@ -332,9 +340,12 @@ err_cache:
 err:
 	kfree(device->cache.pkey_cache);
 	kfree(device->cache.gid_cache);
+	kfree(data);
+	return NULL;
 }
 
-static void ib_cache_cleanup_one(struct ib_device *device)
+static void ib_cache_cleanup_one(struct ib_device *device,
+				 struct ib_client_data *data)
 {
 	int p;
 
@@ -348,6 +359,7 @@ static void ib_cache_cleanup_one(struct 
 
 	kfree(device->cache.pkey_cache);
 	kfree(device->cache.gid_cache);
+	kfree(data);
 }
 
 static struct ib_client cache_client = {
Index: linux-2.6.12.2/drivers/infiniband/core/uverbs_main.c
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/core/uverbs_main.c	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/core/uverbs_main.c	2005-08-31 21:07:15.000000000 +0300
@@ -101,8 +101,9 @@ static ssize_t (*uverbs_cmd_table[])(str
 
 static struct vfsmount *uverbs_event_mnt;
 
-static void ib_uverbs_add_one(struct ib_device *device);
-static void ib_uverbs_remove_one(struct ib_device *device);
+static struct ib_client_data *ib_uverbs_add_one(struct ib_device *device);
+static void ib_uverbs_remove_one(struct ib_device *device,
+				 struct ib_client_data *data);
 
 static int ib_dealloc_ucontext(struct ib_ucontext *context)
 {
@@ -581,16 +582,16 @@ static ssize_t show_abi_version(struct c
 }
 static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
 
-static void ib_uverbs_add_one(struct ib_device *device)
+static struct ib_client_data *ib_uverbs_add_one(struct ib_device *device)
 {
 	struct ib_uverbs_device *uverbs_dev;
 
 	if (!device->alloc_ucontext)
-		return;
+		return NULL;
 
 	uverbs_dev = kmalloc(sizeof *uverbs_dev, GFP_KERNEL);
 	if (!uverbs_dev)
-		return;
+		return NULL;
 
 	memset(uverbs_dev, 0, sizeof *uverbs_dev);
 
@@ -626,9 +627,7 @@ static void ib_uverbs_add_one(struct ib_
 	if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_ibdev))
 		goto err_class;
 
-	ib_set_client_data(device, &uverbs_client, uverbs_dev);
-
-	return;
+	return &uverbs_dev->data;
 
 err_class:
 	class_device_unregister(&uverbs_dev->class_dev);
@@ -639,15 +638,14 @@ err_cdev:
 
 err:
 	kfree(uverbs_dev);
-	return;
+	return NULL;
 }
 
-static void ib_uverbs_remove_one(struct ib_device *device)
+static void ib_uverbs_remove_one(struct ib_device *device,
+				 struct ib_client_data *data)
 {
-	struct ib_uverbs_device *uverbs_dev = ib_get_client_data(device, &uverbs_client);
-
-	if (!uverbs_dev)
-		return;
+	struct ib_uverbs_device *uverbs_dev;
+	uverbs_dev = container_of(data, struct ib_uverbs_device, data);
 
 	class_device_unregister(&uverbs_dev->class_dev);
 }
Index: linux-2.6.12.2/drivers/infiniband/core/ping.c
===================================================================
--- linux-2.6.12.2.orig/drivers/infiniband/core/ping.c	2005-08-31 21:06:55.000000000 +0300
+++ linux-2.6.12.2/drivers/infiniband/core/ping.c	2005-08-31 21:07:15.000000000 +0300
@@ -245,9 +245,10 @@ static int ib_ping_port_close(struct ib_
 	return 0;
 }
 
-static void ib_ping_init_device(struct ib_device *device)
+static struct ib_client_data *ib_ping_init_device(struct ib_device *device)
 {
 	int num_ports, cur_port, i;
+	struct ib_client_data *data;
 
 	if (device->node_type == IB_NODE_SWITCH) {
 		num_ports = 1;
@@ -263,7 +264,11 @@ static void ib_ping_init_device(struct i
 			       device->name, cur_port);
 			goto error_device_open;
 	}
-	return;
+
+	data = kmalloc(sizeof *data, GFP_KERNEL);
+	if (!data)
+		goto error_device_open;
+	return data;
 
 error_device_open:
 	while (i > 0) {
@@ -274,12 +279,16 @@ error_device_open:
 			       device->name, cur_port);
 		i--;
 	}
+	return NULL;
 }
 
-static void ib_ping_remove_device(struct ib_device *device)
+static void ib_ping_remove_device(struct ib_device *device,
+		struct ib_client_data *data)
 {
 	int i, num_ports, cur_port;
 
+	kfree(data);
+
 	if (device->node_type == IB_NODE_SWITCH) {
 		num_ports = 1;
 		cur_port = 0;
-- 
MST



More information about the general mailing list