[PATCH v2 5/8] IB/iser: use ib_client API to wrap ib_device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



ib_client API provides a way to wrap an ib_device with a specific ULP
structure.  Using that API local lists and mutexes can be completely
avoided and allocation/removal paths become a bit cleaner.

Signed-off-by: Roman Pen <roman.penyaev@xxxxxxxxxxxxxxx>
Cc: Christoph Hellwig <hch@xxxxxx>
Cc: Steve Wise <swise@xxxxxxxxxxxxxxxxxxxxx>
Cc: Bart Van Assche <bart.vanassche@xxxxxxxxxxx>
Cc: Sagi Grimberg <sagi@xxxxxxxxxxx>
Cc: Doug Ledford <dledford@xxxxxxxxxx>
---
 drivers/infiniband/ulp/iser/iscsi_iser.c | 21 +++++++---
 drivers/infiniband/ulp/iser/iscsi_iser.h | 10 ++---
 drivers/infiniband/ulp/iser/iser_verbs.c | 69 ++++++++++++++++++++------------
 3 files changed, 64 insertions(+), 36 deletions(-)

diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 0336643c2ed6..bdfe4ab68bc6 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -83,7 +83,14 @@ static struct iscsi_transport iscsi_iser_transport;
 static struct scsi_transport_template *iscsi_iser_scsi_transport;
 static struct workqueue_struct *release_wq;
 static DEFINE_MUTEX(unbind_iser_conn_mutex);
-struct iser_global ig;
+
+struct iser_global ig = {
+	.rdma_ib_client = {
+		.name   = "iser_ib_client",
+		.add    = iser_ib_client_add_one,
+		.remove = iser_ib_client_remove_one
+	}
+};
 
 int iser_debug_level = 0;
 module_param_named(debug_level, iser_debug_level, int, S_IRUGO | S_IWUSR);
@@ -1064,8 +1071,6 @@ static int __init iser_init(void)
 		return -EINVAL;
 	}
 
