]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/infiniband/core/cma.c
RDMA/addr: Use client registration to fix module unload race
[linux-2.6-omap-h63xx.git] / drivers / infiniband / core / cma.c
index 1178bd434d1b1f12cd41f32bbbb0c5aaa3a50929..845090b0859c53b81ff06506fe987320a243bcc4 100644 (file)
@@ -63,6 +63,7 @@ static struct ib_client cma_client = {
 };
 
 static struct ib_sa_client sa_client;
+static struct rdma_addr_client addr_client;
 static LIST_HEAD(dev_list);
 static LIST_HEAD(listen_any_list);
 static DEFINE_MUTEX(lock);
@@ -874,23 +875,25 @@ static struct rdma_id_private *cma_new_id(struct rdma_cm_id *listen_id,
        __u16 port;
        u8 ip_ver;
 
+       if (cma_get_net_info(ib_event->private_data, listen_id->ps,
+                            &ip_ver, &port, &src, &dst))
+               goto err;
+
        id = rdma_create_id(listen_id->event_handler, listen_id->context,
                            listen_id->ps);
        if (IS_ERR(id))
-               return NULL;
+               goto err;
+
+       cma_save_net_info(&id->route.addr, &listen_id->route.addr,
+                         ip_ver, port, src, dst);
 
        rt = &id->route;
        rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1;
-       rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, GFP_KERNEL);
+       rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths,
+                              GFP_KERNEL);
        if (!rt->path_rec)
-               goto err;
-
-       if (cma_get_net_info(ib_event->private_data, listen_id->ps,
-                            &ip_ver, &port, &src, &dst))
-               goto err;
+               goto destroy_id;
 
-       cma_save_net_info(&id->route.addr, &listen_id->route.addr,
-                         ip_ver, port, src, dst);
        rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path;
        if (rt->num_paths == 2)
                rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
@@ -903,8 +906,10 @@ static struct rdma_id_private *cma_new_id(struct rdma_cm_id *listen_id,
        id_priv = container_of(id, struct rdma_id_private, id);
        id_priv->state = CMA_CONNECT;
        return id_priv;
-err:
+
+destroy_id:
        rdma_destroy_id(id);
+err:
        return NULL;
 }
 
@@ -932,6 +937,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
        mutex_unlock(&lock);
        if (ret) {
                ret = -ENODEV;
+               cma_exch(conn_id, CMA_DESTROYING);
                cma_release_remove(conn_id);
                rdma_destroy_id(&conn_id->id);
                goto out;
@@ -1307,6 +1313,7 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
                work->old_state = CMA_ROUTE_QUERY;
                work->new_state = CMA_ADDR_RESOLVED;
                work->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
+               work->event.status = status;
        }
 
        queue_work(cma_wq, &work->work);
@@ -1619,8 +1626,8 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
        if (cma_any_addr(dst_addr))
                ret = cma_resolve_loopback(id_priv);
        else
-               ret = rdma_resolve_ip(&id->route.addr.src_addr, dst_addr,
-                                     &id->route.addr.dev_addr,
+               ret = rdma_resolve_ip(&addr_client, &id->route.addr.src_addr,
+                                     dst_addr, &id->route.addr.dev_addr,
                                      timeout_ms, addr_handler, id_priv);
        if (ret)
                goto err;
@@ -1756,22 +1763,29 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
 
        if (!cma_any_addr(addr)) {
                ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
-               if (!ret) {
-                       mutex_lock(&lock);
-                       ret = cma_acquire_dev(id_priv);
-                       mutex_unlock(&lock);
-               }
                if (ret)
-                       goto err;
+                       goto err1;
+
+               mutex_lock(&lock);
+               ret = cma_acquire_dev(id_priv);
+               mutex_unlock(&lock);
+               if (ret)
+                       goto err1;
        }
 
        memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr));
        ret = cma_get_port(id_priv);
        if (ret)
-               goto err;
+               goto err2;
 
        return 0;
-err:
+err2:
+       if (!cma_any_addr(addr)) {
+               mutex_lock(&lock);
+               cma_detach_from_dev(id_priv);
+               mutex_unlock(&lock);
+       }
+err1:
        cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE);
        return ret;
 }
@@ -1862,6 +1876,11 @@ static int cma_connect_ib(struct rdma_id_private *id_priv,
 
        ret = ib_send_cm_req(id_priv->cm_id.ib, &req);
 out:
+       if (ret && !IS_ERR(id_priv->cm_id.ib)) {
+               ib_destroy_cm_id(id_priv->cm_id.ib);
+               id_priv->cm_id.ib = NULL;
+       }
+
        kfree(private_data);
        return ret;
 }
@@ -1889,10 +1908,8 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
        cm_id->remote_addr = *sin;
 
        ret = cma_modify_qp_rtr(&id_priv->id);
-       if (ret) {
-               iw_destroy_cm_id(cm_id);
-               return ret;
-       }
+       if (ret)
+               goto out;
 
        iw_param.ord = conn_param->initiator_depth;
        iw_param.ird = conn_param->responder_resources;
@@ -1904,6 +1921,10 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
                iw_param.qpn = conn_param->qp_num;
        ret = iw_cm_connect(cm_id, &iw_param);
 out:
+       if (ret && !IS_ERR(cm_id)) {
+               iw_destroy_cm_id(cm_id);
+               id_priv->cm_id.iw = NULL;
+       }
        return ret;
 }
 
@@ -2142,12 +2163,9 @@ static int cma_remove_id_dev(struct rdma_id_private *id_priv)
 
 static void cma_process_remove(struct cma_device *cma_dev)
 {
-       struct list_head remove_list;
        struct rdma_id_private *id_priv;
        int ret;
 
-       INIT_LIST_HEAD(&remove_list);
-
        mutex_lock(&lock);
        while (!list_empty(&cma_dev->id_list)) {
                id_priv = list_entry(cma_dev->id_list.next,
@@ -2158,8 +2176,7 @@ static void cma_process_remove(struct cma_device *cma_dev)
                        continue;
                }
 
-               list_del(&id_priv->list);
-               list_add_tail(&id_priv->list, &remove_list);
+               list_del_init(&id_priv->list);
                atomic_inc(&id_priv->refcount);
                mutex_unlock(&lock);
 
@@ -2201,6 +2218,7 @@ static int cma_init(void)
                return -ENOMEM;
 
        ib_sa_register_client(&sa_client);
+       rdma_addr_register_client(&addr_client);
 
        ret = ib_register_client(&cma_client);
        if (ret)
@@ -2208,6 +2226,7 @@ static int cma_init(void)
        return 0;
 
 err:
+       rdma_addr_unregister_client(&addr_client);
        ib_sa_unregister_client(&sa_client);
        destroy_workqueue(cma_wq);
        return ret;
@@ -2216,6 +2235,7 @@ err:
 static void cma_cleanup(void)
 {
        ib_unregister_client(&cma_client);
+       rdma_addr_unregister_client(&addr_client);
        ib_sa_unregister_client(&sa_client);
        destroy_workqueue(cma_wq);
        idr_destroy(&sdp_ps);