aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorSean Hefty <sean.hefty@intel.com>2011-02-23 12:05:39 -0500
committerRoland Dreier <roland@purestorage.com>2011-03-15 13:57:34 -0400
commita396d43a35fb91f2d4920a4700d25ecc5ec92404 (patch)
tree5658f67fe3b18c51c51340b777cbb0fd803376ba /drivers/infiniband
parent8d8ac86564b616bc17054cbb6e727588da64c86b (diff)
RDMA/cma: Replace global lock in rdma_destroy_id() with id-specific one
rdma_destroy_id currently uses the global rdma cm 'lock' to test if an rdma_cm_id has been bound to a device. This prevents an active address resolution callback handler from assigning a device to the rdma_cm_id after rdma_destroy_id checks for one. Instead, we can replace the use of the global lock around the check to the rdma_cm_id device pointer by setting the id state to destroying, then flushing all active callbacks. The latter is accomplished by acquiring and releasing the handler_mutex. Any active handler will complete first, and any newly scheduled handlers will find the rdma_cm_id in an invalid state. In addition to optimizing the current locking scheme, the use of the rdma_cm_id mutex is a more intuitive synchronization mechanism than that of the global lock. These changes are based on feedback from Doug Ledford <dledford@redhat.com> while he was trying to debug a crash in the rdma cm destroy path. Signed-off-by: Sean Hefty <sean.hefty@intel.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/core/cma.c43
1 files changed, 16 insertions, 27 deletions
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index e450c5a87727..5ed9d25d021a 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -308,11 +308,13 @@ static inline void release_mc(struct kref *kref)
308 kfree(mc); 308 kfree(mc);
309} 309}
310 310
311static void cma_detach_from_dev(struct rdma_id_private *id_priv) 311static void cma_release_dev(struct rdma_id_private *id_priv)
312{ 312{
313 mutex_lock(&lock);
313 list_del(&id_priv->list); 314 list_del(&id_priv->list);
314 cma_deref_dev(id_priv->cma_dev); 315 cma_deref_dev(id_priv->cma_dev);
315 id_priv->cma_dev = NULL; 316 id_priv->cma_dev = NULL;
317 mutex_unlock(&lock);
316} 318}
317 319
318static int cma_set_qkey(struct rdma_id_private *id_priv) 320static int cma_set_qkey(struct rdma_id_private *id_priv)
@@ -373,6 +375,7 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv)
373 enum rdma_link_layer dev_ll = dev_addr->dev_type == ARPHRD_INFINIBAND ? 375 enum rdma_link_layer dev_ll = dev_addr->dev_type == ARPHRD_INFINIBAND ?
374 IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET; 376 IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET;
375 377
378 mutex_lock(&lock);
376 iboe_addr_get_sgid(dev_addr, &iboe_gid); 379 iboe_addr_get_sgid(dev_addr, &iboe_gid);
377 memcpy(&gid, dev_addr->src_dev_addr + 380 memcpy(&gid, dev_addr->src_dev_addr +
378 rdma_addr_gid_offset(dev_addr), sizeof gid); 381 rdma_addr_gid_offset(dev_addr), sizeof gid);
@@ -398,6 +401,7 @@ out:
398 if (!ret) 401 if (!ret)
399 cma_attach_to_dev(id_priv, cma_dev); 402 cma_attach_to_dev(id_priv, cma_dev);
400 403
404 mutex_unlock(&lock);
401 return ret; 405 return ret;
402} 406}
403 407
@@ -904,9 +908,14 @@ void rdma_destroy_id(struct rdma_cm_id *id)
904 state = cma_exch(id_priv, CMA_DESTROYING); 908 state = cma_exch(id_priv, CMA_DESTROYING);
905 cma_cancel_operation(id_priv, state); 909 cma_cancel_operation(id_priv, state);
906 910
907 mutex_lock(&lock); 911 /*
912 * Wait for any active callback to finish. New callbacks will find
913 * the id_priv state set to destroying and abort.
914 */
915 mutex_lock(&id_priv->handler_mutex);
916 mutex_unlock(&id_priv->handler_mutex);
917
908 if (id_priv->cma_dev) { 918 if (id_priv->cma_dev) {
909 mutex_unlock(&lock);
910 switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 919 switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
911 case RDMA_TRANSPORT_IB: 920 case RDMA_TRANSPORT_IB:
912 if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) 921 if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
@@ -920,10 +929,8 @@ void rdma_destroy_id(struct rdma_cm_id *id)
920 break; 929 break;
921 } 930 }
922 cma_leave_mc_groups(id_priv); 931 cma_leave_mc_groups(id_priv);
923 mutex_lock(&lock); 932 cma_release_dev(id_priv);
924 cma_detach_from_dev(id_priv);
925 } 933 }
926 mutex_unlock(&lock);
927 934
928 cma_release_port(id_priv); 935 cma_release_port(id_priv);
929 cma_deref_id(id_priv); 936 cma_deref_id(id_priv);
@@ -1200,9 +1207,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
1200 } 1207 }
1201 1208
1202 mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 1209 mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
1203 mutex_lock(&lock);
1204 ret = cma_acquire_dev(conn_id); 1210 ret = cma_acquire_dev(conn_id);
1205 mutex_unlock(&lock);
1206 if (ret) 1211 if (ret)
1207 goto release_conn_id; 1212 goto release_conn_id;
1208 1213
@@ -1401,9 +1406,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
1401 goto out; 1406 goto out;
1402 } 1407 }
1403 1408
1404 mutex_lock(&lock);
1405 ret = cma_acquire_dev(conn_id); 1409 ret = cma_acquire_dev(conn_id);
1406 mutex_unlock(&lock);
1407 if (ret) { 1410 if (ret) {
1408 mutex_unlock(&conn_id->handler_mutex); 1411 mutex_unlock(&conn_id->handler_mutex);
1409 rdma_destroy_id(new_cm_id); 1412 rdma_destroy_id(new_cm_id);
@@ -1966,20 +1969,11 @@ static void addr_handler(int status, struct sockaddr *src_addr,
1966 1969
1967 memset(&event, 0, sizeof event); 1970 memset(&event, 0, sizeof event);
1968 mutex_lock(&id_priv->handler_mutex); 1971 mutex_lock(&id_priv->handler_mutex);
1969 1972 if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED))
1970 /*
1971 * Grab mutex to block rdma_destroy_id() from removing the device while
1972 * we're trying to acquire it.
1973 */
1974 mutex_lock(&lock);
1975 if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) {
1976 mutex_unlock(&lock);
1977 goto out; 1973 goto out;
1978 }
1979 1974
1980 if (!status && !id_priv->cma_dev) 1975 if (!status && !id_priv->cma_dev)
1981 status = cma_acquire_dev(id_priv); 1976 status = cma_acquire_dev(id_priv);
1982 mutex_unlock(&lock);
1983 1977
1984 if (status) { 1978 if (status) {
1985 if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND)) 1979 if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND))
@@ -2280,9 +2274,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
2280 if (ret) 2274 if (ret)
2281 goto err1; 2275 goto err1;
2282 2276
2283 mutex_lock(&lock);
2284 ret = cma_acquire_dev(id_priv); 2277 ret = cma_acquire_dev(id_priv);
2285 mutex_unlock(&lock);
2286 if (ret) 2278 if (ret)
2287 goto err1; 2279 goto err1;
2288 } 2280 }
@@ -2294,11 +2286,8 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
2294 2286
2295 return 0; 2287 return 0;
2296err2: 2288err2:
2297 if (id_priv->cma_dev) { 2289 if (id_priv->cma_dev)
2298 mutex_lock(&lock); 2290 cma_release_dev(id_priv);
2299 cma_detach_from_dev(id_priv);
2300 mutex_unlock(&lock);
2301 }
2302err1: 2291err1:
2303 cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE); 2292 cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE);
2304 return ret; 2293 return ret;