Skip to content

Commit fc0856c

Browse files
sheftyrleon
authored andcommitted
IB/cm: Rework sending DREQ when destroying a cm_id
A DREQ is sent in 2 situations: 1. When requested by the user. This DREQ has to wait for a DREP, which will be routed to the user. 2. When the cm_id is destroyed. This DREQ is generated by the CM to notify the peer that the connection has been destroyed. In the latter case, any DREP that is received will be discarded. There's no need to hold a reference on the cm_id. Today, both situations are covered by the same function: cm_send_dreq_locked(). When invoked in the cm_id destroy path, the cm_id reference would be held until the DREQ completes, blocking the destruction. Because it could take several seconds to minutes before the DREQ receives a DREP, the destroy call posts a send for the DREQ then immediately cancels the MAD. However, cancellation is not immediate in the MAD layer. There could still be a delay before the MAD layer returns the DREQ to the CM. Moreover, the only guarantee is that the DREQ will be sent at most once. Introduce a separate flow for sending a DREQ when destroying the cm_id. The new flow will not hold a reference on the cm_id, allowing it to be cleaned up immediately. The cancellation trick is no longer needed. The MAD layer will send the DREQ exactly once. Signed-off-by: Sean Hefty <[email protected]> Signed-off-by: Or Har-Toov <[email protected]> Signed-off-by: Vlad Dumitrescu <[email protected]> Link: https://patch.msgid.link/a288a098b8e0550305755fd4a7937431699317f4.1731495873.git.leon@kernel.org Signed-off-by: Leon Romanovsky <[email protected]>
1 parent 1e51592 commit fc0856c

File tree

1 file changed

+32
-21
lines changed
  • drivers/infiniband/core

1 file changed

+32
-21
lines changed

drivers/infiniband/core/cm.c

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@ static void cm_process_work(struct cm_id_private *cm_id_priv,
9595
struct cm_work *work);
9696
static int cm_send_sidr_rep_locked(struct cm_id_private *cm_id_priv,
9797
struct ib_cm_sidr_rep_param *param);
98-
static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv,
99-
const void *private_data, u8 private_data_len);
98+
static void cm_issue_dreq(struct cm_id_private *cm_id_priv);
10099
static int cm_send_drep_locked(struct cm_id_private *cm_id_priv,
101100
void *private_data, u8 private_data_len);
102101
static int cm_send_rej_locked(struct cm_id_private *cm_id_priv,
@@ -1112,7 +1111,8 @@ static void cm_destroy_id(struct ib_cm_id *cm_id, int err)
11121111
cm_id->state = IB_CM_IDLE;
11131112
break;
11141113
}
1115-
cm_send_dreq_locked(cm_id_priv, NULL, 0);
1114+
cm_issue_dreq(cm_id_priv);
1115+
cm_enter_timewait(cm_id_priv);
11161116
goto retest;
11171117
case IB_CM_DREQ_SENT:
11181118
ib_cancel_mad(cm_id_priv->msg);
@@ -2652,20 +2652,42 @@ static void cm_format_dreq(struct cm_dreq_msg *dreq_msg,
26522652
private_data_len);
26532653
}
26542654

2655-
static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv,
2656-
const void *private_data, u8 private_data_len)
2655+
static void cm_issue_dreq(struct cm_id_private *cm_id_priv)
26572656
{
26582657
struct ib_mad_send_buf *msg;
26592658
int ret;
26602659

26612660
lockdep_assert_held(&cm_id_priv->lock);
26622661

2662+
msg = cm_alloc_msg(cm_id_priv);
2663+
if (IS_ERR(msg))
2664+
return;
2665+
2666+
cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv, NULL, 0);
2667+
2668+
trace_icm_send_dreq(&cm_id_priv->id);
2669+
ret = ib_post_send_mad(msg, NULL);
2670+
if (ret)
2671+
cm_free_msg(msg);
2672+
}
2673+
2674+
int ib_send_cm_dreq(struct ib_cm_id *cm_id, const void *private_data,
2675+
u8 private_data_len)
2676+
{
2677+
struct cm_id_private *cm_id_priv =
2678+
container_of(cm_id, struct cm_id_private, id);
2679+
struct ib_mad_send_buf *msg;
2680+
unsigned long flags;
2681+
int ret;
2682+
26632683
if (private_data && private_data_len > IB_CM_DREQ_PRIVATE_DATA_SIZE)
26642684
return -EINVAL;
26652685

2686+
spin_lock_irqsave(&cm_id_priv->lock, flags);
26662687
if (cm_id_priv->id.state != IB_CM_ESTABLISHED) {
26672688
trace_icm_dreq_skipped(&cm_id_priv->id);
2668-
return -EINVAL;
2689+
ret = -EINVAL;
2690+
goto unlock;
26692691
}
26702692

26712693
if (cm_id_priv->id.lap_state == IB_CM_LAP_SENT ||
@@ -2675,7 +2697,8 @@ static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv,
26752697
msg = cm_alloc_priv_msg(cm_id_priv, IB_CM_DREQ_SENT);
26762698
if (IS_ERR(msg)) {
26772699
cm_enter_timewait(cm_id_priv);
2678-
return PTR_ERR(msg);
2700+
ret = PTR_ERR(msg);
2701+
goto unlock;
26792702
}
26802703

26812704
cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv,
@@ -2686,23 +2709,11 @@ static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv,
26862709
if (ret) {
26872710
cm_enter_timewait(cm_id_priv);
26882711
cm_free_priv_msg(msg);
2689-
return ret;
2712+
goto unlock;
26902713
}
26912714

26922715
cm_id_priv->id.state = IB_CM_DREQ_SENT;
2693-
return 0;
2694-
}
2695-
2696-
int ib_send_cm_dreq(struct ib_cm_id *cm_id, const void *private_data,
2697-
u8 private_data_len)
2698-
{
2699-
struct cm_id_private *cm_id_priv =
2700-
container_of(cm_id, struct cm_id_private, id);
2701-
unsigned long flags;
2702-
int ret;
2703-
2704-
spin_lock_irqsave(&cm_id_priv->lock, flags);
2705-
ret = cm_send_dreq_locked(cm_id_priv, private_data, private_data_len);
2716+
unlock:
27062717
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
27072718
return ret;
27082719
}

0 commit comments

Comments
 (0)