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