RDMA/cma: Fix listener leak in rdma_cma_listen_on_all() failure
[sfrench/cifs-2.6.git] / drivers / infiniband / core / cma.c
index 86ee3b01b3ee47ce38553a5108094ce52aea532d..5aa58897965df4916dd2bf6d8e1a0c993bc1782b 100644 (file)
@@ -1746,15 +1746,16 @@ static void cma_cancel_route(struct rdma_id_private *id_priv)
        }
 }
 
-static void cma_cancel_listens(struct rdma_id_private *id_priv)
+static void _cma_cancel_listens(struct rdma_id_private *id_priv)
 {
        struct rdma_id_private *dev_id_priv;
 
+       lockdep_assert_held(&lock);
+
        /*
         * Remove from listen_any_list to prevent added devices from spawning
         * additional listen requests.
         */
-       mutex_lock(&lock);
        list_del(&id_priv->list);
 
        while (!list_empty(&id_priv->listen_list)) {
@@ -1768,6 +1769,12 @@ static void cma_cancel_listens(struct rdma_id_private *id_priv)
                rdma_destroy_id(&dev_id_priv->id);
                mutex_lock(&lock);
        }
+}
+
+static void cma_cancel_listens(struct rdma_id_private *id_priv)
+{
+       mutex_lock(&lock);
+       _cma_cancel_listens(id_priv);
        mutex_unlock(&lock);
 }
 
@@ -2579,7 +2586,7 @@ static int cma_listen_on_all(struct rdma_id_private *id_priv)
        return 0;
 
 err_listen:
-       list_del(&id_priv->list);
+       _cma_cancel_listens(id_priv);
        mutex_unlock(&lock);
        if (to_destroy)
                rdma_destroy_id(&to_destroy->id);