.remove = cma_remove_one
};
+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);
default:
return -ENODEV;
}
- mutex_lock(&lock);
+
list_for_each_entry(cma_dev, &dev_list, list) {
ret = ib_find_cached_gid(cma_dev->device, &gid,
&id_priv->id.port_num, NULL);
break;
}
}
- mutex_unlock(&lock);
return ret;
}
state = cma_exch(id_priv, CMA_DESTROYING);
cma_cancel_operation(id_priv, state);
+ mutex_lock(&lock);
if (id_priv->cma_dev) {
+ mutex_unlock(&lock);
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
}
mutex_lock(&lock);
cma_detach_from_dev(id_priv);
- mutex_unlock(&lock);
}
+ mutex_unlock(&lock);
cma_release_port(id_priv);
cma_deref_id(id_priv);
__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;
+ goto destroy_id;
- if (cma_get_net_info(ib_event->private_data, listen_id->ps,
- &ip_ver, &port, &src, &dst))
- goto err;
-
- 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;
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;
}
}
atomic_inc(&conn_id->dev_remove);
+ mutex_lock(&lock);
ret = cma_acquire_dev(conn_id);
+ 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;
goto out;
}
+ mutex_lock(&lock);
ret = cma_acquire_dev(conn_id);
+ mutex_unlock(&lock);
if (ret) {
cma_release_remove(conn_id);
rdma_destroy_id(new_cm_id);
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);
path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr));
path_rec.numb_path = 1;
- id_priv->query_id = ib_sa_path_rec_get(id_priv->id.device,
+ id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
id_priv->id.port_num, &path_rec,
IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH,
enum rdma_cm_event_type event;
atomic_inc(&id_priv->dev_remove);
- if (!id_priv->cma_dev && !status)
+
+ /*
+ * Grab mutex to block rdma_destroy_id() from removing the device while
+ * we're trying to acquire it.
+ */
+ mutex_lock(&lock);
+ if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) {
+ mutex_unlock(&lock);
+ goto out;
+ }
+
+ if (!status && !id_priv->cma_dev)
status = cma_acquire_dev(id_priv);
+ mutex_unlock(&lock);
if (status) {
- if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND))
+ if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND))
goto out;
event = RDMA_CM_EVENT_ADDR_ERROR;
} else {
- if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED))
- goto out;
memcpy(&id_priv->id.route.addr.src_addr, src_addr,
ip_addr_size(src_addr));
event = RDMA_CM_EVENT_ADDR_RESOLVED;
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;
if (!cma_any_addr(addr)) {
ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
- if (!ret)
- ret = cma_acquire_dev(id_priv);
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;
}
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;
}
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;
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;
}
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,
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);
if (!cma_wq)
return -ENOMEM;
+ ib_sa_register_client(&sa_client);
+ rdma_addr_register_client(&addr_client);
+
ret = ib_register_client(&cma_client);
if (ret)
goto err;
return 0;
err:
+ rdma_addr_unregister_client(&addr_client);
+ ib_sa_unregister_client(&sa_client);
destroy_workqueue(cma_wq);
return ret;
}
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);
idr_destroy(&tcp_ps);