diff options
author | Sean Hefty <sean.hefty@intel.com> | 2011-02-23 12:05:39 -0500 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2011-03-15 13:57:34 -0400 |
commit | a396d43a35fb91f2d4920a4700d25ecc5ec92404 (patch) | |
tree | 5658f67fe3b18c51c51340b777cbb0fd803376ba /drivers/infiniband | |
parent | 8d8ac86564b616bc17054cbb6e727588da64c86b (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.c | 43 |
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 | ||
311 | static void cma_detach_from_dev(struct rdma_id_private *id_priv) | 311 | static 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 | ||
318 | static int cma_set_qkey(struct rdma_id_private *id_priv) | 320 | static 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; |
2296 | err2: | 2288 | err2: |
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 | } | ||
2302 | err1: | 2291 | err1: |
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; |