aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/core/cma.c
diff options
context:
space:
mode:
authorSean Hefty <sean.hefty@intel.com>2006-09-01 18:33:55 -0400
committerRoland Dreier <rolandd@cisco.com>2006-09-22 18:22:49 -0400
commit61a73c708f37295892176bc911b178278df6a091 (patch)
treecaa11f34a88a687f6699373f24bd93733b048f10 /drivers/infiniband/core/cma.c
parentf94b533d091a42da92d908eb7b3f9ade1923f90d (diff)
RDMA/cma: Protect against adding device during destruction
Closes a window where address resolution can attach an rdma_cm_id to a device during destruction of the rdma_cm_id. This can result in the rdma_cm_id remaining in the device list after its memory has been freed. Signed-off-by: Sean Hefty <sean.hefty@intel.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/core/cma.c')
-rw-r--r--drivers/infiniband/core/cma.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index e88a7c652ca0..488fa1d642a7 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -279,7 +279,7 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv)
279 default: 279 default:
280 return -ENODEV; 280 return -ENODEV;
281 } 281 }
282 mutex_lock(&lock); 282
283 list_for_each_entry(cma_dev, &dev_list, list) { 283 list_for_each_entry(cma_dev, &dev_list, list) {
284 ret = ib_find_cached_gid(cma_dev->device, &gid, 284 ret = ib_find_cached_gid(cma_dev->device, &gid,
285 &id_priv->id.port_num, NULL); 285 &id_priv->id.port_num, NULL);
@@ -288,7 +288,6 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv)
288 break; 288 break;
289 } 289 }
290 } 290 }
291 mutex_unlock(&lock);
292 return ret; 291 return ret;
293} 292}
294 293
@@ -712,7 +711,9 @@ void rdma_destroy_id(struct rdma_cm_id *id)
712 state = cma_exch(id_priv, CMA_DESTROYING); 711 state = cma_exch(id_priv, CMA_DESTROYING);
713 cma_cancel_operation(id_priv, state); 712 cma_cancel_operation(id_priv, state);
714 713
714 mutex_lock(&lock);
715 if (id_priv->cma_dev) { 715 if (id_priv->cma_dev) {
716 mutex_unlock(&lock);
716 switch (rdma_node_get_transport(id->device->node_type)) { 717 switch (rdma_node_get_transport(id->device->node_type)) {
717 case RDMA_TRANSPORT_IB: 718 case RDMA_TRANSPORT_IB:
718 if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) 719 if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
@@ -727,8 +728,8 @@ void rdma_destroy_id(struct rdma_cm_id *id)
727 } 728 }
728 mutex_lock(&lock); 729 mutex_lock(&lock);
729 cma_detach_from_dev(id_priv); 730 cma_detach_from_dev(id_priv);
730 mutex_unlock(&lock);
731 } 731 }
732 mutex_unlock(&lock);
732 733
733 cma_release_port(id_priv); 734 cma_release_port(id_priv);
734 cma_deref_id(id_priv); 735 cma_deref_id(id_priv);
@@ -925,7 +926,9 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
925 } 926 }
926 927
927 atomic_inc(&conn_id->dev_remove); 928 atomic_inc(&conn_id->dev_remove);
929 mutex_lock(&lock);
928 ret = cma_acquire_dev(conn_id); 930 ret = cma_acquire_dev(conn_id);
931 mutex_unlock(&lock);
929 if (ret) { 932 if (ret) {
930 ret = -ENODEV; 933 ret = -ENODEV;
931 cma_release_remove(conn_id); 934 cma_release_remove(conn_id);
@@ -1097,7 +1100,9 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
1097 goto out; 1100 goto out;
1098 } 1101 }
1099 1102
1103 mutex_lock(&lock);
1100 ret = cma_acquire_dev(conn_id); 1104 ret = cma_acquire_dev(conn_id);
1105 mutex_unlock(&lock);
1101 if (ret) { 1106 if (ret) {
1102 cma_release_remove(conn_id); 1107 cma_release_remove(conn_id);
1103 rdma_destroy_id(new_cm_id); 1108 rdma_destroy_id(new_cm_id);
@@ -1507,16 +1512,26 @@ static void addr_handler(int status, struct sockaddr *src_addr,
1507 enum rdma_cm_event_type event; 1512 enum rdma_cm_event_type event;
1508 1513
1509 atomic_inc(&id_priv->dev_remove); 1514 atomic_inc(&id_priv->dev_remove);
1510 if (!id_priv->cma_dev && !status) 1515
1516 /*
1517 * Grab mutex to block rdma_destroy_id() from removing the device while
1518 * we're trying to acquire it.
1519 */
1520 mutex_lock(&lock);
1521 if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) {
1522 mutex_unlock(&lock);
1523 goto out;
1524 }
1525
1526 if (!status && !id_priv->cma_dev)
1511 status = cma_acquire_dev(id_priv); 1527 status = cma_acquire_dev(id_priv);
1528 mutex_unlock(&lock);
1512 1529
1513 if (status) { 1530 if (status) {
1514 if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND)) 1531 if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND))
1515 goto out; 1532 goto out;
1516 event = RDMA_CM_EVENT_ADDR_ERROR; 1533 event = RDMA_CM_EVENT_ADDR_ERROR;
1517 } else { 1534 } else {
1518 if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED))
1519 goto out;
1520 memcpy(&id_priv->id.route.addr.src_addr, src_addr, 1535 memcpy(&id_priv->id.route.addr.src_addr, src_addr,
1521 ip_addr_size(src_addr)); 1536 ip_addr_size(src_addr));
1522 event = RDMA_CM_EVENT_ADDR_RESOLVED; 1537 event = RDMA_CM_EVENT_ADDR_RESOLVED;
@@ -1740,8 +1755,11 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
1740 1755
1741 if (!cma_any_addr(addr)) { 1756 if (!cma_any_addr(addr)) {
1742 ret = rdma_translate_ip(addr, &id->route.addr.dev_addr); 1757 ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
1743 if (!ret) 1758 if (!ret) {
1759 mutex_lock(&lock);
1744 ret = cma_acquire_dev(id_priv); 1760 ret = cma_acquire_dev(id_priv);
1761 mutex_unlock(&lock);
1762 }
1745 if (ret) 1763 if (ret)
1746 goto err; 1764 goto err;
1747 } 1765 }