/* Server run loop till shutdown */ void rdb_r_s_server_run(struct server_data *server_data) { int i; /* default xio supplied main loop */ if (xio_context_run_loop(server_data->ctx, XIO_INFINITE) != 0) { for (i = 0; i < server_data->nworkers; i++) { xio_context_stop_loop(server_data->wdata[i].ctx); } fprintf(stderr, "failed to run event loop for server listner. reason %d - (%s)\n", xio_errno(), xio_strerror(xio_errno())); } /* join the worker threads */ for (i = 0; i < server_data->nworkers; i++) { pthread_join(server_data->wdata[i].thread_id, NULL); } /* free the server */ if (server_data->server) xio_unbind(server_data->server); /* free the context */ if (server_data->ctx) xio_context_destroy(server_data->ctx); xio_shutdown(); if (server_data) free(server_data); }
/*---------------------------------------------------------------------------*/ static int on_message_delivered(struct xio_session *session, struct xio_msg *msg, int last_in_rxq, void *cb_user_context) { struct ow_test_params *ow_params = (struct ow_test_params *)cb_user_context; struct xio_msg *new_msg; process_tx_message(ow_params, msg); ow_params->ndelivered++; /* can be safely returned to pool */ msg_pool_put(ow_params->pool, msg); if (ow_params->finite_run) { if (ow_params->ndelivered == ow_params->disconnect_nr) { xio_disconnect(ow_params->conn); return 0; } if (ow_params->nsent == ow_params->disconnect_nr) return 0; } /* peek message from the pool */ new_msg = msg_pool_get(ow_params->pool); if (new_msg == NULL) { printf("pool is empty\n"); return 0; } /* assign buffers to the message */ msg_write(&ow_params->msg_params, new_msg, test_config.hdr_len, 1, test_config.data_len); /* * ask for receipt since we need to put the message back * to pool */ new_msg->flags = XIO_MSG_FLAG_REQUEST_READ_RECEIPT; /* send it */ if (xio_send_msg(ow_params->conn, new_msg) == -1) { if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_msg " \ "failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(ow_params->pool, new_msg); xio_assert(0); } ow_params->nsent++; return 0; }
/*---------------------------------------------------------------------------*/ static int on_response(struct xio_session *session, struct xio_msg *msg, int last_in_rxq, void *cb_user_context) { /* struct scatterlist *sgl; */ process_response(msg); /* message is no longer needed */ xio_release_response(msg); nrecv++; msg_pool_put(pool, msg); if (test_config.finite_run) { if (nrecv == disconnect_nr) { xio_disconnect(g_connection); return 0; } if (nrecv > disconnect_nr) return 0; } /* reset message */ msg->in.header.iov_base = NULL; msg->in.header.iov_len = 0; msg->in.data_tbl.nents = 0; /* sgl = msg->in.data_tbl.sgl; xio_tbl_set_nents(&msg->in.data_tbl, test_config.in_iov_len); sg_set_buf(sgl, NULL, ONE_MB); */ msg->sn = 0; /* recycle the message and fill new request */ msg_build_out_sgl(&msg_params, msg, test_config.hdr_len, 1, test_config.data_len); /* try to send it */ if (xio_send_request(g_connection, msg) == -1) { if (xio_errno() != EAGAIN) pr_err("**** [%p] Error - xio_send_msg " \ "failed %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, msg); /* xio_assert(0); */ } return 0; }
/*---------------------------------------------------------------------------*/ static int on_new_session(struct xio_session *session, struct xio_new_session_req *session_data, void *cb_prv_data) { struct xio_msg *req; int i = 0; printf("**** [%p] on_new_session :%s:%d\n", session, get_ip((struct sockaddr *)&session_data->src_addr), get_port((struct sockaddr *)&session_data->src_addr)); xio_accept(session, NULL, 0, NULL, 0); msg_pool_reset(pool); conn = xio_get_connection(session, ctx); printf("**** starting ...\n"); while (1) { /* create transaction */ req = msg_pool_get(pool); if (req == NULL) break; /* get pointers to internal buffers */ req->in.header.iov_base = NULL; req->in.header.iov_len = 0; req->in.data_iovlen = 1; req->in.data_iov[0].iov_base = NULL; req->in.data_iov[0].iov_len = ONE_MB; req->in.data_iov[0].mr = NULL; /* recycle the message and fill new request */ msg_set(req, 1, test_config.hdr_len, test_config.data_len); /* try to send it */ if (xio_send_request(conn, req) == -1) { printf("**** sent %d messages\n", i); if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_msg " \ "failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, req); return 0; } i++; if (i == 256) break; } return 0; }
/*---------------------------------------------------------------------------*/ static int on_response(struct xio_session *session, struct xio_msg *rsp, int more_in_batch, void *cb_user_context) { struct xio_iovec_ex *sglist; process_response(rsp); /* message is no longer needed */ xio_release_response(rsp); nrecv++; if (test_config.finite_run) { if (nrecv == disconnect_nr) { xio_disconnect(conn); return 0; } if (nrecv > disconnect_nr || nsent == disconnect_nr) return 0; } /* reset message */ rsp->in.header.iov_base = NULL; rsp->in.header.iov_len = 0; sglist = vmsg_sglist(&rsp->in); vmsg_sglist_set_nents(&rsp->in, 1); sglist[0].iov_base = NULL; sglist[0].iov_len = ONE_MB; sglist[0].mr = NULL; rsp->sn = 0; rsp->more_in_batch = 0; do { /* recycle the message and fill new request */ msg_write(&msg_params, rsp, test_config.hdr_len, 1, test_config.data_len); /* try to send it */ if (xio_send_request(conn, rsp) == -1) { if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_msg " \ "failed %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, rsp); xio_assert(0); } nsent++; } while (0); return 0; }
/*---------------------------------------------------------------------------*/ static int on_response(struct xio_session *session, struct xio_msg *msg, int last_in_rxq, void *cb_user_context) { struct thread_data *tdata = (struct thread_data *)cb_user_context; cycles_t rtt = (get_cycles()-(cycles_t)msg->user_context); if (tdata->do_stat) { if (rtt > tdata->stat.max_rtt) tdata->stat.max_rtt = rtt; if (rtt < tdata->stat.min_rtt) tdata->stat.min_rtt = rtt; tdata->stat.tot_rtt += rtt; tdata->stat.ccnt++; } tdata->rx_nr++; /* message is no longer needed */ xio_release_response(msg); if (tdata->disconnect) { if (tdata->rx_nr == tdata->tx_nr) xio_disconnect(tdata->conn); else msg_pool_put(tdata->pool, msg); return 0; } /* reset message */ msg->in.header.iov_len = 0; vmsg_sglist_set_nents(&msg->in, 0); msg->user_context = (void *)get_cycles(); if (xio_send_request(tdata->conn, msg) == -1) { if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_request " \ "failed %s\n", session, xio_strerror(xio_errno())); msg_pool_put(tdata->pool, msg); return 0; } if (tdata->do_stat) tdata->stat.scnt++; tdata->tx_nr++; return 0; }
/*---------------------------------------------------------------------------*/ static int on_response(struct xio_session *session, struct xio_msg *msg, int more_in_batch, void *cb_user_context) { process_response(msg); if (msg->status) printf("**** message completed with error. [%s]\n", xio_strerror(msg->status)); /* message is no longer needed */ xio_release_response(msg); /* reset message */ msg->in.header.iov_base = NULL; msg->in.header.iov_len = 0; msg->in.data_iovlen = 1; msg->in.data_iov[0].iov_base = NULL; msg->in.data_iov[0].iov_len = ONE_MB; msg->in.data_iov[0].mr = NULL; msg->sn = 0; msg->more_in_batch = 0; do { /* recycle the message and fill new request */ msg_write(msg, "hello world request header", test_config.hdr_len, "hello world request data", test_config.data_len); /* try to send it */ if (xio_send_request(conn, msg) == -1) { if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_msg " \ "failed %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, msg); return 0; } } while (0); return 0; }
/*---------------------------------------------------------------------------*/ static int on_new_session(struct xio_session *session, struct xio_new_session_req *req, void *cb_user_context) { int i = 0; struct ow_test_params *ow_params = cb_user_context; struct xio_msg *msg; printf("**** [%p] on_new_session :%s:%d\n", session, get_ip((struct sockaddr *)&req->src_addr), get_port((struct sockaddr *)&req->src_addr)); xio_accept(session, NULL, 0, NULL, 0); if (ow_params->connection == NULL) ow_params->connection = xio_get_connection(session, ow_params->ctx); for (i = 0; i < MAX_OUTSTANDING_REQS; i++) { /* pick message from the pool */ msg = msg_pool_get(ow_params->pool); if (msg == NULL) break; /* assign buffers to the message */ msg_write(&ow_params->msg_params, msg, NULL, test_config.hdr_len, NULL, test_config.data_len); /* ask for read receipt since the message needed to be * recycled to the pool */ msg->flags = XIO_MSG_FLAG_REQUEST_READ_RECEIPT; /* send the message */ if (xio_send_msg(ow_params->connection, msg) == -1) { printf("**** sent %d messages\n", i); if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_msg " \ "failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(ow_params->pool, msg); return 0; } ow_params->nsent++; } return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int more_in_batch, void *cb_user_context) { struct xio_msg *rsp; /* process request */ process_request(req); /* alloc transaction */ rsp = msg_pool_get(pool); rsp->request = req; rsp->more_in_batch = 0; /* fill response */ msg_write(&msg_params, rsp, test_config.hdr_len, 1, test_config.data_len); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, rsp); } return 0; }
void NetworkXioIOHandler::update_fs_client_info(const std::string& volume_name) { uint16_t port = 0; std::string host; xio_connection_attr xcon_peer; int ret = xio_query_connection(cd_->conn, &xcon_peer, XIO_CONNECTION_ATTR_USER_CTX | XIO_CONNECTION_ATTR_PEER_ADDR); if (ret < 0) { LOG_ERROR(volume_name << ": failed to query the xio connection: " << xio_strerror(xio_errno())); } else { const yt::SocketAddress sa(xcon_peer.peer_addr); port = sa.get_port(); host = sa.get_ip_address(); } const FrontendPath volume_path(make_volume_path(volume_name)); cd_->tag = fs_.register_client(ClientInfo(fs_.find_id(volume_path), std::move(host), port)); }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int last_in_rxq, void *cb_prv_data) { struct xio_msg *rsp; /* process request */ process_request(req); /* alloc transaction */ rsp = msg_pool_get(pool); rsp->request = req; /* fill response */ msg_build_out_sgl(&msg_params, rsp, test_config.hdr_len, 1, test_config.data_len); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, req); xio_assert(0); } return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int last_in_rxq, void *cb_prv_data) { struct xio_msg *rsp; struct thread_data *tdata = (struct thread_data *)cb_prv_data; /* process request */ process_request(tdata, req); /* alloc transaction */ rsp = msg_pool_get(tdata->pool); rsp->request = req; /* fill response */ msg_build_out_sgl(&msg_prms, rsp, test_config.hdr_len, 1, test_config.data_len); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(tdata->pool, req); /* better to do disconnect */ /*xio_disconnect(tdata->conn);*/ xio_assert(0); } tdata->nsent++; return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int more_in_batch, void *cb_prv_data) { struct xio_msg *rsp; if (req->status) printf("**** request completed with error. [%s]\n", xio_strerror(req->status)); /* process request */ process_request(req); /* alloc transaction */ rsp = msg_pool_get(pool); rsp->request = req; rsp->more_in_batch = 0; /* fill response */ msg_set(rsp, 0, test_config.hdr_len, test_config.data_len); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, rsp); } return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int more_in_batch, void *cb_prv_data) { struct xio_msg *rsp; struct thread_data *tdata = cb_prv_data; /* alloc transaction */ rsp = msg_pool_get(tdata->pool); /* fill response */ rsp->request = req; rsp->more_in_batch = more_in_batch; rsp->in.header.iov_len = 0; rsp->out.header.iov_len = 0; vmsg_sglist_set_nents(&rsp->in, 0); if (tdata->user_param->verb == READ) vmsg_sglist_set_nents(&rsp->out, 0); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(tdata->pool, req); } return 0; }
/* Server I/O manager */ void *rdb_r_s_io_worker(void *data) { struct io_worker_data *worker_data; struct xio_server *server = NULL; cpu_set_t cpuset; worker_data = (struct io_worker_data *) data; /* set affinity to thread */ CPU_ZERO(&cpuset); CPU_SET(worker_data->affinity, &cpuset); pthread_setaffinity_np(worker_data->thread_id, sizeof(cpu_set_t), &cpuset); worker_data->ctx = xio_context_create(NULL, POLLING_TIMEOUT, worker_data->affinity); if (!worker_data->ctx) { fprintf(stderr, "failed to create context for thread %s. reason %d - (%s)\n", worker_data->portal, xio_errno(), xio_strerror(xio_errno())); goto out; } server = xio_bind(worker_data->ctx, &io_worker_ops, worker_data->portal, NULL, 0, worker_data); if (!server) { fprintf(stderr, "failed to bind context for thread %s. reason %d - (%s)\n", worker_data->portal, xio_errno(), xio_strerror(xio_errno())); goto out; } xio_mem_alloc(MAX_VALUE_SIZE, &worker_data->reg_mem); if (!worker_data->reg_mem.addr) { fprintf(stderr, "failed to allocate accelio transfer buffer for thread %s. reason %d - (%s)\n", worker_data->portal, xio_errno(), xio_strerror(xio_errno())); goto out; } /* the default xio supplied main loop */ if (xio_context_run_loop(worker_data->ctx, XIO_INFINITE) != 0) { fprintf(stderr, "failed to run event loop for thread %s. reason %d - (%s)\n", worker_data->portal, xio_errno(), xio_strerror(xio_errno())); } out: /* detach the worker */ if (server) xio_unbind(server); if (worker_data->reg_mem.addr) xio_mem_free(&worker_data->reg_mem); /* free the context */ if (worker_data->ctx) xio_context_destroy(worker_data->ctx); return NULL; }
/*---------------------------------------------------------------------------*/ static void *portal_server_cb(void *data) { struct thread_data *tdata = (struct thread_data *)data; cpu_set_t cpuset; struct xio_server *server; int retval = 0; /* set affinity to thread */ CPU_ZERO(&cpuset); CPU_SET(tdata->affinity, &cpuset); pthread_setaffinity_np(tdata->thread_id, sizeof(cpu_set_t), &cpuset); /* prepare data for the cuurent thread */ tdata->pool = msg_pool_alloc(MAX_POOL_SIZE, 0, 1); if (tdata->pool == NULL) { retval = -1; goto exit; } /* create thread context for the client */ tdata->ctx = xio_context_create(NULL, test_config.poll_timeout, tdata->affinity); /* bind a listener server to a portal/url */ printf("thread [%d] - listen:%s\n", tdata->affinity, tdata->portal); server = xio_bind(tdata->ctx, &portal_server_ops, tdata->portal, NULL, 0, tdata); if (server == NULL) { printf("**** Error - xio_bind failed. %s\n", xio_strerror(xio_errno())); retval = -1; goto cleanup; } /* the default xio supplied main loop */ xio_context_run_loop(tdata->ctx, XIO_INFINITE); /* normal exit phase */ fprintf(stdout, "thread [%d] - exit signaled\n", tdata->affinity); /* detach the server */ xio_unbind(server); if (tdata->pool) msg_pool_free(tdata->pool); if (tdata->reg_mem.addr) xio_mem_free(&tdata->reg_mem); cleanup: /* free the context */ xio_context_destroy(tdata->ctx); exit: pthread_exit((void *)(unsigned long)retval); }
/* Reads a ID3v1 tag from the input file and stores them in the given structure. Returns 0 if it successfully reads the tag or if the input file don't have a ID3v1 tag. A nonzero return value indicates an error. */ int ID3V1_TAG::ReadTag(XFILE* x) { if ( xio_fseek(x, -128, XIO_SEEK_END) != -1 && xio_fread(this, 1, 128, x) == 128 ) { if (!IsValid()) Clean(); return 0; } Clean(); return xio_errno(); }
/*---------------------------------------------------------------------------*/ static int on_message_delivered(struct xio_session *session, struct xio_msg *msg, int more_in_batch, void *cb_user_context) { struct xio_msg *new_msg; process_tx_message(msg); /* can be safely returned to pool */ msg_pool_put(pool, msg); /* peek message from the pool */ new_msg = msg_pool_get(pool); if (new_msg == NULL) { printf("pool is empty\n"); return 0; } /* assign buffers to the message */ msg_write(new_msg, NULL, test_config.hdr_len, NULL, test_config.data_len); /* * ask for receipt since we need to put the message back * to pool */ new_msg->flags = XIO_MSG_FLAG_REQUEST_READ_RECEIPT; /* send it */ if (xio_send_msg(conn, new_msg) == -1) { if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_msg " \ "failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(pool, new_msg); return 0; } return 0; }
/*---------------------------------------------------------------------------*/ static int on_connection_established(struct xio_connection *conn) { struct xio_msg *msg; pr_info("**** starting ...\n"); /* create transaction */ msg = msg_pool_get(pool); if (!msg) return 0; /* get pointers to internal buffers */ msg->in.header.iov_base = NULL; msg->in.header.iov_len = 0; msg->in.data_tbl.nents = 0; /* sglist = vmsg_sglist(&msg->in); sglist[0].iov_base = NULL; sglist[0].iov_len = ONE_MB; sglist[0].mr = NULL; vmsg_sglist_set_nents(&msg->in, 1); */ /* recycle the message and fill new request */ msg_build_out_sgl(&msg_params, msg, test_config.hdr_len, 1, test_config.data_len); /* try to send it */ if (xio_send_request(conn, msg) == -1) { pr_info("**** sent %d messages\n", 1); if (xio_errno() != EAGAIN) pr_info("**** [%p] Error - xio_send_msg " \ "failed. %s\n", conn, xio_strerror(xio_errno())); msg_pool_put(pool, msg); xio_assert(0); } return 0; }
/* Server session manager */ struct server_data* rdb_r_s_server_create(const char *host, const int *port) { struct server_data *server_data = NULL; char url[NAME_LEN]; server_data = (struct server_data *)calloc(1, sizeof(*server_data)); if (!server_data) { fprintf(stderr, "failed to allocate memory for server_data\n"); return (NULL); } /* init the accelio library */ xio_init(); /* create thread context */ server_data->ctx = xio_context_create(NULL, 0, -1); if (!server_data->ctx) { fprintf(stderr, "failed to create context for server listner. reason %d - (%s)\n", xio_errno(), xio_strerror(xio_errno())); goto out; } sprintf(url, "%s://%s:%d", TRANSPORT, host, *port); strcpy(server_data->host, host); server_data->port = *port; /* bind a listner */ server_data->server = xio_bind(server_data->ctx, &server_ops, url, NULL, 0, server_data); if (!server_data->server) { fprintf(stderr, "failed to bind server listner. reason %d - (%s)\n", xio_errno(), xio_strerror(xio_errno())); goto out; } out: return (server_data); }
/*---------------------------------------------------------------------------*/ static int on_message_delivered(struct xio_session *session, struct xio_msg *msg, int more_in_batch, void *cb_user_context) { struct xio_msg *new_msg; struct ow_test_params *ow_params = cb_user_context; ow_params->ndelivered++; /* can be safely freed */ msg_pool_put(ow_params->pool, msg); #if TEST_DISCONNECT if (ow_params->ndelivered == DISCONNECT_NR) { xio_disconnect(ow_params->connection); return 0; } if (ow_params->nsent == DISCONNECT_NR) return 0; #endif /* peek new message from the pool */ new_msg = msg_pool_get(ow_params->pool); new_msg->more_in_batch = 0; /* fill response */ msg_write(&ow_params->msg_params, new_msg, NULL, test_config.hdr_len, NULL, test_config.data_len); new_msg->flags = XIO_MSG_FLAG_REQUEST_READ_RECEIPT; if (xio_send_msg(ow_params->connection, new_msg) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(ow_params->pool, new_msg); } ow_params->nsent++; return 0; }
/*---------------------------------------------------------------------------*/ static int on_request(struct xio_session *session, struct xio_msg *req, int more_in_batch, void *cb_user_context) { struct xio_msg *rsp; struct test_params *test_params = cb_user_context; if (req->status) printf("**** request completed with error. [%s]\n", xio_strerror(req->status)); /* process request */ process_request(req); /* alloc transaction */ rsp = msg_pool_get(test_params->pool); rsp->request = req; rsp->more_in_batch = 0; /* fill response */ msg_write(&test_params->msg_params, rsp, NULL, test_config.hdr_len, NULL, test_config.data_len); if (xio_send_response(rsp) == -1) { printf("**** [%p] Error - xio_send_msg failed. %s\n", session, xio_strerror(xio_errno())); msg_pool_put(test_params->pool, req); } test_params->nsent++; return 0; }
/*---------------------------------------------------------------------------*/ static int xio_client_main(void *data) { char url[256]; struct xio_session_params params; struct xio_context_params ctx_params; struct xio_connection_params cparams; int error; int retval = 0; atomic_add(2, &module_state); print_counter = PRINT_COUNTER; print_test_config(&test_config); memset(¶ms, 0, sizeof(params)); memset(&cparams, 0, sizeof(cparams)); /* prepare buffers for this test */ if (msg_api_init(&msg_params, test_config.hdr_len, test_config.data_len, 0) != 0) { pr_err("msg_api_init failed\n"); return -1; } pool = msg_pool_alloc(MAX_POOL_SIZE, 1, 1); if (!pool) { pr_err("msg_pool_alloc failed\n"); goto cleanup; } /* create thread context for the server */ memset(&ctx_params, 0, sizeof(ctx_params)); ctx_params.flags = XIO_LOOP_GIVEN_THREAD; ctx_params.worker = current; ctx = xio_context_create(&ctx_params, POLLING_TIMEOUT, cpu); if (!ctx) { pr_err("context open failed\n"); goto cleanup; } sprintf(url, "%s://%s:%d", test_config.transport, test_config.server_addr, test_config.server_port); params.type = XIO_SESSION_CLIENT; params.ses_ops = &ses_ops; params.uri = url; g_session = xio_session_create(¶ms); if (!g_session) pr_err("session creation failed\n"); cparams.session = g_session; cparams.ctx = ctx; cparams.conn_idx = test_config.conn_idx; /* connect the session */ g_connection = xio_connect(&cparams); /* the default xio supplied main loop */ if (atomic_add_unless(&module_state, 4, 0x83)) retval = xio_context_run_loop(ctx); atomic_sub(4, &module_state); if (retval != 0) { error = xio_errno(); pr_err("running event loop failed. reason %d - (%s)\n", error, xio_strerror(error)); xio_assert(retval == 0); } /* normal exit phase */ pr_info("exit signaled\n"); xio_context_destroy(ctx); msg_pool_free(pool); cleanup: msg_api_free(&msg_params); pr_info("exit complete\n"); complete_and_exit(&cleanup_complete, 0); return 0; }
static int on_request(struct xio_session *session, struct xio_msg *req, int last_in_rxq, void *cb_user_context) { struct xio_msg *rsp; struct io_worker_data *wdata; struct xio_iovec_ex *in_sglist; struct xio_iovec_ex *out_sglist; struct rdb_req_hdr *req_hdr; void *ptr; int *status; char *value; size_t key_size, value_size; // int len; wdata = cb_user_context; rsp = &wdata->rsp; in_sglist = vmsg_sglist(&req->in); req_hdr = in_sglist[0].iov_base; ptr = in_sglist[0].iov_base; ptr += sizeof (*req_hdr); switch (req_hdr->rdb_command) { case RDB_CMD_PUT: { struct rdb_put_req_hdr *put_hdr; put_hdr = ptr; struct __attribute__((__packed__)) rdb_put_req { struct rdb_key { struct rdb_key_hdr key_hdr; char key_data[put_hdr->key_size]; } key; struct rdb_value { struct rdb_value_hdr value_hdr; char value_data[put_hdr->value_size]; } value; } *put_req; ptr += sizeof (*put_hdr); put_req = ptr; key_size = sizeof (struct rdb_key); value_size = sizeof (struct rdb_value); if (!null_mode) if (!rocksdb_server_put(wdata->rdb, (char *)&put_req->key, &key_size, (char *)&put_req->value, &value_size)) { fprintf(stderr, "rocksdb put failed\n"); } // len = (int) in_sglist[0].iov_len; break; } case RDB_CMD_MPUT: { struct rdb_mput_req_hdr *mput_hdr; char *records; mput_hdr = ptr; struct __attribute__((__packed__)) rdb_mput_req { struct multi_kv_pairs { struct rdb_key { struct rdb_key_hdr key_hdr; char key_data[mput_hdr->key_size]; } key; struct rdb_value { struct rdb_value_hdr value_hdr; char value_data[mput_hdr->value_size]; } value; } m_kv_pairs[mput_hdr->num_records]; } *mput_req; ptr += sizeof (*mput_hdr); mput_req = ptr; key_size = sizeof (struct rdb_key); value_size = sizeof (struct rdb_value); records = (char *)mput_req->m_kv_pairs; if (!null_mode) if (!rocksdb_server_mput(wdata->rdb, records, &key_size, &value_size, &mput_hdr->num_records)) { fprintf(stderr, "rocksdb mput failed\n"); } // len = (int) in_sglist[0].iov_len; break; } case RDB_CMD_GET: { struct rdb_get_req_hdr *get_hdr; get_hdr = ptr; struct __attribute__((__packed__)) rdb_get_req { struct rdb_key { struct rdb_key_hdr key_hdr; char key_data[get_hdr->key_size]; } key; } *get_req; ptr += sizeof (*get_hdr); get_req = ptr; key_size = sizeof (get_req->key); out_sglist = vmsg_sglist(&rsp->out); out_sglist[0].iov_base = wdata->reg_mem.addr; out_sglist[0].mr = wdata->reg_mem.mr; if (!null_mode) { status = wdata->reg_mem.addr; value = wdata->reg_mem.addr + sizeof (*status); *status = rocksdb_server_get(wdata->rdb, (char *)&get_req->key, &key_size, value, &value_size); if (*status) out_sglist[0].iov_len = value_size + sizeof (*status); else out_sglist[0].iov_len = sizeof (*status); } else { status = wdata->reg_mem.addr; *status = 1; out_sglist[0].iov_len = sizeof (*status); } // len = (int) out_sglist[0].iov_len; vmsg_sglist_set_nents(&rsp->out, 1); break; } case RDB_CMD_MGET: { struct rdb_mget_req_hdr *mget_hdr; char *records; mget_hdr = ptr; struct __attribute__((__packed__)) rdb_mget_req { struct multi_k_pairs { struct rdb_key { struct rdb_key_hdr key_hdr; char key_data[mget_hdr->key_size]; } key; } m_k_pairs[mget_hdr->num_records]; } *mget_req; ptr += sizeof (*mget_hdr); mget_req = ptr; key_size = sizeof (struct rdb_key); records = (char *) mget_req->m_k_pairs; out_sglist = vmsg_sglist(&rsp->out); out_sglist[0].iov_base = wdata->reg_mem.addr; out_sglist[0].mr = wdata->reg_mem.mr; if (!null_mode) { status = wdata->reg_mem.addr; value = wdata->reg_mem.addr + sizeof (*status); *status = rocksdb_server_mget(wdata->rdb, records, &key_size, value, &value_size, &mget_hdr->num_records); if (*status) out_sglist[0].iov_len = value_size + sizeof (*status); else out_sglist[0].iov_len = sizeof (*status); } else { status = wdata->reg_mem.addr; *status = 1; out_sglist[0].iov_len = sizeof (*status); } // len = (int) out_sglist[0].iov_len; vmsg_sglist_set_nents(&rsp->out, 1); break; } default: break; }; /*printf("thread : portal : %s, command : %d, version : %d, key : %s, value : %s, len : %d\n", wdata->portal, *payload_cmd, *payload_version, key, value, len);*/ in_sglist[0].iov_base = NULL; in_sglist[0].iov_len = 0; vmsg_sglist_set_nents(&req->in, 0); rsp->request = req; if (xio_send_response(rsp) == -1) { fprintf(stderr, "failed to send response for thread %s. reason %d - (%s)\n", wdata->portal, xio_errno(), xio_strerror(xio_errno())); } return (0); }
/*---------------------------------------------------------------------------*/ int xio_on_setup_req_recv(struct xio_connection *connection, struct xio_task *task) { struct xio_msg *msg = &task->imsg; struct xio_new_session_req req; uint8_t *ptr; uint16_t len; struct xio_session_hdr hdr; struct xio_session *session = connection->session; int retval; struct xio_session_event_data error_event = {}; error_event.event = XIO_SESSION_ERROR_EVENT; /* read session header */ xio_session_read_header(task, &hdr); #ifdef XIO_SESSION_DEBUG connection->peer_connection = hdr.connection; connection->peer_session = hdr.session; #endif task->imsg.sn = hdr.serial_num; task->connection = connection; task->session = session; connection->session->setup_req = msg; /* read the header */ ptr = (uint8_t *)msg->in.header.iov_base; memset(&req, 0, sizeof(req)); /* session id */ len = xio_read_uint32(&session->peer_session_id, 0, ptr); ptr = ptr + len; /* queue depth bytes */ len = xio_read_uint64(&session->peer_snd_queue_depth_bytes, 0, ptr); ptr = ptr + len; len = xio_read_uint64(&session->peer_rcv_queue_depth_bytes, 0, ptr); ptr = ptr + len; /* queue depth msgs */ len = xio_read_uint16((uint16_t *)&session->peer_snd_queue_depth_msgs, 0, ptr); ptr = ptr + len; len = xio_read_uint16((uint16_t *)&session->peer_rcv_queue_depth_msgs, 0, ptr); ptr = ptr + len; /* uri length */ len = xio_read_uint16(&req.uri_len, 0, ptr); ptr = ptr + len; /* private length */ len = xio_read_uint16(&req.private_data_len, 0, ptr); ptr = ptr + len; if (req.uri_len) { req.uri = (char *)kcalloc(req.uri_len, sizeof(char), GFP_KERNEL); if (unlikely(!req.uri)) { xio_set_error(ENOMEM); ERROR_LOG("uri allocation failed. len:%d\n", req.uri_len); goto cleanup1; } len = xio_read_array((uint8_t *)req.uri, req.uri_len, 0, ptr); ptr = ptr + len; } if (req.private_data_len) { req.private_data = kcalloc(req.private_data_len, sizeof(uint8_t), GFP_KERNEL); if (unlikely(!req.private_data)) { xio_set_error(ENOMEM); ERROR_LOG("private data allocation failed. len:%d\n", req.private_data_len); goto cleanup2; } len = xio_read_array((uint8_t *)req.private_data, req.private_data_len, 0, ptr); ptr = ptr + len; } req.proto = (enum xio_proto)xio_nexus_get_proto(connection->nexus); xio_nexus_get_peer_addr(connection->nexus, &req.src_addr, sizeof(req.src_addr)); /* cache the task in io queue*/ xio_connection_queue_io_task(connection, task); /* notify the upper layer */ if (connection->ses_ops.on_new_session) { retval = connection->ses_ops.on_new_session( session, &req, connection->cb_user_context); if (retval) goto cleanup2; } else { retval = xio_accept(session, NULL, 0, NULL, 0); if (retval) { ERROR_LOG("failed to auto accept session. session:%p\n", session); goto cleanup2; } } /* Don't move session state to ONLINE. In case of multiple portals * the accept moves the state to ACCEPTED until the first "HELLO" * message arrives. Note that the "upper layer" may call redirect or * reject. */ xio_session_notify_new_connection(session, connection); kfree(req.private_data); kfree(req.uri); return 0; cleanup2: kfree(req.private_data); cleanup1: kfree(req.uri); if (session->ses_ops.on_session_event) { error_event.reason = (enum xio_status)xio_errno(); session->ses_ops.on_session_event( session, &error_event, session->cb_user_context); } return 0; }
/*---------------------------------------------------------------------------*/ int run_client_test(struct perf_parameters *user_param) { struct session_data sess_data; struct perf_comm *comm; struct thread_data *tdata; char url[256]; int i = 0; int max_cpus; pthread_t statistics_thread_id; struct perf_command command; int size_log2; int max_size_log2 = 24; /* client session attributes */ struct xio_session_attr attr = { &ses_ops, NULL, 0 }; xio_init(); g_mhz = get_cpu_mhz(0); max_cpus = sysconf(_SC_NPROCESSORS_ONLN); threads_iter = 1; size_log2 = 0; tdata = calloc(user_param->threads_num, sizeof(*tdata)); if (tdata == NULL) { fprintf(fd, "malloc failed\n"); return -1; } comm = create_comm_struct(user_param); if (establish_connection(comm)) { fprintf(stderr, "failed to establish connection\n"); free(tdata); destroy_comm_struct(comm); return -1; } if (user_param->output_file) { fd = fopen(user_param->output_file, "w"); if (fd == NULL) { fprintf(fd, "file open failed. %s\n", user_param->output_file); free(sess_data.tdata); destroy_comm_struct(comm); return -1; } fprintf(fd, "size, threads, tps, bw[Mbps], lat[usec]\n"); fflush(fd); } printf("%s", RESULT_FMT); printf("%s", RESULT_LINE); while (threads_iter <= user_param->threads_num) { data_len = (uint64_t)1 << size_log2; memset(&sess_data, 0, sizeof(sess_data)); memset(tdata, 0, user_param->threads_num*sizeof(*tdata)); sess_data.tdata = tdata; command.test_param.machine_type = user_param->machine_type; command.test_param.test_type = user_param->test_type; command.test_param.verb = user_param->verb; command.test_param.data_len = data_len; command.command = GetTestParams; ctx_write_data(comm, &command, sizeof(command)); sprintf(url, "rdma://%s:%d", user_param->server_addr, user_param->server_port); sess_data.session = xio_session_create(XIO_SESSION_CLIENT, &attr, url, 0, 0, &sess_data); if (sess_data.session == NULL) { int error = xio_errno(); fprintf(stderr, "session creation failed. reason %d - (%s)\n", error, xio_strerror(error)); goto cleanup; } pthread_create(&statistics_thread_id, NULL, statistics_thread_cb, &sess_data); /* spawn threads to handle connection */ for (i = 0; i < threads_iter; i++) { sess_data.tdata[i].affinity = ((user_param->cpu + i) % max_cpus); sess_data.tdata[i].cid = i; sess_data.tdata[i].sdata = &sess_data; sess_data.tdata[i].user_param = user_param; sess_data.tdata[i].data_len = data_len; /* all threads are working on the same session */ sess_data.tdata[i].session = sess_data.session; pthread_create(&sess_data.tdata[i].thread_id, NULL, worker_thread, &sess_data.tdata[i]); } pthread_join(statistics_thread_id, NULL); /* join the threads */ for (i = 0; i < threads_iter; i++) pthread_join(sess_data.tdata[i].thread_id, NULL); /* close the session */ xio_session_destroy(sess_data.session); if (sess_data.abort) { fprintf(stderr, "program aborted\n"); goto cleanup; } /* send result to server */ command.results.bytes = data_len; command.results.threads = threads_iter; command.results.tps = sess_data.tps; command.results.avg_bw = sess_data.avg_bw; command.results.avg_lat = sess_data.avg_lat_us; command.results.min_lat = sess_data.min_lat_us; command.results.max_lat = sess_data.max_lat_us; command.command = GetTestResults; /* sync point */ ctx_write_data(comm, &command, sizeof(command)); printf(REPORT_FMT, data_len, threads_iter, sess_data.tps, sess_data.avg_bw, sess_data.avg_lat_us, sess_data.min_lat_us, sess_data.max_lat_us); if (fd) fprintf(fd, "%lu, %d, %lu, %.2lf, %.2lf\n", data_len, threads_iter, sess_data.tps, sess_data.avg_bw, sess_data.avg_lat_us); fflush(fd); /* sync point */ ctx_read_data(comm, NULL, 0, NULL); if (++size_log2 < max_size_log2) continue; threads_iter++; size_log2 = 0; } printf("%s", RESULT_LINE); cleanup: if (fd) fclose(fd); ctx_hand_shake(comm); ctx_close_connection(comm); destroy_comm_struct(comm); free(tdata); xio_shutdown(); return 0; }
/*---------------------------------------------------------------------------*/ static void *worker_thread(void *data) { struct thread_data *tdata = data; cpu_set_t cpuset; struct xio_msg *msg; int i; /* set affinity to thread */ CPU_ZERO(&cpuset); CPU_SET(tdata->affinity, &cpuset); pthread_setaffinity_np(tdata->thread_id, sizeof(cpu_set_t), &cpuset); /* prepare data for the cuurent thread */ tdata->pool = msg_pool_alloc(tdata->user_param->queue_depth); /* create thread context for the client */ tdata->ctx = xio_context_create(NULL, tdata->user_param->poll_timeout, tdata->affinity); /* connect the session */ tdata->conn = xio_connect(tdata->session, tdata->ctx, tdata->cid, NULL, tdata); if (tdata->data_len) tdata->xbuf = xio_alloc(tdata->data_len); for (i = 0; i < tdata->user_param->queue_depth; i++) { /* create transaction */ msg = msg_pool_get(tdata->pool); if (msg == NULL) break; /* get pointers to internal buffers */ msg->in.header.iov_len = 0; msg->in.data_iovlen = 0; msg->out.header.iov_len = 0; if (tdata->data_len) { msg->out.data_iovlen = 1; msg->out.data_iov[0].iov_base = tdata->xbuf->addr; msg->out.data_iov[0].iov_len = tdata->xbuf->length; msg->out.data_iov[0].mr = tdata->xbuf->mr; } else { msg->out.data_iovlen = 0; } msg->user_context = (void *)get_cycles(); /* send first message */ if (xio_send_request(tdata->conn, msg) == -1) { if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_request " \ "failed. %s\n", tdata->session, xio_strerror(xio_errno())); msg_pool_put(tdata->pool, msg); return 0; } if (tdata->do_stat) tdata->stat.scnt++; tdata->tx_nr++; } /* the default xio supplied main loop */ xio_context_run_loop(tdata->ctx, XIO_INFINITE); /* normal exit phase */ if (tdata->pool) msg_pool_free(tdata->pool); if (tdata->xbuf) xio_free(&tdata->xbuf); /* free the context */ xio_context_destroy(tdata->ctx); return NULL; }
/*---------------------------------------------------------------------------*/ static int on_response(struct xio_session *session, struct xio_msg *msg, int last_in_rxq, void *cb_user_context) { struct test_params *test_params = (struct test_params *)cb_user_context; struct xio_iovec_ex *sglist; static int chain_messages = CHAIN_MESSAGES; size_t j; test_params->nrecv++; process_response(test_params, msg); /* message is no longer needed */ xio_release_response(msg); msg_pool_put(test_params->pool, msg); if (test_params->finite_run) { if (test_params->nrecv == test_params->disconnect_nr) { xio_disconnect(test_params->connection); return 0; } if (test_params->nsent == test_params->disconnect_nr) return 0; } /* peek message from the pool */ msg = msg_pool_get(test_params->pool); if (msg == NULL) { printf("pool is empty\n"); return 0; } msg->in.header.iov_base = NULL; msg->in.header.iov_len = 0; sglist = vmsg_sglist(&msg->in); vmsg_sglist_set_nents(&msg->in, test_config.in_iov_len); /* tell accelio to use 1MB buffer from its internal pool */ for (j = 0; j < test_config.in_iov_len; j++) { sglist[j].iov_base = NULL; sglist[j].iov_len = ONE_MB; sglist[j].mr = NULL; } msg->sn = 0; /* assign buffers to the message */ msg_build_out_sgl(&test_params->msg_params, msg, test_config.hdr_len, test_config.out_iov_len, test_config.data_len); if (chain_messages) { msg->next = NULL; if (test_params->chain.head == NULL) { test_params->chain.head = msg; test_params->chain.tail = test_params->chain.head; } else { test_params->chain.tail->next = msg; test_params->chain.tail = test_params->chain.tail->next; } if (++test_params->chain.sz == MAX_OUTSTANDING_REQS) { if (xio_send_request(test_params->connection, test_params->chain.head) == -1) { if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_request " \ "failed %s\n", session, xio_strerror(xio_errno())); msg_pool_put(test_params->pool, msg); xio_assert(xio_errno() == EAGAIN); } test_params->nsent += test_params->chain.sz; test_params->chain.head = NULL; test_params->chain.sz = 0; } } else { /* try to send it */ /*msg->flags = XIO_MSG_FLAG_REQUEST_READ_RECEIPT; */ /*msg->flags = XIO_MSG_FLAG_PEER_READ_REQ;*/ if (xio_send_request(test_params->connection, msg) == -1) { if (xio_errno() != EAGAIN) printf("**** [%p] Error - xio_send_request " \ "failed %s\n", session, xio_strerror(xio_errno())); msg_pool_put(test_params->pool, msg); xio_assert(xio_errno() == EAGAIN); } test_params->nsent++; } return 0; }
/*---------------------------------------------------------------------------*/ static int xio_server_main(void *data) { struct xio_server *server; struct xio_context_params ctx_params; char url[256]; atomic_add(2, &module_state); print_test_config(&test_config); g_test_params.finite_run = test_config.finite_run; g_test_params.disconnect_nr = PRINT_COUNTER * DISCONNECT_FACTOR; memset(&ctx_params, 0, sizeof(ctx_params)); ctx_params.flags = XIO_LOOP_GIVEN_THREAD; ctx_params.worker = current; g_test_params.ctx = xio_context_create(&ctx_params, 0, g_test_params.cpu); if (!g_test_params.ctx) { int error = xio_errno(); pr_err("context creation failed. reason %d - (%s)\n", error, xio_strerror(error)); goto cleanup; } sprintf(url, "%s://%s:%d", test_config.transport, test_config.server_addr, test_config.server_port); server = xio_bind(g_test_params.ctx, &server_ops, url, NULL, 0, &g_test_params); if (server) { pr_info("listen to %s\n", url); if (atomic_add_unless(&module_state, 4, 0x83)) xio_context_run_loop(g_test_params.ctx); atomic_sub(4, &module_state); /* normal exit phase */ pr_info("exit signaled\n"); /* free the server */ xio_unbind(server); } else { pr_err("**** Error - xio_bind failed - %s. " \ "Did you load a transport module?\n", xio_strerror(xio_errno())); /*xio_assert(0);*/ } xio_context_destroy(g_test_params.ctx); kfree(g_test_params.xbuf); g_test_params.xbuf = NULL; cleanup: complete_and_exit(&cleanup_complete, 0); return 0; }
/*---------------------------------------------------------------------------*/ int xio_on_setup_req_recv(struct xio_connection *connection, struct xio_task *task) { struct xio_msg *msg = &task->imsg; struct xio_new_session_req req; uint8_t *ptr; uint16_t len; struct xio_session_hdr hdr; struct xio_session *session = connection->session; int retval; struct xio_session_event_data error_event = { .conn = NULL, .conn_user_context = NULL, .event = XIO_SESSION_ERROR_EVENT, .reason = XIO_E_SUCCESS, .private_data = NULL, .private_data_len = 0, }; /* read session header */ xio_session_read_header(task, &hdr); #ifdef XIO_SESSION_DEBUG connection->peer_connection = hdr.connection; connection->peer_session = hdr.session; #endif task->imsg.sn = hdr.serial_num; task->connection = connection; task->session = session; connection->session->setup_req = msg; connection->session->connection_srv_first = connection; /* read the header */ ptr = (uint8_t *)msg->in.header.iov_base; memset(&req, 0, sizeof(req)); /* session id */ len = xio_read_uint32(&session->peer_session_id, 0, ptr); ptr = ptr + len; /* queue depth bytes */ len = xio_read_uint64(&session->peer_snd_queue_depth_bytes, 0, ptr); ptr = ptr + len; len = xio_read_uint64(&session->peer_rcv_queue_depth_bytes, 0, ptr); ptr = ptr + len; /* queue depth msgs */ len = xio_read_uint16((uint16_t *)&session->peer_snd_queue_depth_msgs, 0, ptr); ptr = ptr + len; len = xio_read_uint16((uint16_t *)&session->peer_rcv_queue_depth_msgs, 0, ptr); ptr = ptr + len; /* uri length */ len = xio_read_uint16(&req.uri_len, 0, ptr); ptr = ptr + len; /* private length */ len = xio_read_uint16(&req.private_data_len, 0, ptr); ptr = ptr + len; if (req.uri_len) { req.uri = (char *)kcalloc(req.uri_len, sizeof(char), GFP_KERNEL); if (unlikely(!req.uri)) { xio_set_error(ENOMEM); ERROR_LOG("uri allocation failed. len:%d\n", req.uri_len); goto cleanup1; } len = xio_read_array((uint8_t *)req.uri, req.uri_len, 0, ptr); ptr = ptr + len; } if (req.private_data_len) { req.private_data = kcalloc(req.private_data_len, sizeof(uint8_t), GFP_KERNEL); if (unlikely(!req.private_data)) { xio_set_error(ENOMEM); ERROR_LOG("private data allocation failed. len:%d\n", req.private_data_len); goto cleanup2; } len = xio_read_array((uint8_t *)req.private_data, req.private_data_len, 0, ptr); ptr = ptr + len; } req.proto = (enum xio_proto)xio_nexus_get_proto(connection->nexus); xio_nexus_get_peer_addr(connection->nexus, &req.src_addr, sizeof(req.src_addr)); /* cache the task in io queue*/ xio_connection_queue_io_task(connection, task); /* notify the upper layer */ if (connection->ses_ops.on_new_session) { #ifdef XIO_THREAD_SAFE_DEBUG xio_ctx_debug_thread_unlock(connection->ctx); #endif retval = connection->ses_ops.on_new_session( session, &req, connection->cb_user_context); #ifdef XIO_THREAD_SAFE_DEBUG xio_ctx_debug_thread_lock(connection->ctx); #endif if (retval) goto cleanup2; } else { retval = xio_accept(session, NULL, 0, NULL, 0); if (retval) { ERROR_LOG("failed to auto accept session. session:%p\n", session); goto cleanup2; } } /* Don't move session state to ONLINE. In case of multiple portals * the accept moves the state to ACCEPTED until the first "HELLO" * message arrives. Note that the "upper layer" may call redirect or * reject. */ xio_session_notify_new_connection(session, connection); kfree(req.private_data); kfree(req.uri); return 0; cleanup2: kfree(req.private_data); cleanup1: kfree(req.uri); if (session->ses_ops.on_session_event) { #ifdef XIO_THREAD_SAFE_DEBUG xio_ctx_debug_thread_unlock(connection->ctx); #endif error_event.reason = (enum xio_status)xio_errno(); session->ses_ops.on_session_event( session, &error_event, session->cb_user_context); #ifdef XIO_THREAD_SAFE_DEBUG xio_ctx_debug_thread_lock(connection->ctx); #endif } return 0; } /*---------------------------------------------------------------------------*/ /* xio_session_write_accept_rsp */ /*---------------------------------------------------------------------------*/ struct xio_msg *xio_session_write_accept_rsp(struct xio_session *session, uint16_t action, const char **portals_array, uint16_t portals_array_len, void *user_context, uint16_t user_context_len) { struct xio_msg *msg; uint8_t *buf; uint8_t *ptr; uint16_t len, i, str_len, tot_len; /* calculate length */ tot_len = 5*sizeof(uint16_t) + sizeof(uint32_t) + 2*sizeof(uint64_t); for (i = 0; i < portals_array_len; i++) tot_len += strlen(portals_array[i]) + sizeof(uint16_t); tot_len += user_context_len; if (tot_len > SETUP_BUFFER_LEN) { ERROR_LOG("buffer is too small\n"); xio_set_error(EMSGSIZE); return NULL; } /* allocate message */ buf = (uint8_t *)kcalloc(SETUP_BUFFER_LEN + sizeof(struct xio_msg), sizeof(uint8_t), GFP_KERNEL); if (unlikely(!buf)) { ERROR_LOG("message allocation failed\n"); xio_set_error(ENOMEM); return NULL; } /* fill the message */ msg = (struct xio_msg *)buf; msg->out.header.iov_base = buf + sizeof(struct xio_msg); msg->out.header.iov_len = 0; ptr = (uint8_t *)msg->out.header.iov_base; len = 0; /* serialize message into the buffer */ /* session_id */ len = xio_write_uint32(session->session_id, 0, ptr); ptr = ptr + len; /* action */ len = xio_write_uint16(action, 0, ptr); ptr = ptr + len; if (action == XIO_ACTION_ACCEPT) { /* tx queue depth bytes */ len = xio_write_uint64(session->snd_queue_depth_bytes, 0, ptr); ptr = ptr + len; /* rx queue depth bytes */ len = xio_write_uint64(session->rcv_queue_depth_bytes, 0, ptr); ptr = ptr + len; /* tx queue depth msgs */ len = xio_write_uint16(session->snd_queue_depth_msgs, 0, ptr); ptr = ptr + len; /* rx queue depth msgs */ len = xio_write_uint16(session->rcv_queue_depth_msgs, 0, ptr); ptr = ptr + len; } /* portals_array_len */ len = xio_write_uint16(portals_array_len, 0, ptr); ptr = ptr + len; /* user_context_len */ len = xio_write_uint16(user_context_len, 0, ptr); ptr = ptr + len; for (i = 0; i < portals_array_len; i++) { str_len = strlen(portals_array[i]); len = xio_write_uint16(str_len, 0, ptr); ptr = ptr + len; len = xio_write_array((uint8_t *)portals_array[i], str_len, 0, ptr); ptr = ptr + len; } if (user_context_len) { len = xio_write_array((const uint8_t *)user_context, user_context_len, 0, ptr); ptr = ptr + len; } msg->out.header.iov_len = ptr - (uint8_t *)msg->out.header.iov_base; if (msg->out.header.iov_len != tot_len) { ERROR_LOG("calculated length %d != actual length %zd\n", tot_len, msg->out.header.iov_len); } return msg; } /*---------------------------------------------------------------------------*/ /* xio_session_write_reject_rsp */ /*---------------------------------------------------------------------------*/ struct xio_msg *xio_session_write_reject_rsp(struct xio_session *session, enum xio_status reason, void *user_context, uint16_t user_context_len) { struct xio_msg *msg; uint8_t *buf; uint8_t *ptr; uint16_t len, tot_len; uint16_t action = XIO_ACTION_REJECT; /* calclate length */ tot_len = 2*sizeof(uint16_t) + 2*sizeof(uint32_t); tot_len += user_context_len; if (tot_len > SETUP_BUFFER_LEN) { ERROR_LOG("buffer is too small\n"); xio_set_error(EMSGSIZE); return NULL; } /* allocate message */ buf = (uint8_t *)kcalloc(SETUP_BUFFER_LEN + sizeof(struct xio_msg), sizeof(uint8_t), GFP_KERNEL); if (!buf) { ERROR_LOG("message allocation failed\n"); xio_set_error(ENOMEM); return NULL; } /* fill the message */ msg = (struct xio_msg *)buf; msg->out.header.iov_base = buf + sizeof(struct xio_msg); msg->out.header.iov_len = 0; ptr = (uint8_t *)msg->out.header.iov_base; len = 0; /* serialize message into the buffer */ /* session_id */ len = xio_write_uint32(session->session_id, 0, ptr); ptr = ptr + len; /* action */ len = xio_write_uint16(action, 0, ptr); ptr = ptr + len; /* reason */ len = xio_write_uint32(reason, 0, ptr); ptr = ptr + len; /* user_context_len */ len = xio_write_uint16(user_context_len, 0, ptr); ptr = ptr + len; if (user_context_len) { len = xio_write_array((const uint8_t *)user_context, user_context_len, 0, ptr); ptr = ptr + len; } msg->out.header.iov_len = ptr - (uint8_t *)msg->out.header.iov_base; if (msg->out.header.iov_len != tot_len) { ERROR_LOG("calculated length %d != actual length %zd\n", tot_len, msg->out.header.iov_len); } return msg; } /*---------------------------------------------------------------------------*/ /* xio_accept */ /*---------------------------------------------------------------------------*/ int xio_accept(struct xio_session *session, const char **portals_array, size_t portals_array_len, void *user_context, size_t user_context_len) { int retval = 0; struct xio_msg *msg; struct xio_task *task; msg = xio_session_write_accept_rsp(session, XIO_ACTION_ACCEPT, portals_array, portals_array_len, user_context, user_context_len); if (!msg) { ERROR_LOG("setup request creation failed\n"); return -1; } msg->request = session->setup_req; msg->type = (enum xio_msg_type)XIO_SESSION_SETUP_RSP; task = container_of(msg->request, struct xio_task, imsg); if (portals_array_len != 0) { /* server side state is changed to ACCEPT, will be move to * ONLINE state when first "hello" message arrives */ session->state = XIO_SESSION_STATE_ACCEPTED; /* temporary disable teardown */ session->disable_teardown = 1; TRACE_LOG("session state is now ACCEPT. session:%p\n", session); } else { /* initialize credits */ task->connection->peer_credits_msgs = session->peer_rcv_queue_depth_msgs; task->connection->credits_msgs = 0; task->connection->peer_credits_bytes = session->peer_rcv_queue_depth_bytes; task->connection->credits_bytes = 0; /* server side state is changed to ONLINE, immediately */ session->state = XIO_SESSION_STATE_ONLINE; TRACE_LOG("session state changed to ONLINE. session:%p\n", session); } retval = xio_connection_send(task->connection, msg); if (retval && retval != -EAGAIN) { ERROR_LOG("failed to send message. errno:%d\n", -retval); xio_set_error(-retval); return -1; } return 0; }