diff options
author | Roland Dreier <roland@purestorage.com> | 2017-08-29 13:34:43 -0400 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2017-08-31 08:35:07 -0400 |
commit | c76161181193985087cd716fdf69b5cb6cf9ee85 (patch) | |
tree | abc2e8648e24f498f3d768b8a9131866a32cb300 | |
parent | f43dbebfa32041826299bdccae0352887fa007ea (diff) |
IB/cm: Fix sleeping in atomic when RoCE is used
A couple of places in the CM do
spin_lock_irq(&cm_id_priv->lock);
...
if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
However when the underlying transport is RoCE, this leads to a sleeping function
being called with the lock held - the callchain is
cm_alloc_response_msg() ->
ib_create_ah_from_wc() ->
ib_init_ah_from_wc() ->
rdma_addr_find_l2_eth_by_grh() ->
rdma_resolve_ip()
and rdma_resolve_ip() starts out by doing
req = kzalloc(sizeof *req, GFP_KERNEL);
not to mention rdma_addr_find_l2_eth_by_grh() doing
wait_for_completion(&ctx.comp);
to wait for the task that rdma_resolve_ip() queues up.
Fix this by moving the AH creation out of the lock.
Signed-off-by: Roland Dreier <roland@purestorage.com>
Reviewed-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r-- | drivers/infiniband/core/cm.c | 63 |
1 files changed, 44 insertions, 19 deletions
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index fa3b0a428195..4c4b46586af2 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c | |||
@@ -373,11 +373,19 @@ out: | |||
373 | return ret; | 373 | return ret; |
374 | } | 374 | } |
375 | 375 | ||
376 | static int cm_alloc_response_msg(struct cm_port *port, | 376 | static struct ib_mad_send_buf *cm_alloc_response_msg_no_ah(struct cm_port *port, |
377 | struct ib_mad_recv_wc *mad_recv_wc, | 377 | struct ib_mad_recv_wc *mad_recv_wc) |
378 | struct ib_mad_send_buf **msg) | 378 | { |
379 | return ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index, | ||
380 | 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, | ||
381 | GFP_ATOMIC, | ||
382 | IB_MGMT_BASE_VERSION); | ||
383 | } | ||
384 | |||
385 | static int cm_create_response_msg_ah(struct cm_port *port, | ||
386 | struct ib_mad_recv_wc *mad_recv_wc, | ||
387 | struct ib_mad_send_buf *msg) | ||
379 | { | 388 | { |
380 | struct ib_mad_send_buf *m; | ||
381 | struct ib_ah *ah; | 389 | struct ib_ah *ah; |
382 | 390 | ||
383 | ah = ib_create_ah_from_wc(port->mad_agent->qp->pd, mad_recv_wc->wc, | 391 | ah = ib_create_ah_from_wc(port->mad_agent->qp->pd, mad_recv_wc->wc, |
@@ -385,27 +393,40 @@ static int cm_alloc_response_msg(struct cm_port *port, | |||
385 | if (IS_ERR(ah)) | 393 | if (IS_ERR(ah)) |
386 | return PTR_ERR(ah); | 394 | return PTR_ERR(ah); |
387 | 395 | ||
388 | m = ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index, | 396 | msg->ah = ah; |
389 | 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, | ||
390 | GFP_ATOMIC, | ||
391 | IB_MGMT_BASE_VERSION); | ||
392 | if (IS_ERR(m)) { | ||
393 | rdma_destroy_ah(ah); | ||
394 | return PTR_ERR(m); | ||
395 | } | ||
396 | m->ah = ah; | ||
397 | *msg = m; | ||
398 | return 0; | 397 | return 0; |
399 | } | 398 | } |
400 | 399 | ||
401 | static void cm_free_msg(struct ib_mad_send_buf *msg) | 400 | static void cm_free_msg(struct ib_mad_send_buf *msg) |
402 | { | 401 | { |
403 | rdma_destroy_ah(msg->ah); | 402 | if (msg->ah) |
403 | rdma_destroy_ah(msg->ah); | ||
404 | if (msg->context[0]) | 404 | if (msg->context[0]) |
405 | cm_deref_id(msg->context[0]); | 405 | cm_deref_id(msg->context[0]); |
406 | ib_free_send_mad(msg); | 406 | ib_free_send_mad(msg); |
407 | } | 407 | } |
408 | 408 | ||
409 | static int cm_alloc_response_msg(struct cm_port *port, | ||
410 | struct ib_mad_recv_wc *mad_recv_wc, | ||
411 | struct ib_mad_send_buf **msg) | ||
412 | { | ||
413 | struct ib_mad_send_buf *m; | ||
414 | int ret; | ||
415 | |||
416 | m = cm_alloc_response_msg_no_ah(port, mad_recv_wc); | ||
417 | if (IS_ERR(m)) | ||
418 | return PTR_ERR(m); | ||
419 | |||
420 | ret = cm_create_response_msg_ah(port, mad_recv_wc, m); | ||
421 | if (ret) { | ||
422 | cm_free_msg(m); | ||
423 | return ret; | ||
424 | } | ||
425 | |||
426 | *msg = m; | ||
427 | return 0; | ||
428 | } | ||
429 | |||
409 | static void * cm_copy_private_data(const void *private_data, | 430 | static void * cm_copy_private_data(const void *private_data, |
410 | u8 private_data_len) | 431 | u8 private_data_len) |
411 | { | 432 | { |
@@ -2497,7 +2518,8 @@ static int cm_dreq_handler(struct cm_work *work) | |||
2497 | case IB_CM_TIMEWAIT: | 2518 | case IB_CM_TIMEWAIT: |
2498 | atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. | 2519 | atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. |
2499 | counter[CM_DREQ_COUNTER]); | 2520 | counter[CM_DREQ_COUNTER]); |
2500 | if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) | 2521 | msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc); |
2522 | if (IS_ERR(msg)) | ||
2501 | goto unlock; | 2523 | goto unlock; |
2502 | 2524 | ||
2503 | cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv, | 2525 | cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv, |
@@ -2505,7 +2527,8 @@ static int cm_dreq_handler(struct cm_work *work) | |||
2505 | cm_id_priv->private_data_len); | 2527 | cm_id_priv->private_data_len); |
2506 | spin_unlock_irq(&cm_id_priv->lock); | 2528 | spin_unlock_irq(&cm_id_priv->lock); |
2507 | 2529 | ||
2508 | if (ib_post_send_mad(msg, NULL)) | 2530 | if (cm_create_response_msg_ah(work->port, work->mad_recv_wc, msg) || |
2531 | ib_post_send_mad(msg, NULL)) | ||
2509 | cm_free_msg(msg); | 2532 | cm_free_msg(msg); |
2510 | goto deref; | 2533 | goto deref; |
2511 | case IB_CM_DREQ_RCVD: | 2534 | case IB_CM_DREQ_RCVD: |
@@ -3083,7 +3106,8 @@ static int cm_lap_handler(struct cm_work *work) | |||
3083 | case IB_CM_MRA_LAP_SENT: | 3106 | case IB_CM_MRA_LAP_SENT: |
3084 | atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. | 3107 | atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. |
3085 | counter[CM_LAP_COUNTER]); | 3108 | counter[CM_LAP_COUNTER]); |
3086 | if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) | 3109 | msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc); |
3110 | if (IS_ERR(msg)) | ||
3087 | goto unlock; | 3111 | goto unlock; |
3088 | 3112 | ||
3089 | cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, | 3113 | cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, |
@@ -3093,7 +3117,8 @@ static int cm_lap_handler(struct cm_work *work) | |||
3093 | cm_id_priv->private_data_len); | 3117 | cm_id_priv->private_data_len); |
3094 | spin_unlock_irq(&cm_id_priv->lock); | 3118 | spin_unlock_irq(&cm_id_priv->lock); |
3095 | 3119 | ||
3096 | if (ib_post_send_mad(msg, NULL)) | 3120 | if (cm_create_response_msg_ah(work->port, work->mad_recv_wc, msg) || |
3121 | ib_post_send_mad(msg, NULL)) | ||
3097 | cm_free_msg(msg); | 3122 | cm_free_msg(msg); |
3098 | goto deref; | 3123 | goto deref; |
3099 | case IB_CM_LAP_RCVD: | 3124 | case IB_CM_LAP_RCVD: |