Skip to content

Commit c206f8b

Browse files
committed
RDMA/cm: Make it clearer how concurrency works in cm_req_handler()
ib_crate_cm_id() immediately places the id in the xarray, and publishes it into the remote_id and remote_qpn rbtrees. This makes it visible to other threads before it is fully set up. It appears the thinking here was that the states IB_CM_IDLE and IB_CM_REQ_RCVD do not allow any MAD handler or lookup in the remote_id and remote_qpn rbtrees to advance. However, cm_rej_handler() does take an action on IB_CM_REQ_RCVD, which is not really expected by the design. Make the whole thing clearer: - Keep the new cm_id out of the xarray until it is completely set up. This directly prevents MAD handlers and all rbtree lookups from seeing the pointer. - Move all the trivial setup right to the top so it is obviously done before any concurrency begins - Move the mutation of the cm_id_priv out of cm_match_id() and into the caller so the state transition is obvious - Place the manipulation of the work_list at the end, under lock, after the cm_id is placed in the xarray. The work_count cannot change on an ID outside the xarray. - Add some comments Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Leon Romanovsky <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 083bfdb commit c206f8b

File tree

1 file changed

+57
-42
lines changed
  • drivers/infiniband/core

1 file changed

+57
-42
lines changed

drivers/infiniband/core/cm.c

Lines changed: 57 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,14 +1958,10 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
19581958
cm_issue_rej(work->port, work->mad_recv_wc,
19591959
IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ,
19601960
NULL, 0);
1961-
goto out;
1961+
return NULL;
19621962
}
19631963
refcount_inc(&listen_cm_id_priv->refcount);
1964-
refcount_inc(&cm_id_priv->refcount);
1965-
cm_id_priv->id.state = IB_CM_REQ_RCVD;
1966-
atomic_inc(&cm_id_priv->work_count);
19671964
spin_unlock_irq(&cm.lock);
1968-
out:
19691965
return listen_cm_id_priv;
19701966
}
19711967

@@ -2007,7 +2003,6 @@ static void cm_process_routed_req(struct cm_req_msg *req_msg, struct ib_wc *wc)
20072003

