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 | |
| 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>
| -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; |
