Пример #1
0
/*---------------------------------------------------------------------------*/
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;
}
Пример #2
0
/*---------------------------------------------------------------------------*/
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;
}
Пример #3
0
/* first message after new connection are going trough the server */
static int xio_on_new_message(struct xio_server *server,
			      struct xio_nexus *nexus,
			      int event,
			      union xio_nexus_event_data *event_data)
{
	struct xio_session		*session = NULL;
	struct xio_connection		*connection = NULL;
	struct xio_connection		*connection1 = NULL;
	struct xio_task			*task;
	uint32_t			tlv_type;
	struct xio_session_params	params;
	int				locked = 0;

	if (!server || !nexus || !event_data || !event_data->msg.task) {
		ERROR_LOG("server [new session]: failed " \
			  "invalid parameter\n");
		return -1;
	}
	task			= event_data->msg.task;

	params.type		= XIO_SESSION_SERVER;
	params.initial_sn	= 0;
	params.ses_ops		= &server->ops;
	params.uri		= server->uri;
	params.private_data	= NULL;
	params.private_data_len = 0;
	params.user_context	= server->cb_private_data;

	/* read the first message  type */
	tlv_type = xio_read_tlv_type(&event_data->msg.task->mbuf);

	if (tlv_type == XIO_SESSION_SETUP_REQ) {
		/* create new session */
		session = xio_session_create(&params);
		if (!session) {
			ERROR_LOG("server [new session]: failed " \
				"  allocating session failed\n");
			return -1;
		}
		DEBUG_LOG("server [new session]: server:%p, " \
			  "session:%p, nexus:%p ,session_id:%d\n",
			  server, session, nexus, session->session_id);

		/* get transport class routines */
		session->validators_cls = xio_nexus_get_validators_cls(nexus);

		connection =
			xio_session_alloc_connection(session,
						     server->ctx, 0,
						     server->cb_private_data);
		if (!connection) {
			ERROR_LOG("server failed to allocate new connection\n");
			goto cleanup;
		}
		connection1 = xio_session_assign_nexus(session, nexus);
		if (!connection1) {
			ERROR_LOG("server failed to assign new connection\n");
			goto cleanup1;
		}
		connection = connection1;

		xio_idr_add_uobj(usr_idr, session, "xio_session");
		xio_idr_add_uobj(usr_idr, connection, "xio_connection");
		xio_connection_set_state(connection,
					 XIO_CONNECTION_STATE_ONLINE);

		xio_connection_keepalive_start(connection);

		task->session		= session;
		task->connection	= connection;
	} else if (tlv_type == XIO_CONNECTION_HELLO_REQ) {
		struct xio_session *session1;
		/* find the old session without lock */
		session = xio_find_session(event_data->msg.task);
		if (!session) {
			ERROR_LOG("server [new connection]: failed " \
				  "session not found. server:%p\n",
				  server);
			xio_nexus_close(nexus, NULL);
			return -1;
		}
		/* lock it and retry find */
		mutex_lock(&session->lock);
		/* session before destruction - try to lock before continue */
		session1 = xio_find_session(event_data->msg.task);
		if (!session1) {
			ERROR_LOG("server [new connection]: failed " \
				  "session not found. server:%p\n",
				  server);
			xio_nexus_close(nexus, NULL);
			mutex_unlock(&session->lock);
			return -1;
		}
		locked = 1;
		task->session = session;

		DEBUG_LOG("server [new connection]: server:%p, " \
			  "session:%p, nexus:%p, session_id:%d\n",
			   server, session, nexus, session->session_id);

		connection = xio_session_alloc_connection(
				task->session,
				server->ctx, 0,
				server->cb_private_data);

		if (!connection) {
			ERROR_LOG("server failed to allocate new connection\n");
			goto cleanup;
		}
		connection1 = xio_session_assign_nexus(task->session, nexus);
		if (!connection1) {
			ERROR_LOG("server failed to assign new connection\n");
			goto cleanup1;
		}
		connection = connection1;

		/* copy the server attributes to the connection */
		xio_connection_set_ops(connection, &server->ops);

		task->connection = connection;

		/* This in a multiple-portal situation */
		session->state = XIO_SESSION_STATE_ONLINE;
		xio_connection_set_state(connection,
					 XIO_CONNECTION_STATE_ONLINE);

		xio_connection_keepalive_start(connection);

		xio_idr_add_uobj(usr_idr, connection, "xio_connection");
	} else {
		ERROR_LOG("server unexpected message\n");
		return -1;
	}

	/* route the message to the session */
	if (session)
		xio_nexus_notify_observer(nexus, &session->observer,
					  event, event_data);
	if (locked)
		mutex_unlock(&session->lock);

	return 0;

cleanup1:
	if (connection)
		xio_session_free_connection(connection);

cleanup:
	if (session)
		xio_session_destroy(session);

	return -1;
}