-	memset(&ig, 0, sizeof(struct iser_global));
-
 	ig.desc_cache = kmem_cache_create("iser_descriptors",
 					  sizeof(struct iser_tx_desc),
 					  0, SLAB_HWCACHE_ALIGN,
@@ -1074,11 +1079,14 @@ static int __init iser_init(void)
 		return -ENOMEM;
 
 	/* device init is called only after the first addr resolution */
-	mutex_init(&ig.device_list_mutex);
-	INIT_LIST_HEAD(&ig.device_list);
 	mutex_init(&ig.connlist_mutex);
 	INIT_LIST_HEAD(&ig.connlist);
 
+	err = ib_register_client(&ig.rdma_ib_client);
+	if (unlikely(err)) {
+		iser_err("ib_register_client(): %d\n", err);
+		goto err_register_client;
+	}
 	release_wq = alloc_workqueue("release workqueue", 0, 0);
 	if (!release_wq) {
 		iser_err("failed to allocate release workqueue\n");
@@ -1099,6 +1107,8 @@ static int __init iser_init(void)
 err_reg:
 	destroy_workqueue(release_wq);
 err_alloc_wq:
+	ib_unregister_client(&ig.rdma_ib_client);
+err_register_client:
 	kmem_cache_destroy(ig.desc_cache);
 
 	return err;
@@ -1127,6 +1137,7 @@ static void __exit iser_exit(void)
 
 	iscsi_unregister_transport(&iscsi_iser_transport);
 	kmem_cache_destroy(ig.desc_cache);
+	ib_unregister_client(&ig.rdma_ib_client);
 }
 
 module_init(iser_init);
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 09664e12bd6b..310f5e540c3d 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -364,7 +364,6 @@ struct iser_reg_ops {
  * @pd:            Protection Domain for this device
  * @mr:            Global DMA memory region
  * @event_handler: IB events handle routine
- * @ig_list:	   entry in devices list
  * @refcount:      Reference counter, dominated by open iser connections
  * @comps_used:    Number of completion contexts used, Min between online
  *                 cpus and device max completion vectors
@@ -558,15 +557,13 @@ struct iser_page_vec {
 /**
  * struct iser_global: iSER global context
  *
- * @device_list_mutex:    protects device_list
- * @device_list:          iser devices global list
+ * @rdma_ib_client:       IB client
  * @connlist_mutex:       protects connlist
  * @connlist:             iser connections global list
  * @desc_cache:           kmem cache for tx dataout
  */
 struct iser_global {
-	struct mutex      device_list_mutex;
-	struct list_head  device_list;
+	struct ib_client  rdma_ib_client;
 	struct mutex      connlist_mutex;
 	struct list_head  connlist;
 	struct kmem_cache *desc_cache;
@@ -579,6 +576,9 @@ extern int iser_pi_guard;
 extern unsigned int iser_max_sectors;
 extern bool iser_always_reg;
 
+void iser_ib_client_add_one(struct ib_device *ib_device);
+void iser_ib_client_remove_one(struct ib_device *ib_device, void *client_data);
+
 int iser_assign_reg_ops(struct iser_device *device);
 
 int iser_send_control(struct iscsi_conn *conn,
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 786f348e27c1..c67ceb87fb5e 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -491,55 +491,72 @@ static int iser_create_ib_conn_res(struct ib_conn *ib_conn)
 	return ret;
 }
 
-/**
- * based on the resolved device node GUID see if there already allocated
- * device for this device. If there's no such, create one.
- */
 static
 struct iser_device *iser_device_find_by_ib_device(struct rdma_cm_id *cma_id)
 {
 	struct iser_device *device;
 
-	mutex_lock(&ig.device_list_mutex);
+	/* Paired with iser_ib_client_remove_one() */
+	rcu_read_lock();
+	device = ib_get_client_data(cma_id->device, &ig.rdma_ib_client);
+	if (device && WARN_ON(!refcount_inc_not_zero(&device->refcount)))
+		device = NULL;
+	rcu_read_unlock();
 
-	list_for_each_entry(device, &ig.device_list, ig_list)
-		/* find if there's a match using the node GUID */
-		if (device->ib_device->node_guid == cma_id->device->node_guid)
-			goto inc_refcnt;
+	return device;
+}
+
+static struct iser_device *iser_device_alloc(struct ib_device *ib_device)
+{
+	struct iser_device *device;
 
 	device = kzalloc(sizeof *device, GFP_KERNEL);
-	if (device == NULL)
-		goto out;
+	if (unlikely(!device))
+		return NULL;
 
-	/* assign this device to the device */
-	device->ib_device = cma_id->device;
-	/* init the device and link it into ig device list */
+	refcount_set(&device->refcount, 1);
+	device->ib_device = ib_device;
 	if (iser_create_device_ib_res(device)) {
 		kfree(device);
-		device = NULL;
-		goto out;
+		return NULL;
 	}
-	list_add(&device->ig_list, &ig.device_list);
 
-inc_refcnt:
-	refcount_inc(&device->refcount);
-out:
-	mutex_unlock(&ig.device_list_mutex);
 	return device;
 }
 
 /* if there's no demand for this device, release it */
 static void iser_device_try_release(struct iser_device *device)
 {
-	mutex_lock(&ig.device_list_mutex);
 	iser_info("device %p refcount %d\n", device,
 		  refcount_read(&device->refcount));
 	if (refcount_dec_and_test(&device->refcount)) {
 		iser_free_device_ib_res(device);
-		list_del(&device->ig_list);
 		kfree(device);
 	}
-	mutex_unlock(&ig.device_list_mutex);
+}
+
+void iser_ib_client_add_one(struct ib_device *ib_device)
+{
+	struct iser_device *device;
+
+	device = iser_device_alloc(ib_device);
+	if (likely(device))
+		ib_set_client_data(ib_device, &ig.rdma_ib_client, device);
+	else
+		pr_err("Allocattion of a device failed.\n");
+}
+
+void iser_ib_client_remove_one(struct ib_device *ib_device, void *client_data)
+{
+	struct iser_device *device = client_data;
+
+	if (unlikely(!device))
+		return;
+
+	ib_set_client_data(ib_device, &ig.rdma_ib_client, NULL);
+	/* Paired with iser_device_find_by_ib_device() */
+	synchronize_rcu();
+	iser_device_try_release(device);
 }
 
 /**
@@ -735,8 +752,8 @@ static void iser_addr_handler(struct rdma_cm_id *cma_id)
 
 	ib_conn = &iser_conn->ib_conn;
 	device = iser_device_find_by_ib_device(cma_id);
-	if (!device) {
-		iser_err("device lookup/creation failed\n");
+	if (unlikely(!device)) {
+		iser_err("no device exists\n");
 		iser_connect_error(cma_id);
 		return;
 	}
-- 
2.13.1

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux