static void handle_accept_conn(struct poll_fd_mgr *poll_mgr, struct poll_fd_info *poll_info) { struct fi_eq_cm_entry cm_entry; struct fi_eq_err_entry err_entry; struct tcpx_ep *ep; int ret; assert(poll_info->fid->fclass == FI_CLASS_EP); ep = container_of(poll_info->fid, struct tcpx_ep, util_ep.ep_fid.fid); ret = tx_cm_data(ep->conn_fd, ofi_ctrl_connresp, poll_info); if (ret) goto err; cm_entry.fid = poll_info->fid; ret = (int) fi_eq_write(&ep->util_ep.eq->eq_fid, FI_CONNECTED, &cm_entry, sizeof(cm_entry), 0); if (ret < 0) { FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "Error writing to EQ\n"); } ret = fi_fd_nonblock(ep->conn_fd); return; err: memset(&err_entry, 0, sizeof err_entry); err_entry.fid = poll_info->fid; err_entry.context = poll_info->fid->context; err_entry.err = ret; fi_eq_write(&ep->util_ep.eq->eq_fid, FI_SHUTDOWN, &err_entry, sizeof(err_entry), UTIL_FLAG_ERROR); }
DIRECT_FN STATIC int gnix_shutdown(struct fid_ep *ep, uint64_t flags) { int ret; struct gnix_fid_ep *ep_priv; struct fi_eq_cm_entry eq_entry = {0}; if (!ep) return -FI_EINVAL; ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid.fid); COND_ACQUIRE(ep_priv->requires_lock, &ep_priv->vc_lock); eq_entry.fid = &ep_priv->ep_fid.fid; ret = fi_eq_write(&ep_priv->eq->eq_fid, FI_SHUTDOWN, &eq_entry, sizeof(eq_entry), 0); if (ret != sizeof(eq_entry)) { GNIX_WARN(FI_LOG_EP_CTRL, "fi_eq_write failed, err: %d\n", ret); } else { ret = FI_SUCCESS; } COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock); return ret; }
static int proc_conn_resp(struct poll_fd_mgr *poll_mgr, struct poll_fd_info *poll_info, struct tcpx_ep *ep, int index) { struct ofi_ctrl_hdr conn_resp; struct fi_eq_cm_entry *cm_entry; int ret = FI_SUCCESS; assert(poll_mgr->poll_fds[index].revents == POLLIN); ret = rx_cm_data(ep->conn_fd, &conn_resp, ofi_ctrl_connresp, poll_info); if (ret) return ret; cm_entry = calloc(1, sizeof(*cm_entry) + poll_info->cm_data_sz); if (!cm_entry) { FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "mem alloc failed\n"); return -FI_ENOMEM; } cm_entry->fid = poll_info->fid; memcpy(cm_entry->data, poll_info->cm_data, poll_info->cm_data_sz); ret = (int) fi_eq_write(&ep->util_ep.eq->eq_fid, FI_CONNECTED, cm_entry, sizeof(*cm_entry) + poll_info->cm_data_sz, 0); if (ret < 0) { FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "Error writing to EQ\n"); goto err; } ret = fi_fd_nonblock(ep->conn_fd); err: free(cm_entry); return ret; }
static int proc_conn_resp(struct tcpx_cm_context *cm_ctx, struct tcpx_ep *ep) { struct ofi_ctrl_hdr conn_resp; struct fi_eq_cm_entry *cm_entry; ssize_t len; int ret = FI_SUCCESS; ret = rx_cm_data(ep->conn_fd, &conn_resp, ofi_ctrl_connresp, cm_ctx); if (ret) return ret; cm_entry = calloc(1, sizeof(*cm_entry) + cm_ctx->cm_data_sz); if (!cm_entry) return -FI_ENOMEM; cm_entry->fid = cm_ctx->fid; memcpy(cm_entry->data, cm_ctx->cm_data, cm_ctx->cm_data_sz); ret = tcpx_ep_msg_xfer_enable(ep); if (ret) goto err; len = fi_eq_write(&ep->util_ep.eq->eq_fid, FI_CONNECTED, cm_entry, sizeof(*cm_entry) + cm_ctx->cm_data_sz, 0); if (len < 0) { ret = (int) len; goto err; } err: free(cm_entry); return ret; }
static void handle_connreq(struct poll_fd_mgr *poll_mgr, struct poll_fd_info *poll_info) { struct tcpx_conn_handle *handle; struct tcpx_pep *pep; struct fi_eq_cm_entry *cm_entry; struct ofi_ctrl_hdr conn_req; SOCKET sock; int ret; assert(poll_info->fid->fclass == FI_CLASS_PEP); pep = container_of(poll_info->fid, struct tcpx_pep, util_pep.pep_fid.fid); sock = accept(pep->sock, NULL, 0); if (sock < 0) { FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "accept error: %d\n", ofi_sockerr()); return; } ret = rx_cm_data(sock, &conn_req, ofi_ctrl_connreq, poll_info); if (ret) { FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "cm data recv failed \n"); goto err1; } handle = calloc(1, sizeof(*handle)); if (!handle) goto err1; cm_entry = calloc(1, sizeof(*cm_entry) + poll_info->cm_data_sz); if (!cm_entry) goto err2; handle->conn_fd = sock; cm_entry->fid = poll_info->fid; cm_entry->info = fi_dupinfo(&pep->info); if (!cm_entry->info) goto err3; cm_entry->info->handle = &handle->handle; memcpy(cm_entry->data, poll_info->cm_data, poll_info->cm_data_sz); ret = (int) fi_eq_write(&pep->util_pep.eq->eq_fid, FI_CONNREQ, cm_entry, sizeof(*cm_entry) + poll_info->cm_data_sz, 0); if (ret < 0) { FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "Error writing to EQ\n"); goto err4; } free(cm_entry); return; err4: fi_freeinfo(cm_entry->info); err3: free(cm_entry); err2: free(handle); err1: ofi_close_socket(sock); }
static ssize_t hook_eq_write(struct fid_eq *eq, uint32_t event, const void *buf, size_t len, uint64_t flags) { struct hook_eq *myeq = container_of(eq, struct hook_eq, eq); return fi_eq_write(myeq->heq, event, buf, len, flags); }
static void ip_av_write_event(struct util_av *av, uint64_t data, int err, void *context) { struct fi_eq_err_entry entry; size_t size; ssize_t ret; uint64_t flags; entry.fid = &av->av_fid.fid; entry.context = context; entry.data = data; if (err) { FI_INFO(av->prov, FI_LOG_AV, "writing error entry to EQ\n"); entry.err = err; size = sizeof(struct fi_eq_err_entry); flags = UTIL_FLAG_ERROR; } else { FI_DBG(av->prov, FI_LOG_AV, "writing entry to EQ\n"); size = sizeof(struct fi_eq_entry); flags = 0; } ret = fi_eq_write(&av->eq->eq_fid, FI_AV_COMPLETE, &entry, size, flags); if (ret != size) FI_WARN(av->prov, FI_LOG_AV, "error writing to EQ\n"); }
/* Process an incoming connection request at a listening PEP. */ static int __gnix_pep_connreq(struct gnix_fid_pep *pep, int fd) { int ret; struct gnix_pep_sock_conn *conn; struct fi_eq_cm_entry *eq_entry; int eqe_size; /* Create and initialize a new connection request. */ conn = calloc(1, sizeof(*conn)); if (!conn) { GNIX_WARN(FI_LOG_EP_CTRL, "Failed to alloc accepted socket conn\n"); return -FI_ENOMEM; } conn->fid.fclass = FI_CLASS_CONNREQ; conn->fid.context = pep; conn->sock_fd = fd; /* Pull request data from the listening socket. */ conn->bytes_read += read(fd, &conn->req, sizeof(conn->req)); if (conn->bytes_read != sizeof(conn->req)) { /* TODO Wait for more bytes. */ GNIX_FATAL(FI_LOG_EP_CTRL, "Unexpected read size\n"); } conn->req.info.src_addr = &conn->req.src_addr; conn->req.info.dest_addr = &conn->req.dest_addr; conn->req.info.tx_attr = &conn->req.tx_attr; conn->req.info.rx_attr = &conn->req.rx_attr; conn->req.info.ep_attr = &conn->req.ep_attr; conn->req.info.domain_attr = &conn->req.domain_attr; conn->req.info.fabric_attr = &conn->req.fabric_attr; conn->req.info.domain_attr->name = NULL; conn->req.info.fabric_attr->name = NULL; conn->req.info.fabric_attr->prov_name = NULL; conn->info = &conn->req.info; conn->info->handle = &conn->fid; /* Tell user of a new conn req via the EQ. */ eq_entry = (struct fi_eq_cm_entry *)conn->req.eqe_buf; eq_entry->fid = &pep->pep_fid.fid; eq_entry->info = fi_dupinfo(conn->info); eqe_size = sizeof(*eq_entry) + conn->req.cm_data_len; ret = fi_eq_write(&pep->eq->eq_fid, FI_CONNREQ, eq_entry, eqe_size, 0); if (ret != eqe_size) { GNIX_WARN(FI_LOG_EP_CTRL, "fi_eq_write failed, err: %d\n", ret); fi_freeinfo(conn->info); free(conn); return ret; } GNIX_DEBUG(FI_LOG_EP_CTRL, "Added FI_CONNREQ EQE: %p, %p\n", pep->eq, pep); return FI_SUCCESS; }
static void server_send_cm_accept(struct util_wait *wait, struct tcpx_cm_context *cm_ctx) { struct fi_eq_cm_entry cm_entry = {0}; struct fi_eq_err_entry err_entry; struct tcpx_ep *ep; int ret; assert(cm_ctx->fid->fclass == FI_CLASS_EP); ep = container_of(cm_ctx->fid, struct tcpx_ep, util_ep.ep_fid.fid); ret = tx_cm_data(ep->conn_fd, ofi_ctrl_connresp, cm_ctx); if (ret) goto err; cm_entry.fid = cm_ctx->fid; ret = (int) fi_eq_write(&ep->util_ep.eq->eq_fid, FI_CONNECTED, &cm_entry, sizeof(cm_entry), 0); if (ret < 0) { FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "Error writing to EQ\n"); } ret = ofi_wait_fd_del(wait, ep->conn_fd); if (ret) { FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "Could not remove fd from wait\n"); goto err; } ret = tcpx_ep_msg_xfer_enable(ep); if (ret) goto err; FI_DBG(&tcpx_prov, FI_LOG_EP_CTRL, "Connection Accept Successful\n"); free(cm_ctx); return; err: memset(&err_entry, 0, sizeof err_entry); err_entry.fid = cm_ctx->fid; err_entry.context = cm_ctx->fid->context; err_entry.err = -ret; free(cm_ctx); fi_eq_write(&ep->util_ep.eq->eq_fid, FI_NOTIFY, &err_entry, sizeof(err_entry), UTIL_FLAG_ERROR); }
static void server_recv_connreq(struct util_wait *wait, struct tcpx_cm_context *cm_ctx) { struct tcpx_conn_handle *handle; struct fi_eq_cm_entry *cm_entry; struct ofi_ctrl_hdr conn_req; int ret; assert(cm_ctx->fid->fclass == FI_CLASS_CONNREQ); handle = container_of(cm_ctx->fid, struct tcpx_conn_handle, handle); ret = rx_cm_data(handle->conn_fd, &conn_req, ofi_ctrl_connreq, cm_ctx); if (ret) goto err1; cm_entry = calloc(1, sizeof(*cm_entry) + cm_ctx->cm_data_sz); if (!cm_entry) goto err1; cm_entry->fid = &handle->pep->util_pep.pep_fid.fid; cm_entry->info = fi_dupinfo(&handle->pep->info); if (!cm_entry->info) goto err2; cm_entry->info->handle = &handle->handle; memcpy(cm_entry->data, cm_ctx->cm_data, cm_ctx->cm_data_sz); ret = (int) fi_eq_write(&handle->pep->util_pep.eq->eq_fid, FI_CONNREQ, cm_entry, sizeof(*cm_entry) + cm_ctx->cm_data_sz, 0); if (ret < 0) { FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "Error writing to EQ\n"); goto err3; } ret = ofi_wait_fd_del(wait, handle->conn_fd); if (ret) FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "fd deletion from ofi_wait failed\n"); free(cm_entry); free(cm_ctx); return; err3: fi_freeinfo(cm_entry->info); err2: free(cm_entry); err1: ofi_wait_fd_del(wait, handle->conn_fd); ofi_close_socket(handle->conn_fd); free(cm_ctx); free(handle); }
static void tcpx_report_error(struct tcpx_ep *tcpx_ep, int err) { struct fi_eq_err_entry err_entry = {0}; tcpx_cq_report_xfer_fail(tcpx_ep, err); err_entry.fid = &tcpx_ep->util_ep.ep_fid.fid; err_entry.context = tcpx_ep->util_ep.ep_fid.fid.context; err_entry.err = -err; fi_eq_write(&tcpx_ep->util_ep.eq->eq_fid, FI_NOTIFY, &err_entry, sizeof(err_entry), UTIL_FLAG_ERROR); }
/* * Tests: * - write overflow */ static int eq_write_overflow() { struct fi_eq_entry entry; int testret; int ret; int i; testret = FAIL; ret = create_eq(32, FI_WRITE, FI_WAIT_NONE); if (ret != 0) { sprintf(err_buf, "fi_eq_open ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* Insert some events */ for (i = 0; i < 32; ++i) { entry.fid = &fabric->fid; entry.context = (void *)(uintptr_t)i; ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } } ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != -FI_EAGAIN && ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write of full EQ returned %d", ret); goto fail; } testret = PASS; fail: FT_CLOSE_FID(eq); return TEST_RET_VAL(ret, testret); }
static void psmx_av_post_completion(struct psmx_fid_av *av, void *context, uint64_t data, int prov_errno) { if (prov_errno) { struct fi_eq_err_entry entry; entry.fid = &av->av.fid; entry.context = context; entry.data = data; entry.err = -psmx_errno(prov_errno); entry.prov_errno = prov_errno; entry.err_data = NULL; entry.err_data_size = 0; fi_eq_write(av->eq, FI_AV_COMPLETE, &entry, sizeof(entry), UTIL_FLAG_ERROR); } else { struct fi_eq_entry entry; entry.fid = &av->av.fid; entry.context = context; entry.data = data; fi_eq_write(av->eq, FI_AV_COMPLETE, &entry, sizeof(entry), 0); } }
static void client_send_connreq(struct util_wait *wait, struct tcpx_cm_context *cm_ctx) { struct tcpx_ep *ep; struct fi_eq_err_entry err_entry; socklen_t len; int status, ret = FI_SUCCESS; FI_DBG(&tcpx_prov, FI_LOG_EP_CTRL, "client send connreq\n"); assert(cm_ctx->fid->fclass == FI_CLASS_EP); ep = container_of(cm_ctx->fid, struct tcpx_ep, util_ep.ep_fid.fid); len = sizeof(status); ret = getsockopt(ep->conn_fd, SOL_SOCKET, SO_ERROR, (char *) &status, &len); if (ret < 0 || status) { FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "connection failure\n"); ret = (ret < 0)? -ofi_sockerr() : status; goto err; } ret = tx_cm_data(ep->conn_fd, ofi_ctrl_connreq, cm_ctx); if (ret) goto err; ret = ofi_wait_fd_del(wait, ep->conn_fd); if (ret) goto err; cm_ctx->type = CLIENT_RECV_CONNRESP; ret = ofi_wait_fd_add(wait, ep->conn_fd, FI_EPOLL_IN, tcpx_eq_wait_try_func, NULL, cm_ctx); if (ret) goto err; wait->signal(wait); return; err: memset(&err_entry, 0, sizeof err_entry); err_entry.fid = cm_ctx->fid; err_entry.context = cm_ctx->fid->context; err_entry.err = -ret; free(cm_ctx); fi_eq_write(&ep->util_ep.eq->eq_fid, FI_NOTIFY, &err_entry, sizeof(err_entry), UTIL_FLAG_ERROR); }
int tcpx_ep_shutdown_report(struct tcpx_ep *ep, fid_t fid) { struct fi_eq_cm_entry cm_entry = {0}; ssize_t len; if (ep->cm_state == TCPX_EP_SHUTDOWN) return FI_SUCCESS; tcpx_cq_report_xfer_fail(ep, -FI_ENOTCONN); ep->cm_state = TCPX_EP_SHUTDOWN; cm_entry.fid = fid; len = fi_eq_write(&ep->util_ep.eq->eq_fid, FI_SHUTDOWN, &cm_entry, sizeof(cm_entry), 0); if (len < 0) return (int) len; return FI_SUCCESS; }
static int insert_events(size_t count) { struct fi_eq_entry entry; size_t i; int ret; for (i = 0; i < count; i++) { ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write ret=%d, %s", ret, fi_strerror(-ret)); return ret; } } return FI_SUCCESS; }
static void client_recv_connresp(struct util_wait *wait, struct tcpx_cm_context *cm_ctx) { struct fi_eq_err_entry err_entry = { 0 }; struct tcpx_ep *ep; ssize_t ret; assert(cm_ctx->fid->fclass == FI_CLASS_EP); ep = container_of(cm_ctx->fid, struct tcpx_ep, util_ep.ep_fid.fid); ret = ofi_wait_fd_del(wait, ep->conn_fd); if (ret) { FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "Could not remove fd from wait\n"); goto err; } ret = proc_conn_resp(cm_ctx, ep); if (ret) goto err; FI_DBG(&tcpx_prov, FI_LOG_EP_CTRL, "Received Accept from server\n"); free(cm_ctx); return; err: err_entry.fid = cm_ctx->fid; err_entry.context = cm_ctx->fid->context; err_entry.err = -ret; if (cm_ctx->cm_data_sz) { err_entry.err_data = calloc(1, cm_ctx->cm_data_sz); if (OFI_LIKELY(err_entry.err_data != NULL)) { memcpy(err_entry.err_data, cm_ctx->cm_data, cm_ctx->cm_data_sz); err_entry.err_data_size = cm_ctx->cm_data_sz; } } FI_DBG(&tcpx_prov, FI_LOG_EP_CTRL, "fi_eq_write the conn refused %"PRId64"\n", ret); free(cm_ctx); /* `err_entry.err_data` must live until it is passed to user */ ret = fi_eq_write(&ep->util_ep.eq->eq_fid, FI_NOTIFY, &err_entry, sizeof(err_entry), UTIL_FLAG_ERROR); if (OFI_UNLIKELY(ret < 0)) { free(err_entry.err_data); } }
static void handle_connect(struct poll_fd_mgr *poll_mgr, int index) { struct tcpx_ep *ep; struct poll_fd_info *poll_info = &poll_mgr->poll_info[index]; struct fi_eq_err_entry err_entry; int ret; assert(poll_info->fid->fclass == FI_CLASS_EP); ep = container_of(poll_info->fid, struct tcpx_ep, util_ep.ep_fid.fid); switch (poll_info->state) { case ESTABLISH_CONN: ret = send_conn_req(poll_mgr, poll_info, ep, index); if (ret) goto err; poll_info->state = RCV_RESP; poll_mgr->poll_fds[index].events = POLLIN; break; case RCV_RESP: ret = proc_conn_resp(poll_mgr, poll_info, ep, index); if (ret) goto err; poll_info->state = CONNECT_DONE; break; default: FI_WARN(&tcpx_prov, FI_LOG_EP_CTRL, "Invalid connection state\n"); ret = -FI_EINVAL; goto err; } return; err: memset(&err_entry, 0, sizeof err_entry); err_entry.fid = poll_info->fid; err_entry.context = poll_info->fid->context; err_entry.err = ret; poll_info->state = CONNECT_DONE; fi_eq_write(&ep->util_ep.eq->eq_fid, FI_SHUTDOWN, &err_entry, sizeof(err_entry), UTIL_FLAG_ERROR); }
/* * Tests: * - extracting FD from EQ with FI_WAIT_FD * - wait on fd with nothing pending * - wait on fd with event pending */ static int eq_wait_fd_poll() { int fd; struct fi_eq_entry entry; struct pollfd pfd; struct fid *fids[1]; int testret; int ret; testret = FAIL; ret = create_eq(32, FI_WRITE, FI_WAIT_FD); if (ret != 0) { sprintf(err_buf, "fi_eq_open ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } ret = fi_control(&eq->fid, FI_GETWAIT, &fd); if (ret != 0) { sprintf(err_buf, "fi_control ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } fids[0] = &eq->fid; if (fi_trywait(fabric, fids, 1) != FI_SUCCESS) { sprintf(err_buf, "fi_trywait ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } pfd.fd = fd; pfd.events = POLLIN; ret = poll(&pfd, 1, 0); if (ret < 0) { sprintf(err_buf, "poll errno=%d, %s", errno, fi_strerror(-errno)); goto fail; } if (ret > 0) { sprintf(err_buf, "poll returned %d, should be 0", ret); goto fail; } /* write an event */ entry.fid = &eq->fid; entry.context = eq; ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } pfd.fd = fd; pfd.events = POLLIN; ret = poll(&pfd, 1, 0); if (ret < 0) { sprintf(err_buf, "poll errno=%d, %s", errno, fi_strerror(-errno)); goto fail; } if (ret != 1) { sprintf(err_buf, "poll returned %d, should be 1", ret); goto fail; } testret = PASS; fail: FT_CLOSE_FID(eq); return TEST_RET_VAL(ret, testret); }
/* * Tests: * - sread with event pending * - sread with no event pending */ static int eq_wait_fd_sread() { struct fi_eq_entry entry; uint32_t event; int64_t elapsed; int testret; int ret; testret = FAIL; ret = create_eq(32, FI_WRITE, FI_WAIT_FD); if (ret != 0) { sprintf(err_buf, "fi_eq_open ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* timed sread on empty EQ, 2s timeout */ ft_start(); ret = fi_eq_sread(eq, &event, &entry, sizeof(entry), 2000, 0); if (ret != -FI_EAGAIN) { sprintf(err_buf, "fi_eq_read of empty EQ returned %d", ret); goto fail; } /* check timeout accuracy */ ft_stop(); elapsed = get_elapsed(&start, &end, MILLI); if (elapsed < 1500 || elapsed > 2500) { sprintf(err_buf, "fi_eq_sread slept %d ms, expected 2000", (int)elapsed); goto fail; } /* write an event */ entry.fid = &eq->fid; entry.context = eq; ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* timed sread on EQ with event, 2s timeout */ ft_start(); event = ~0; memset(&entry, 0, sizeof(entry)); ret = fi_eq_sread(eq, &event, &entry, sizeof(entry), 2000, 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_read ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* check that no undue waiting occurred */ ft_stop(); elapsed = get_elapsed(&start, &end, MILLI); if (elapsed > 5) { sprintf(err_buf, "fi_eq_sread slept %d ms, expected immediate return", (int)elapsed); goto fail; } if (event != FI_NOTIFY) { sprintf(err_buf, "fi_eq_sread: event = %d, should be %d\n", event, FI_NOTIFY); goto fail; } if (entry.fid != &eq->fid) { sprintf(err_buf, "fi_eq_sread: fid mismatch: %p should be %p\n", entry.fid, &eq->fid); goto fail; } if (entry.context != eq) { sprintf(err_buf, "fi_eq_sread: context mismatch: %p should be %p\n", entry.context, eq); goto fail; } testret = PASS; fail: FT_CLOSE_FID(eq); return TEST_RET_VAL(ret, testret); }
/* * Tests: * - writing to EQ * - reading from EQ with and without FI_PEEK * - underflow read */ static int eq_write_read_self() { struct fi_eq_entry entry; uint32_t event; int testret; int ret; int i; testret = FAIL; ret = create_eq(32, FI_WRITE, FI_WAIT_NONE); if (ret != 0) { sprintf(err_buf, "fi_eq_open ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* Insert some events */ for (i = 0; i < 5; ++i) { if (i & 1) { entry.fid = &fabric->fid; } else { entry.fid = &eq->fid; } entry.context = (void *)(uintptr_t)i; ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } } /* Now read them back, peeking first at each one */ for (i = 0; i < 10; ++i) { event = ~0; memset(&entry, 0, sizeof(entry)); ret = fi_eq_read(eq, &event, &entry, sizeof(entry), (i & 1) ? 0 : FI_PEEK); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_read ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } if (event != FI_NOTIFY) { sprintf(err_buf, "iter %d: event = %d, should be %d\n", i, event, FI_NOTIFY); goto fail; } if ((int)(uintptr_t)entry.context != i / 2) { sprintf(err_buf, "iter %d: context mismatch %d != %d", i, (int)(uintptr_t)entry.context, i / 2); goto fail; } if (entry.fid != ((i & 2) ? &fabric->fid : &eq->fid)) { sprintf(err_buf, "iter %d: fid mismatch %p != %p", i, entry.fid, ((i & 2) ? &fabric->fid : &eq->fid)); goto fail; } } /* queue is now empty */ ret = fi_eq_read(eq, &event, &entry, sizeof(entry), 0); if (ret != -FI_EAGAIN) { sprintf(err_buf, "fi_eq_read of empty EQ returned %d", ret); goto fail; } testret = PASS; fail: FT_CLOSE_FID(eq); return TEST_RET_VAL(ret, testret); }
DIRECT_FN STATIC int gnix_accept(struct fid_ep *ep, const void *param, size_t paramlen) { int ret; struct gnix_vc *vc; struct gnix_fid_ep *ep_priv; struct gnix_pep_sock_conn *conn; struct gnix_pep_sock_connresp resp; struct fi_eq_cm_entry eq_entry, *eqe_ptr; struct gnix_mbox *mbox = NULL; struct gnix_av_addr_entry av_entry; if (!ep || (paramlen && !param) || paramlen > GNIX_CM_DATA_MAX_SIZE) return -FI_EINVAL; ep_priv = container_of(ep, struct gnix_fid_ep, ep_fid.fid); COND_ACQUIRE(ep_priv->requires_lock, &ep_priv->vc_lock); /* Look up and unpack the connection request used to create this EP. */ conn = (struct gnix_pep_sock_conn *)ep_priv->info->handle; if (!conn || conn->fid.fclass != FI_CLASS_CONNREQ) { ret = -FI_EINVAL; goto err_unlock; } /* Create new VC without CM data. */ av_entry.gnix_addr = ep_priv->dest_addr.gnix_addr; av_entry.cm_nic_cdm_id = ep_priv->dest_addr.cm_nic_cdm_id; ret = _gnix_vc_alloc(ep_priv, &av_entry, &vc); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "Failed to create VC: %d\n", ret); goto err_unlock; } ep_priv->vc = vc; ep_priv->vc->peer_caps = conn->req.peer_caps; ep_priv->vc->peer_id = conn->req.vc_id; ret = _gnix_mbox_alloc(vc->ep->nic->mbox_hndl, &mbox); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_DATA, "_gnix_mbox_alloc returned %s\n", fi_strerror(-ret)); goto err_mbox_alloc; } vc->smsg_mbox = mbox; /* Initialize the GNI connection. */ ret = _gnix_vc_smsg_init(vc, conn->req.vc_id, &conn->req.vc_mbox_attr, &conn->req.cq_irq_mdh); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_vc_smsg_init returned %s\n", fi_strerror(-ret)); goto err_smsg_init; } vc->conn_state = GNIX_VC_CONNECTED; /* Send ACK with VC attrs to allow peer to initialize GNI connection. */ resp.cmd = GNIX_PEP_SOCK_RESP_ACCEPT; resp.vc_id = vc->vc_id; resp.vc_mbox_attr.msg_type = GNI_SMSG_TYPE_MBOX_AUTO_RETRANSMIT; resp.vc_mbox_attr.msg_buffer = mbox->base; resp.vc_mbox_attr.buff_size = vc->ep->nic->mem_per_mbox; resp.vc_mbox_attr.mem_hndl = *mbox->memory_handle; resp.vc_mbox_attr.mbox_offset = (uint64_t)mbox->offset; resp.vc_mbox_attr.mbox_maxcredit = ep_priv->domain->params.mbox_maxcredit; resp.vc_mbox_attr.msg_maxsize = ep_priv->domain->params.mbox_msg_maxsize; resp.cq_irq_mdh = ep_priv->nic->irq_mem_hndl; resp.peer_caps = ep_priv->caps; resp.cm_data_len = paramlen; if (paramlen) { eqe_ptr = (struct fi_eq_cm_entry *)resp.eqe_buf; memcpy(eqe_ptr->data, param, paramlen); } ret = write(conn->sock_fd, &resp, sizeof(resp)); if (ret != sizeof(resp)) { GNIX_WARN(FI_LOG_EP_CTRL, "Failed to send resp, errno: %d\n", errno); ret = -FI_EIO; goto err_write; } /* Notify user that this side is connected. */ eq_entry.fid = &ep_priv->ep_fid.fid; ret = fi_eq_write(&ep_priv->eq->eq_fid, FI_CONNECTED, &eq_entry, sizeof(eq_entry), 0); if (ret != sizeof(eq_entry)) { GNIX_WARN(FI_LOG_EP_CTRL, "fi_eq_write failed, err: %d\n", ret); goto err_eq_write; } /* Free the connection request. */ free(conn); ep_priv->conn_state = GNIX_EP_CONNECTED; COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock); GNIX_DEBUG(FI_LOG_EP_CTRL, "Sent conn accept: %p\n", ep_priv); return FI_SUCCESS; err_eq_write: err_write: err_smsg_init: _gnix_mbox_free(ep_priv->vc->smsg_mbox); ep_priv->vc->smsg_mbox = NULL; err_mbox_alloc: _gnix_vc_destroy(ep_priv->vc); ep_priv->vc = NULL; err_unlock: COND_RELEASE(ep_priv->requires_lock, &ep_priv->vc_lock); return ret; }
/* Process a connection response on an FI_EP_MSG. */ static int __gnix_ep_connresp(struct gnix_fid_ep *ep, struct gnix_pep_sock_connresp *resp) { int ret = FI_SUCCESS; struct fi_eq_cm_entry *eq_entry; int eqe_size; switch (resp->cmd) { case GNIX_PEP_SOCK_RESP_ACCEPT: ep->vc->peer_caps = resp->peer_caps; ep->vc->peer_id = resp->vc_id; /* Initialize the GNI connection. */ ret = _gnix_vc_smsg_init(ep->vc, resp->vc_id, &resp->vc_mbox_attr, &resp->cq_irq_mdh); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "_gnix_vc_smsg_init returned %s\n", fi_strerror(-ret)); return ret; } ep->vc->conn_state = GNIX_VC_CONNECTED; ep->conn_state = GNIX_EP_CONNECTED; /* Notify user that this side is connected. */ eq_entry = (struct fi_eq_cm_entry *)resp->eqe_buf; eq_entry->fid = &ep->ep_fid.fid; eqe_size = sizeof(*eq_entry) + resp->cm_data_len; ret = fi_eq_write(&ep->eq->eq_fid, FI_CONNECTED, eq_entry, eqe_size, 0); if (ret != eqe_size) { GNIX_WARN(FI_LOG_EP_CTRL, "fi_eq_write failed, err: %d\n", ret); return ret; } GNIX_DEBUG(FI_LOG_EP_CTRL, "Received conn accept: %p\n", ep); break; case GNIX_PEP_SOCK_RESP_REJECT: /* Undo the connect and generate a failure EQE. */ close(ep->conn_fd); ep->conn_fd = -1; _gnix_mbox_free(ep->vc->smsg_mbox); ep->vc->smsg_mbox = NULL; _gnix_vc_destroy(ep->vc); ep->vc = NULL; ep->conn_state = GNIX_EP_UNCONNECTED; /* Generate EQE. */ eq_entry = (struct fi_eq_cm_entry *)resp->eqe_buf; eq_entry->fid = &ep->ep_fid.fid; eq_entry = (struct fi_eq_cm_entry *)resp->eqe_buf; ret = _gnix_eq_write_error(ep->eq, &ep->ep_fid.fid, NULL, 0, FI_ECONNREFUSED, FI_ECONNREFUSED, &eq_entry->data, resp->cm_data_len); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_EP_CTRL, "fi_eq_write failed, err: %d\n", ret); return ret; } GNIX_DEBUG(FI_LOG_EP_CTRL, "Conn rejected: %p\n", ep); break; default: GNIX_INFO(FI_LOG_EP_CTRL, "Invalid response command: %d\n", resp->cmd); return -FI_EINVAL; } return FI_SUCCESS; }