20082004
static int cm_req_handler(struct cm_work *work)
20092005
{
2010-
struct ib_cm_id *cm_id;
20112006
struct cm_id_private *cm_id_priv, *listen_cm_id_priv;
20122007
struct cm_req_msg *req_msg;
20132008
const struct ib_global_route *grh;
@@ -2016,13 +2011,33 @@ static int cm_req_handler(struct cm_work *work)
20162011

20172012
req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad;
20182013

2019-
cm_id = ib_create_cm_id(work->port->cm_dev->ib_device, NULL, NULL);
2020-
if (IS_ERR(cm_id))
2021-
return PTR_ERR(cm_id);
2014+
cm_id_priv =
2015+
cm_alloc_id_priv(work->port->cm_dev->ib_device, NULL, NULL);
2016+
if (IS_ERR(cm_id_priv))
2017+
return PTR_ERR(cm_id_priv);
20222018

2023-
cm_id_priv = container_of(cm_id, struct cm_id_private, id);
20242019
cm_id_priv->id.remote_id =
20252020
cpu_to_be32(IBA_GET(CM_REQ_LOCAL_COMM_ID, req_msg));
2021+
cm_id_priv->id.service_id =
2022+
cpu_to_be64(IBA_GET(CM_REQ_SERVICE_ID, req_msg));
2023+
cm_id_priv->id.service_mask = ~cpu_to_be64(0);
2024+
cm_id_priv->tid = req_msg->hdr.tid;
2025+
cm_id_priv->timeout_ms = cm_convert_to_ms(
2026+
IBA_GET(CM_REQ_LOCAL_CM_RESPONSE_TIMEOUT, req_msg));
2027+
cm_id_priv->max_cm_retries = IBA_GET(CM_REQ_MAX_CM_RETRIES, req_msg);
2028+
cm_id_priv->remote_qpn =
2029+
cpu_to_be32(IBA_GET(CM_REQ_LOCAL_QPN, req_msg));
2030+
cm_id_priv->initiator_depth =
2031+
IBA_GET(CM_REQ_RESPONDER_RESOURCES, req_msg);
2032+
cm_id_priv->responder_resources =
2033+
IBA_GET(CM_REQ_INITIATOR_DEPTH, req_msg);
2034+
cm_id_priv->path_mtu = IBA_GET(CM_REQ_PATH_PACKET_PAYLOAD_MTU, req_msg);
2035+
cm_id_priv->pkey = cpu_to_be16(IBA_GET(CM_REQ_PARTITION_KEY, req_msg));
2036+
cm_id_priv->sq_psn = cpu_to_be32(IBA_GET(CM_REQ_STARTING_PSN, req_msg));
2037+
cm_id_priv->retry_count = IBA_GET(CM_REQ_RETRY_COUNT, req_msg);
2038+
cm_id_priv->rnr_retry_count = IBA_GET(CM_REQ_RNR_RETRY_COUNT, req_msg);
2039+
cm_id_priv->qp_type = cm_req_get_qp_type(req_msg);
2040+
20262041
ret = cm_init_av_for_response(work->port, work->mad_recv_wc->wc,
20272042
work->mad_recv_wc->recv_buf.grh,
20282043
&cm_id_priv->av);
@@ -2034,27 +2049,26 @@ static int cm_req_handler(struct cm_work *work)
20342049
ret = PTR_ERR(cm_id_priv->timewait_info);
20352050
goto destroy;
20362051
}
2037-
cm_id_priv->timewait_info->work.remote_id =
2038-
cpu_to_be32(IBA_GET(CM_REQ_LOCAL_COMM_ID, req_msg));
2052+
cm_id_priv->timewait_info->work.remote_id = cm_id_priv->id.remote_id;
20392053
cm_id_priv->timewait_info->remote_ca_guid =
20402054
cpu_to_be64(IBA_GET(CM_REQ_LOCAL_CA_GUID, req_msg));
2041-
cm_id_priv->timewait_info->remote_qpn =
2042-
cpu_to_be32(IBA_GET(CM_REQ_LOCAL_QPN, req_msg));
2055+
cm_id_priv->timewait_info->remote_qpn = cm_id_priv->remote_qpn;
2056+
2057+
/*
2058+
* Note that the ID pointer is not in the xarray at this point,
2059+
* so this set is only visible to the local thread.
2060+
*/
2061+
cm_id_priv->id.state = IB_CM_REQ_RCVD;
20432062

20442063
listen_cm_id_priv = cm_match_req(work, cm_id_priv);
20452064
if (!listen_cm_id_priv) {
20462065
pr_debug("%s: local_id %d, no listen_cm_id_priv\n", __func__,
2047-
be32_to_cpu(cm_id->local_id));
2066+
be32_to_cpu(cm_id_priv->id.local_id));
2067+
cm_id_priv->id.state = IB_CM_IDLE;
20482068
ret = -EINVAL;
20492069
goto destroy;
20502070
}
20512071

2052-
cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler;
2053-
cm_id_priv->id.context = listen_cm_id_priv->id.context;
2054-
cm_id_priv->id.service_id =
2055-
cpu_to_be64(IBA_GET(CM_REQ_SERVICE_ID, req_msg));
2056-
cm_id_priv->id.service_mask = ~cpu_to_be64(0);
2057-
20582072
cm_process_routed_req(req_msg, work->mad_recv_wc->wc);
20592073

