[RFC 5/5] IB/isert: 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.h |  1 +
 drivers/infiniband/ulp/isert/ib_isert.c  | 94 +++++++++++++++++++++-----------
 drivers/infiniband/ulp/isert/ib_isert.h  |  3 +-
 3 files changed, 66 insertions(+), 32 deletions(-)

diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index bd87bae65d59..04fb3edad749 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -44,6 +44,7 @@
 #include <linux/types.h>
 #include <linux/net.h>
 #include <linux/printk.h>
+#include <linux/refcount.h>
 #include <scsi/libiscsi.h>
 #include <scsi/scsi_transport_iscsi.h>
 #include <scsi/scsi_cmnd.h>
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index b7da1a6ea32c..560c328c32d8 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -42,8 +42,7 @@ static int isert_debug_level;
 module_param_named(debug_level, isert_debug_level, int, 0644);
 MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:0)");
 
-static DEFINE_MUTEX(device_list_mutex);
-static LIST_HEAD(device_list);
+static struct ib_client isert_rdma_ib_client;
 static struct workqueue_struct *isert_comp_wq;
 static struct workqueue_struct *isert_release_wq;
 
@@ -341,56 +340,51 @@ isert_free_device_ib_res(struct isert_device *device)
 static void
 isert_device_put(struct isert_device *device)
 {
-	mutex_lock(&device_list_mutex);
-	device->refcount--;
-	isert_info("device %p refcount %d\n", device, device->refcount);
-	if (!device->refcount) {
+	isert_info("device %p refcount %d\n", device,
+		   refcount_read(&device->refcount));
+	if (refcount_dec_and_test(&device->refcount)) {
 		isert_free_device_ib_res(device);
 		list_del(&device->dev_node);
 		kfree(device);
 	}
-	mutex_unlock(&device_list_mutex);
 }
 
 static struct isert_device *
 isert_device_get(struct rdma_cm_id *cma_id)
 {
 	struct isert_device *device;
-	int ret;
 
-	mutex_lock(&device_list_mutex);
-	list_for_each_entry(device, &device_list, dev_node) {
-		if (device->ib_device->node_guid == cma_id->device->node_guid) {
-			device->refcount++;
-			isert_info("Found iser device %p refcount %d\n",
-				   device, device->refcount);
-			mutex_unlock(&device_list_mutex);
-			return device;
-		}
-	}
+	/* Paired with isert_ib_client_remove_one() */
+	rcu_read_lock();
+	device = ib_get_client_data(cma_id->device, &isert_rdma_ib_client);
+	if (device && WARN_ON(!refcount_inc_not_zero(&device->refcount)))
+		device = NULL;
+	rcu_read_unlock();
+
+	return device;
+}
+
+static struct isert_device *
+isert_device_alloc(struct ib_device *ib_device)
+{
+	struct isert_device *device;
+	int ret;
 
-	device = kzalloc(sizeof(struct isert_device), GFP_KERNEL);
-	if (!device) {
-		mutex_unlock(&device_list_mutex);
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (unlikely(!device))
 		return ERR_PTR(-ENOMEM);
-	}
 
 	INIT_LIST_HEAD(&device->dev_node);
 	mutex_init(&device->comp_mutex);
-
-	device->ib_device = cma_id->device;
+	refcount_set(&device->refcount, 1);
+	device->ib_device = ib_device;
 	ret = isert_create_device_ib_res(device);
 	if (ret) {
 		kfree(device);
-		mutex_unlock(&device_list_mutex);
 		return ERR_PTR(ret);
 	}
-
-	device->refcount++;
-	list_add_tail(&device->dev_node, &device_list);
 	isert_info("Created a new iser device %p refcount %d\n",
-		   device, device->refcount);
-	mutex_unlock(&device_list_mutex);
+		   device, refcount_read(&device->refcount));
 
 	return device;
 }
@@ -2681,15 +2675,50 @@ static struct iscsit_transport iser_target_transport = {
 	.iscsit_get_sup_prot_ops = isert_get_sup_prot_ops,
 };
 
+static void isert_ib_client_add_one(struct ib_device *ib_device)
+{
+	struct isert_device *device;
+
+	device = isert_device_alloc(ib_device);
+	if (!WARN_ON(!device))
+		ib_set_client_data(ib_device, &isert_rdma_ib_client, device);
+}
+
+static void isert_ib_client_remove_one(struct ib_device *ib_device,
+				       void *client_data)
+{
+	struct isert_device *device = client_data;
+
+	if (unlikely(!device))
+		return;
+
+	ib_set_client_data(ib_device, &isert_rdma_ib_client, NULL);
+	/* Paired with isert_device_get() */
+	synchronize_rcu();
+	isert_device_put(device);
+}
+
+static struct ib_client isert_rdma_ib_client = {
+	.name   = "isert_rdma_ib",
+	.add    = isert_ib_client_add_one,
+	.remove = isert_ib_client_remove_one
+};
+
 static int __init isert_init(void)
 {
 	int ret;
 
+	ret = ib_register_client(&isert_rdma_ib_client);
+	if (unlikely(ret)) {
+		isert_err("ib_register_client(): %d\n", ret);
+		return ret;
+	}
 	isert_comp_wq = alloc_workqueue("isert_comp_wq",
 					WQ_UNBOUND | WQ_HIGHPRI, 0);
 	if (!isert_comp_wq) {
 		isert_err("Unable to allocate isert_comp_wq\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto unregister_client;
 	}
 
 	isert_release_wq = alloc_workqueue("isert_release_wq", WQ_UNBOUND,
@@ -2707,6 +2736,8 @@ static int __init isert_init(void)
 
 destroy_comp_wq:
 	destroy_workqueue(isert_comp_wq);
+unregister_client:
+	ib_unregister_client(&isert_rdma_ib_client);
 
 	return ret;
 }
@@ -2717,6 +2748,7 @@ static void __exit isert_exit(void)
 	destroy_workqueue(isert_release_wq);
 	destroy_workqueue(isert_comp_wq);
 	iscsit_unregister_transport(&iser_target_transport);
+	ib_unregister_client(&isert_rdma_ib_client);
 	isert_info("iSER_TARGET[0] - Released iser_target_transport\n");
 }
 
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
index 9f0b0a6d87cf..ff08bf29dce4 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.h
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -2,6 +2,7 @@
 #include <linux/socket.h>
 #include <linux/in.h>
 #include <linux/in6.h>
+#include <linux/refcount.h>
 #include <rdma/ib_verbs.h>
 #include <rdma/rdma_cm.h>
 #include <rdma/rw.h>
@@ -183,7 +184,7 @@ struct isert_comp {
 
 struct isert_device {
 	bool			pi_capable;
-	int			refcount;
+	refcount_t		refcount;
 	struct mutex		comp_mutex;
 	struct ib_device	*ib_device;
 	struct ib_pd		*pd;
-- 
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