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