20602074
memset(&work->path[0], 0, sizeof(work->path[0]));
@@ -2092,10 +2106,10 @@ static int cm_req_handler(struct cm_work *work)
20922106
work->port->port_num, 0,
20932107
&work->path[0].sgid);
20942108
if (err)
2095-
ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_GID,
2109+
ib_send_cm_rej(&cm_id_priv->id, IB_CM_REJ_INVALID_GID,
20962110
NULL, 0, NULL, 0);
20972111
else
2098-
ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_GID,
2112+
ib_send_cm_rej(&cm_id_priv->id, IB_CM_REJ_INVALID_GID,
20992113
&work->path[0].sgid,
21002114
sizeof(work->path[0].sgid),
21012115
NULL, 0);
@@ -2105,39 +2119,40 @@ static int cm_req_handler(struct cm_work *work)
21052119
ret = cm_init_av_by_path(&work->path[1], NULL,
21062120
&cm_id_priv->alt_av, cm_id_priv);
21072121
if (ret) {
2108-
ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_ALT_GID,
2122+
ib_send_cm_rej(&cm_id_priv->id,
2123+
IB_CM_REJ_INVALID_ALT_GID,
21092124
&work->path[0].sgid,
21102125
sizeof(work->path[0].sgid), NULL, 0);
21112126
goto rejected;
21122127
}
21132128
}
2114-
cm_id_priv->tid = req_msg->hdr.tid;
2115-
cm_id_priv->timeout_ms = cm_convert_to_ms(
2116-
IBA_GET(CM_REQ_LOCAL_CM_RESPONSE_TIMEOUT, req_msg));
2117-
cm_id_priv->max_cm_retries = IBA_GET(CM_REQ_MAX_CM_RETRIES, req_msg);
2118-
cm_id_priv->remote_qpn =
2119-
cpu_to_be32(IBA_GET(CM_REQ_LOCAL_QPN, req_msg));
2120-
cm_id_priv->initiator_depth =
2121-
IBA_GET(CM_REQ_RESPONDER_RESOURCES, req_msg);
2122-
cm_id_priv->responder_resources =
2123-
IBA_GET(CM_REQ_INITIATOR_DEPTH, req_msg);
2124-
cm_id_priv->path_mtu = IBA_GET(CM_REQ_PATH_PACKET_PAYLOAD_MTU, req_msg);
2125-
cm_id_priv->pkey = cpu_to_be16(IBA_GET(CM_REQ_PARTITION_KEY, req_msg));
2126-
cm_id_priv->sq_psn = cpu_to_be32(IBA_GET(CM_REQ_STARTING_PSN, req_msg));
2127-
cm_id_priv->retry_count = IBA_GET(CM_REQ_RETRY_COUNT, req_msg);
2128-
cm_id_priv->rnr_retry_count = IBA_GET(CM_REQ_RNR_RETRY_COUNT, req_msg);
2129-
cm_id_priv->qp_type = cm_req_get_qp_type(req_msg);
21302129

2130+
cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler;
2131+
cm_id_priv->id.context = listen_cm_id_priv->id.context;
21312132
cm_format_req_event(work, cm_id_priv, &listen_cm_id_priv->id);
2133+
2134+
/* Now MAD handlers can see the new ID */
2135+
spin_lock_irq(&cm_id_priv->lock);
2136+
cm_finalize_id(cm_id_priv);
2137+
2138+
/* Refcount belongs to the event, pairs with cm_process_work() */
2139+
refcount_inc(&cm_id_priv->refcount);
2140+
atomic_inc(&cm_id_priv->work_count);
2141+
spin_unlock_irq(&cm_id_priv->lock);
21322142
cm_process_work(cm_id_priv, work);
2143+
/*
2144+
* Since this ID was just created and was not made visible to other MAD
2145+
* handlers until the cm_finalize_id() above we know that the
2146+
* cm_process_work() will deliver the event and the listen_cm_id
2147+
* embedded in the event can be derefed here.
2148+
*/
21332149
cm_deref_id(listen_cm_id_priv);
21342150
return 0;
21352151

21362152
rejected:
2137-
refcount_dec(&cm_id_priv->refcount);
21382153
cm_deref_id(listen_cm_id_priv);
21392154
destroy:
2140-
ib_destroy_cm_id(cm_id);
2155+
ib_destroy_cm_id(&cm_id_priv->id);
21412156
return ret;
21422157
}
21432158

0 commit comments

Comments
 (0)