/*---------------------------------------------------------------------------*/ struct xio_context *xio_context_create(unsigned int flags, struct xio_loop_ops *loop_ops, struct task_struct *worker, int polling_timeout, int cpu_hint) { struct xio_context *ctx; struct dentry *xio_root; char name[32]; int cpu; if (cpu_hint > 0 && cpu_hint >= num_online_cpus()) { xio_set_error(EINVAL); ERROR_LOG("cpu_hint(%d) >= num_online_cpus(%d)\n", cpu_hint, num_online_cpus()); goto cleanup0; } if ((flags == XIO_LOOP_USER_LOOP) && (!(loop_ops && loop_ops->add_event && loop_ops->ev_loop))) { xio_set_error(EINVAL); ERROR_LOG("loop_ops and ev_loop and ev_loop_add_event are mandatory with loop_ops\n"); goto cleanup0; } xio_read_logging_level(); /* no need to disable preemption */ cpu = raw_smp_processor_id(); if (cpu == -1) goto cleanup0; /* allocate new context */ ctx = kzalloc(sizeof(struct xio_context), GFP_KERNEL); if (ctx == NULL) { xio_set_error(ENOMEM); ERROR_LOG("kzalloc failed\n"); goto cleanup0; } if (cpu_hint < 0) cpu_hint = cpu; ctx->flags = flags; ctx->cpuid = cpu_hint; ctx->nodeid = cpu_to_node(cpu_hint); ctx->polling_timeout = polling_timeout; ctx->workqueue = xio_workqueue_create(ctx); if (!ctx->workqueue) { xio_set_error(ENOMEM); ERROR_LOG("xio_workqueue_init failed.\n"); goto cleanup1; } XIO_OBSERVABLE_INIT(&ctx->observable, ctx); INIT_LIST_HEAD(&ctx->ctx_list); switch (flags) { case XIO_LOOP_USER_LOOP: break; case XIO_LOOP_GIVEN_THREAD: set_cpus_allowed_ptr(worker, cpumask_of(cpu_hint)); ctx->worker = (uint64_t) worker; break; case XIO_LOOP_TASKLET: break; case XIO_LOOP_WORKQUEUE: break; default: ERROR_LOG("wrong type. %u\n", flags); goto cleanup2; } xio_root = xio_debugfs_root(); if (xio_root) { /* More then one contexts can share the core */ sprintf(name, "ctx-%d-%p", cpu_hint, worker); ctx->ctx_dentry = debugfs_create_dir(name, xio_root); if (!ctx->ctx_dentry) { ERROR_LOG("debugfs entry %s create failed\n", name); goto cleanup2; } } ctx->ev_loop = xio_ev_loop_init(flags, ctx, loop_ops); if (!ctx->ev_loop) goto cleanup3; ctx->stats.hertz = HZ; /* Initialize default counters' name */ ctx->stats.name[XIO_STAT_TX_MSG] = kstrdup("TX_MSG", GFP_KERNEL); ctx->stats.name[XIO_STAT_RX_MSG] = kstrdup("RX_MSG", GFP_KERNEL); ctx->stats.name[XIO_STAT_TX_BYTES] = kstrdup("TX_BYTES", GFP_KERNEL); ctx->stats.name[XIO_STAT_RX_BYTES] = kstrdup("RX_BYTES", GFP_KERNEL); ctx->stats.name[XIO_STAT_DELAY] = kstrdup("DELAY", GFP_KERNEL); ctx->stats.name[XIO_STAT_APPDELAY] = kstrdup("APPDELAY", GFP_KERNEL); return ctx; cleanup3: debugfs_remove_recursive(ctx->ctx_dentry); ctx->ctx_dentry = NULL; cleanup2: xio_workqueue_destroy(ctx->workqueue); cleanup1: kfree(ctx); cleanup0: ERROR_LOG("xio_ctx_open failed\n"); return NULL; }
/*---------------------------------------------------------------------------*/ struct xio_context *xio_context_create(struct xio_context_params *ctx_params, int polling_timeout, int cpu_hint) { struct xio_context *ctx; struct xio_loop_ops *loop_ops; struct task_struct *worker; struct xio_transport *transport; int flags, cpu; if (!ctx_params) { xio_set_error(EINVAL); ERROR_LOG("ctx_params is NULL\n"); goto cleanup0; } loop_ops = ctx_params->loop_ops; worker = ctx_params->worker; flags = ctx_params->flags; if (cpu_hint > 0 && cpu_hint >= num_online_cpus()) { xio_set_error(EINVAL); ERROR_LOG("cpu_hint(%d) >= num_online_cpus(%d)\n", cpu_hint, num_online_cpus()); goto cleanup0; } if ((flags == XIO_LOOP_USER_LOOP) && (!(loop_ops && loop_ops->add_event && loop_ops->ev_loop))) { xio_set_error(EINVAL); ERROR_LOG("loop_ops and ev_loop and ev_loop_add_event are " \ "mandatory with loop_ops\n"); goto cleanup0; } xio_read_logging_level(); /* no need to disable preemption */ cpu = raw_smp_processor_id(); if (cpu == -1) goto cleanup0; /* allocate new context */ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) { xio_set_error(ENOMEM); ERROR_LOG("kzalloc failed\n"); goto cleanup0; } if (cpu_hint < 0) cpu_hint = cpu; ctx->run_private = 0; ctx->user_context = ctx_params->user_context; ctx->flags = flags; ctx->cpuid = cpu_hint; ctx->nodeid = cpu_to_node(cpu_hint); ctx->polling_timeout = polling_timeout; ctx->prealloc_xio_inline_bufs = !!ctx_params->prealloc_xio_inline_bufs; ctx->rq_depth = ctx_params->rq_depth; if (!ctx_params->max_conns_per_ctx) ctx->max_conns_per_ctx = 100; else ctx->max_conns_per_ctx = max(ctx_params->max_conns_per_ctx , 2); ctx->workqueue = xio_workqueue_create(ctx); if (!ctx->workqueue) { xio_set_error(ENOMEM); ERROR_LOG("xio_workqueue_init failed.\n"); goto cleanup1; } ctx->msg_pool = xio_objpool_create(sizeof(struct xio_msg), MSGPOOL_INIT_NR, MSGPOOL_GROW_NR); if (!ctx->msg_pool) { xio_set_error(ENOMEM); ERROR_LOG("context's msg_pool create failed. %m\n"); goto cleanup2; } XIO_OBSERVABLE_INIT(&ctx->observable, ctx); INIT_LIST_HEAD(&ctx->ctx_list); switch (flags) { case XIO_LOOP_USER_LOOP: break; case XIO_LOOP_GIVEN_THREAD: set_cpus_allowed_ptr(worker, cpumask_of(cpu_hint)); ctx->worker = (uint64_t)worker; break; case XIO_LOOP_TASKLET: break; case XIO_LOOP_WORKQUEUE: break; default: ERROR_LOG("wrong type. %u\n", flags); goto cleanup3; } ctx->ev_loop = xio_ev_loop_init(flags, ctx, loop_ops); if (!ctx->ev_loop) goto cleanup3; ctx->stats.hertz = HZ; /* Initialize default counters' name */ ctx->stats.name[XIO_STAT_TX_MSG] = kstrdup("TX_MSG", GFP_KERNEL); ctx->stats.name[XIO_STAT_RX_MSG] = kstrdup("RX_MSG", GFP_KERNEL); ctx->stats.name[XIO_STAT_TX_BYTES] = kstrdup("TX_BYTES", GFP_KERNEL); ctx->stats.name[XIO_STAT_RX_BYTES] = kstrdup("RX_BYTES", GFP_KERNEL); ctx->stats.name[XIO_STAT_DELAY] = kstrdup("DELAY", GFP_KERNEL); ctx->stats.name[XIO_STAT_APPDELAY] = kstrdup("APPDELAY", GFP_KERNEL); /* initialize rdma pools only */ transport = xio_get_transport("rdma"); if (transport && ctx->prealloc_xio_inline_bufs) { int retval = xio_ctx_pool_create(ctx, XIO_PROTO_RDMA, XIO_CONTEXT_POOL_CLASS_INITIAL); if (retval) { ERROR_LOG("Failed to create initial pool. ctx:%p\n", ctx); goto cleanup2; } retval = xio_ctx_pool_create(ctx, XIO_PROTO_RDMA, XIO_CONTEXT_POOL_CLASS_PRIMARY); if (retval) { ERROR_LOG("Failed to create primary pool. ctx:%p\n", ctx); goto cleanup2; } } spin_lock_init(&ctx->ctx_list_lock); xio_idr_add_uobj(usr_idr, ctx, "xio_context"); return ctx; cleanup3: xio_objpool_destroy(ctx->msg_pool); cleanup2: xio_workqueue_destroy(ctx->workqueue); cleanup1: kfree(ctx); cleanup0: ERROR_LOG("xio_ctx_open failed\n"); return NULL; }
/*---------------------------------------------------------------------------*/ struct xio_server *xio_bind(struct xio_context *ctx, struct xio_session_ops *ops, const char *uri, uint16_t *src_port, uint32_t session_flags, void *cb_private_data) { struct xio_server *server; int retval; int backlog = 4; if (!ctx || !ops || !uri) { ERROR_LOG("invalid parameters ctx:%p, ops:%p, uri:%p\n", ctx, ops, uri); xio_set_error(EINVAL); return NULL; } TRACE_LOG("bind to %s\n", uri); /* create the server */ server = (struct xio_server *) kcalloc(1, sizeof(struct xio_server), GFP_KERNEL); if (!server) { xio_set_error(ENOMEM); return NULL; } kref_init(&server->kref); /* fill server data*/ server->ctx = ctx; server->cb_private_data = cb_private_data; server->uri = kstrdup(uri, GFP_KERNEL); server->session_flags = session_flags; memcpy(&server->ops, ops, sizeof(*ops)); XIO_OBSERVER_INIT(&server->observer, server, xio_on_nexus_event); XIO_OBSERVABLE_INIT(&server->nexus_observable, server); server->listener = xio_nexus_open(ctx, uri, NULL, 0, 0, NULL); if (!server->listener) { ERROR_LOG("failed to create connection\n"); goto cleanup; } retval = xio_nexus_listen(server->listener, uri, src_port, backlog); if (retval != 0) { ERROR_LOG("connection listen failed\n"); goto cleanup1; } xio_nexus_set_server(server->listener, server); xio_idr_add_uobj(usr_idr, server, "xio_server"); return server; cleanup1: xio_nexus_close(server->listener, NULL); cleanup: kfree(server->uri); kfree(server); return NULL; }