aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/core/cma.c70
1 files changed, 23 insertions, 47 deletions
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 01ae052ac3f4..ee946cc2576b 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -114,11 +114,12 @@ struct rdma_id_private {
114 114
115 struct rdma_bind_list *bind_list; 115 struct rdma_bind_list *bind_list;
116 struct hlist_node node; 116 struct hlist_node node;
117 struct list_head list; 117 struct list_head list; /* listen_any_list or cma_device.list */
118 struct list_head listen_list; 118 struct list_head listen_list; /* per device listens */
119 struct cma_device *cma_dev; 119 struct cma_device *cma_dev;
120 struct list_head mc_list; 120 struct list_head mc_list;
121 121
122 int internal_id;
122 enum cma_state state; 123 enum cma_state state;
123 spinlock_t lock; 124 spinlock_t lock;
124 struct mutex qp_mutex; 125 struct mutex qp_mutex;
@@ -745,50 +746,27 @@ static void cma_cancel_route(struct rdma_id_private *id_priv)
745 } 746 }
746} 747}
747 748
748static inline int cma_internal_listen(struct rdma_id_private *id_priv)
749{
750 return (id_priv->state == CMA_LISTEN) && id_priv->cma_dev &&
751 cma_any_addr(&id_priv->id.route.addr.src_addr);
752}
753
754static void cma_destroy_listen(struct rdma_id_private *id_priv)
755{
756 cma_exch(id_priv, CMA_DESTROYING);
757
758 if (id_priv->cma_dev) {
759 switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
760 case RDMA_TRANSPORT_IB:
761 if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
762 ib_destroy_cm_id(id_priv->cm_id.ib);
763 break;
764 case RDMA_TRANSPORT_IWARP:
765 if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw))
766 iw_destroy_cm_id(id_priv->cm_id.iw);
767 break;
768 default:
769 break;
770 }
771 cma_detach_from_dev(id_priv);
772 }
773 list_del(&id_priv->listen_list);
774
775 cma_deref_id(id_priv);
776 wait_for_completion(&id_priv->comp);
777
778 kfree(id_priv);
779}
780
781static void cma_cancel_listens(struct rdma_id_private *id_priv) 749static void cma_cancel_listens(struct rdma_id_private *id_priv)
782{ 750{
783 struct rdma_id_private *dev_id_priv; 751 struct rdma_id_private *dev_id_priv;
784 752
753 /*
754 * Remove from listen_any_list to prevent added devices from spawning
755 * additional listen requests.
756 */
785 mutex_lock(&lock); 757 mutex_lock(&lock);
786 list_del(&id_priv->list); 758 list_del(&id_priv->list);
787 759
788 while (!list_empty(&id_priv->listen_list)) { 760 while (!list_empty(&id_priv->listen_list)) {
789 dev_id_priv = list_entry(id_priv->listen_list.next, 761 dev_id_priv = list_entry(id_priv->listen_list.next,
790 struct rdma_id_private, listen_list); 762 struct rdma_id_private, listen_list);
791 cma_destroy_listen(dev_id_priv); 763 /* sync with device removal to avoid duplicate destruction */
764 list_del_init(&dev_id_priv->list);
765 list_del(&dev_id_priv->listen_list);
766 mutex_unlock(&lock);
767
768 rdma_destroy_id(&dev_id_priv->id);
769 mutex_lock(&lock);
792 } 770 }
793 mutex_unlock(&lock); 771 mutex_unlock(&lock);
794} 772}
@@ -876,6 +854,9 @@ void rdma_destroy_id(struct rdma_cm_id *id)
876 cma_deref_id(id_priv); 854 cma_deref_id(id_priv);
877 wait_for_completion(&id_priv->comp); 855 wait_for_completion(&id_priv->comp);
878 856
857 if (id_priv->internal_id)
858 cma_deref_id(id_priv->id.context);
859
879 kfree(id_priv->id.route.path_rec); 860 kfree(id_priv->id.route.path_rec);
880 kfree(id_priv); 861 kfree(id_priv);
881} 862}
@@ -1432,14 +1413,13 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
1432 1413
1433 cma_attach_to_dev(dev_id_priv, cma_dev); 1414 cma_attach_to_dev(dev_id_priv, cma_dev);
1434 list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); 1415 list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list);
1416 atomic_inc(&id_priv->refcount);
1417 dev_id_priv->internal_id = 1;
1435 1418
1436 ret = rdma_listen(id, id_priv->backlog); 1419 ret = rdma_listen(id, id_priv->backlog);
1437 if (ret) 1420 if (ret)
1438 goto err; 1421 printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, "
1439 1422 "listening on device %s", ret, cma_dev->device->name);
1440 return;
1441err:
1442 cma_destroy_listen(dev_id_priv);
1443} 1423}
1444 1424
1445static void cma_listen_on_all(struct rdma_id_private *id_priv) 1425static void cma_listen_on_all(struct rdma_id_private *id_priv)
@@ -2787,16 +2767,12 @@ static void cma_process_remove(struct cma_device *cma_dev)
2787 id_priv = list_entry(cma_dev->id_list.next, 2767 id_priv = list_entry(cma_dev->id_list.next,
2788 struct rdma_id_private, list); 2768 struct rdma_id_private, list);
2789 2769
2790 if (cma_internal_listen(id_priv)) { 2770 list_del(&id_priv->listen_list);
2791 cma_destroy_listen(id_priv);
2792 continue;
2793 }
2794
2795 list_del_init(&id_priv->list); 2771 list_del_init(&id_priv->list);
2796 atomic_inc(&id_priv->refcount); 2772 atomic_inc(&id_priv->refcount);
2797 mutex_unlock(&lock); 2773 mutex_unlock(&lock);
2798 2774
2799 ret = cma_remove_id_dev(id_priv); 2775 ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv);
2800 cma_deref_id(id_priv); 2776 cma_deref_id(id_priv);
2801 if (ret) 2777 if (ret)
2802 rdma_destroy_id(&id_priv->id); 2778 rdma_destroy_id(&id_priv->id);