dapl_os_memzero(conn, sizeof(*conn));
dapl_os_lock_init(&conn->lock);
+ conn->refs++;
/* create CM_ID, bind to local device, create QP */
if (rdma_create_id(g_cm_events, &cm_id, (void *)conn, RDMA_PS_TCP)) {
}
/*
- * Called from consumer thread via dat_ep_free().
- * CANNOT be called from the async event processing thread
- * dapli_cma_event_cb() since a cm_id reference is held and
- * a deadlock will occur.
+ * Only called from consumer thread via dat_ep_free()
+ * accept, reject, or connect.
+ * Cannot be called from callback thread.
+ * rdma_destroy_id will block until rdma_get_cm_event is acked.
*/
-
void dapls_ib_cm_free(dp_ib_cm_handle_t conn, DAPL_EP *ep)
{
- struct rdma_cm_id *cm_id;
-
- if (conn == NULL)
- return;
-
dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " destroy_conn: conn %p id %d\n", conn, conn->cm_id);
+ " destroy_conn: conn %p id %d\n",
+ conn, conn->cm_id);
dapl_os_lock(&conn->lock);
- conn->destroy = 1;
+ conn->refs--;
+ dapl_os_unlock(&conn->lock);
- if (ep != NULL) {
+ /* block until event thread complete */
+ while (conn->refs)
+ dapl_os_sleep_usec(10000);
+
+ if (ep) {
ep->cm_handle = NULL;
ep->qp_handle = NULL;
ep->qp_state = IB_QP_STATE_ERROR;
}
- cm_id = conn->cm_id;
- conn->cm_id = NULL;
- dapl_os_unlock(&conn->lock);
-
- /*
- * rdma_destroy_id will force synchronization with async CM event
- * thread since it blocks until the in-process event reference
- * is cleared during our event processing call exit.
- */
- if (cm_id) {
- if (cm_id->qp)
- rdma_destroy_qp(cm_id);
-
- rdma_destroy_id(cm_id);
+ if (conn->cm_id) {
+ if (conn->cm_id->qp)
+ rdma_destroy_qp(conn->cm_id);
+ rdma_destroy_id(conn->cm_id);
}
+
dapl_os_free(conn, sizeof(*conn));
}
event->id->context = new_conn; /* update CM_ID context */
new_conn->sp = conn->sp;
new_conn->hca = conn->hca;
+ new_conn->refs++;
/* Get requesters connect data, setup for accept */
new_conn->params.responder_resources =
static void dapli_cm_active_cb(struct dapl_cm_id *conn,
struct rdma_cm_event *event)
{
+ DAPL_OS_LOCK *lock = &conn->lock;
+ ib_cm_events_t ib_cm_event;
+ const void *pdata = NULL;
+
dapl_dbg_log(DAPL_DBG_TYPE_CM,
" active_cb: conn %p id %d event %d\n",
conn, conn->cm_id, event->event);
- dapl_os_lock(&conn->lock);
- if (conn->destroy) {
- dapl_os_unlock(&conn->lock);
- return;
- }
- dapl_os_unlock(&conn->lock);
-
/* There is a chance that we can get events after
* the consumer calls disconnect in a pending state
* since the IB CM and uDAPL states are not shared.
conn->ep->param.ep_state = DAT_EP_STATE_DISCONNECTED;
dapl_os_unlock(&conn->ep->header.lock);
+ dapl_os_lock(lock);
switch (event->event) {
case RDMA_CM_EVENT_UNREACHABLE:
case RDMA_CM_EVENT_CONNECT_ERROR:
- {
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ "dapl_cma_active: CONN_ERR event=0x%x"
+ " status=%d %s DST %s, %d\n",
+ event->event, event->status,
+ (event->status == -ETIMEDOUT) ? "TIMEOUT" : "",
+ inet_ntoa(((struct sockaddr_in *)
+ &conn->cm_id->route.addr.dst_addr)->
+ sin_addr),
+ ntohs(((struct sockaddr_in *)
+ &conn->cm_id->route.addr.dst_addr)->
+ sin_port));
+
+ /* per DAT SPEC provider always returns UNREACHABLE */
+ ib_cm_event = IB_CME_DESTINATION_UNREACHABLE;
+ break;
+ case RDMA_CM_EVENT_REJECTED:
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
+ " dapli_cm_active_handler: REJECTED reason=%d\n",
+ event->status);
+
+ /* valid REJ from consumer will always contain private data */
+ if (event->status == 28 &&
+ event->param.conn.private_data_len) {
+ ib_cm_event = IB_CME_DESTINATION_REJECT_PRIVATE_DATA;
+ pdata =
+ (unsigned char *)event->param.conn.
+ private_data +
+ sizeof(struct dapl_pdata_hdr);
+ } else {
+ ib_cm_event = IB_CME_DESTINATION_REJECT;
dapl_log(DAPL_DBG_TYPE_WARN,
- "dapl_cma_active: CONN_ERR event=0x%x"
- " status=%d %s DST %s, %d\n",
- event->event, event->status,
- (event->status == -ETIMEDOUT) ? "TIMEOUT" : "",
+ "dapl_cma_active: non-consumer REJ,"
+ " reason=%d, DST %s, %d\n",
+ event->status,
inet_ntoa(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_addr),
+ &conn->cm_id->route.addr.
+ dst_addr)->sin_addr),
ntohs(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_port));
-
- /* per DAT SPEC provider always returns UNREACHABLE */
- dapl_evd_connection_callback(conn,
- IB_CME_DESTINATION_UNREACHABLE,
- NULL, conn->ep);
- break;
- }
- case RDMA_CM_EVENT_REJECTED:
- {
- ib_cm_events_t cm_event;
- unsigned char *pdata = NULL;
-
- dapl_dbg_log(DAPL_DBG_TYPE_CM,
- " dapli_cm_active_handler: REJECTED reason=%d\n",
- event->status);
-
- /* valid REJ from consumer will always contain private data */
- if (event->status == 28 &&
- event->param.conn.private_data_len) {
- cm_event =
- IB_CME_DESTINATION_REJECT_PRIVATE_DATA;
- pdata =
- (unsigned char *)event->param.conn.
- private_data +
- sizeof(struct dapl_pdata_hdr);
- } else {
- cm_event = IB_CME_DESTINATION_REJECT;
- dapl_log(DAPL_DBG_TYPE_WARN,
- "dapl_cma_active: non-consumer REJ,"
- " reason=%d, DST %s, %d\n",
- event->status,
- inet_ntoa(((struct sockaddr_in *)
- &conn->cm_id->route.addr.
- dst_addr)->sin_addr),
- ntohs(((struct sockaddr_in *)
- &conn->cm_id->route.addr.
- dst_addr)->sin_port));
- }
- dapl_evd_connection_callback(conn, cm_event, pdata,
- conn->ep);
- break;
+ &conn->cm_id->route.addr.
+ dst_addr)->sin_port));
}
+ break;
case RDMA_CM_EVENT_ESTABLISHED:
dapl_dbg_log(DAPL_DBG_TYPE_CM,
" active_cb: cm_id %d PORT %d CONNECTED to %s!\n",
conn->ep->param.local_port_qual =
PORT_TO_SID(rdma_get_src_port(conn->cm_id));
- dapl_evd_connection_callback(conn, IB_CME_CONNECTED,
- event->param.conn.private_data,
- conn->ep);
+ ib_cm_event = IB_CME_CONNECTED;
+ pdata = event->param.conn.private_data;
break;
-
case RDMA_CM_EVENT_DISCONNECTED:
dapl_dbg_log(DAPL_DBG_TYPE_CM,
" active_cb: DISC EVENT - EP %p\n",conn->ep);
rdma_disconnect(conn->cm_id); /* required for DREP */
+ ib_cm_event = IB_CME_DISCONNECTED;
/* validate EP handle */
- if (!DAPL_BAD_HANDLE(conn->ep, DAPL_MAGIC_EP))
- dapl_evd_connection_callback(conn,
- IB_CME_DISCONNECTED,
- NULL, conn->ep);
+ if (DAPL_BAD_HANDLE(conn->ep, DAPL_MAGIC_EP))
+ conn = NULL;
break;
default:
dapl_dbg_log(DAPL_DBG_TYPE_ERR,
" dapli_cm_active_cb_handler: Unexpected CM "
"event %d on ID 0x%p\n", event->event,
conn->cm_id);
+ conn = NULL;
break;
}
- return;
+ dapl_os_unlock(lock);
+ if (conn)
+ dapl_evd_connection_callback(conn, ib_cm_event, pdata, conn->ep);
}
static void dapli_cm_passive_cb(struct dapl_cm_id *conn,
struct rdma_cm_event *event)
{
- struct dapl_cm_id *new_conn;
-
+ ib_cm_events_t ib_cm_event;
+ struct dapl_cm_id *conn_recv = conn;
+ const void *pdata = NULL;
+
dapl_dbg_log(DAPL_DBG_TYPE_CM,
" passive_cb: conn %p id %d event %d\n",
conn, event->id, event->event);
dapl_os_lock(&conn->lock);
- if (conn->destroy) {
- dapl_os_unlock(&conn->lock);
- return;
- }
- dapl_os_unlock(&conn->lock);
switch (event->event) {
case RDMA_CM_EVENT_CONNECT_REQUEST:
/* create new conn object with new conn_id from event */
- new_conn = dapli_req_recv(conn, event);
-
- if (new_conn)
- dapls_cr_callback(new_conn,
- IB_CME_CONNECTION_REQUEST_PENDING,
- event->param.conn.private_data,
- new_conn->sp);
+ conn_recv = dapli_req_recv(conn, event);
+ ib_cm_event = IB_CME_CONNECTION_REQUEST_PENDING;
+ pdata = event->param.conn.private_data;
break;
case RDMA_CM_EVENT_UNREACHABLE:
case RDMA_CM_EVENT_CONNECT_ERROR:
sin_addr), ntohs(((struct sockaddr_in *)
&conn->cm_id->route.addr.
dst_addr)->sin_port));
-
- dapls_cr_callback(conn, IB_CME_DESTINATION_UNREACHABLE,
- NULL, conn->sp);
+ ib_cm_event = IB_CME_DESTINATION_UNREACHABLE;
break;
-
case RDMA_CM_EVENT_REJECTED:
- {
- /* will alwasys be abnormal NON-consumer from active side */
- dapl_log(DAPL_DBG_TYPE_WARN,
- "dapl_cm_passive: non-consumer REJ, reason=%d,"
- " DST %s, %d\n",
- event->status,
- inet_ntoa(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_addr),
- ntohs(((struct sockaddr_in *)
- &conn->cm_id->route.addr.dst_addr)->
- sin_port));
-
- dapls_cr_callback(conn, IB_CME_DESTINATION_REJECT,
- NULL, conn->sp);
- break;
- }
+ /* will alwasys be abnormal NON-consumer from active side */
+ dapl_log(DAPL_DBG_TYPE_WARN,
+ "dapl_cm_passive: non-consumer REJ, reason=%d,"
+ " DST %s, %d\n",
+ event->status,
+ inet_ntoa(((struct sockaddr_in *)
+ &conn->cm_id->route.addr.dst_addr)->
+ sin_addr),
+ ntohs(((struct sockaddr_in *)
+ &conn->cm_id->route.addr.dst_addr)->
+ sin_port));
+ ib_cm_event = IB_CME_DESTINATION_REJECT;
+ break;
case RDMA_CM_EVENT_ESTABLISHED:
dapl_dbg_log(DAPL_DBG_TYPE_CM,
" passive_cb: cm_id %p PORT %d CONNECTED from 0x%x!\n",
ntohl(((struct sockaddr_in *)
&conn->cm_id->route.addr.dst_addr)->
sin_addr.s_addr));
-
- dapls_cr_callback(conn, IB_CME_CONNECTED, NULL, conn->sp);
-
+ ib_cm_event = IB_CME_CONNECTED;
break;
case RDMA_CM_EVENT_DISCONNECTED:
rdma_disconnect(conn->cm_id); /* required for DREP */
+ ib_cm_event = IB_CME_DISCONNECTED;
/* validate SP handle context */
- if (!DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_PSP) ||
- !DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_RSP))
- dapls_cr_callback(conn,
- IB_CME_DISCONNECTED, NULL, conn->sp);
+ if (DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_PSP) &&
+ DAPL_BAD_HANDLE(conn->sp, DAPL_MAGIC_RSP))
+ conn_recv = NULL;
break;
default:
dapl_dbg_log(DAPL_DBG_TYPE_ERR, " passive_cb: "
"Unexpected CM event %d on ID 0x%p\n",
event->event, conn->cm_id);
+ conn_recv = NULL;
break;
}
- return;
+ dapl_os_unlock(&conn->lock);
+ if (conn_recv)
+ dapls_cr_callback(conn_recv, ib_cm_event, pdata, conn_recv->sp);
}
/************************ DAPL provider entry points **********************/
dapl_os_memzero(conn, sizeof(*conn));
dapl_os_lock_init(&conn->lock);
+ conn->refs++;
/* create CM_ID, bind to local device, create QP */
if (rdma_create_id
void dapli_cma_event_cb(void)
{
struct rdma_cm_event *event;
-
- dapl_dbg_log(DAPL_DBG_TYPE_UTIL, " cm_event()\n");
-
- /* process one CM event, fairness */
+
+ /* process one CM event, fairness, non-blocking */
if (!rdma_get_cm_event(g_cm_events, &event)) {
struct dapl_cm_id *conn;
dapl_dbg_log(DAPL_DBG_TYPE_CM,
" cm_event: EVENT=%d ID=%p LID=%p CTX=%p\n",
event->event, event->id, event->listen_id, conn);
+
+ /* cm_free is blocked waiting for ack */
+ dapl_os_lock(&conn->lock);
+ if (!conn->refs) {
+ dapl_os_unlock(&conn->lock);
+ rdma_ack_cm_event(event);
+ return;
+ }
+ conn->refs++;
+ dapl_os_unlock(&conn->lock);
switch (event->event) {
case RDMA_CM_EVENT_ADDR_RESOLVED:
#endif
break;
default:
- dapl_dbg_log(DAPL_DBG_TYPE_WARN,
+ dapl_dbg_log(DAPL_DBG_TYPE_CM,
" cm_event: UNEXPECTED EVENT=%p ID=%p CTX=%p\n",
event->event, event->id,
event->id->context);
break;
}
+
/* ack event, unblocks destroy_cm_id in consumer threads */
rdma_ack_cm_event(event);
- }
+
+ dapl_os_lock(&conn->lock);
+ conn->refs--;
+ dapl_os_unlock(&conn->lock);
+ }
}
/*