Commit 64f6abea authored by Ben Walker's avatar Ben Walker
Browse files

nvmf: Sessions now contain a list of connections.



There was an extra layer of indirection complicating
things for no reason. This removes it.

Change-Id: I8d4e654eb17f8f6ec028d775329794f0745fb0f7
Signed-off-by: default avatarBen Walker <benjamin.walker@intel.com>
parent 2cb8321a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -250,7 +250,7 @@ _conn_destruct(spdk_event_t event)
	 * going away.  If this is the AQ connection then
	 * set state for other connections to abort.
	 */
	nvmf_disconnect((void *)conn, conn->sess);
	nvmf_disconnect(conn->sess, conn);

	if (conn->type == CONN_TYPE_AQ) {
		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "AQ connection destruct, trigger session closure\n");
+0 −4
Original line number Diff line number Diff line
@@ -59,10 +59,6 @@ struct spdk_nvmf_conn {

	struct nvmf_session		*sess;


	/*
	 * values saved from fabric connect and private data
	 */
	uint16_t			qid;
	uint16_t			cntlid;

+10 −6
Original line number Diff line number Diff line
@@ -434,14 +434,18 @@ nvmf_process_connect(struct spdk_nvmf_request *req)

	response = &req->rsp->connect_rsp;

	session = nvmf_connect((void *)conn, connect, connect_data, response);
	if (session != NULL) {
		conn->sess = session;
	conn->qid = connect->qid;
		if (connect->qid > 0) {
			conn->type = CONN_TYPE_IOQ; /* I/O Connection */
	conn->cntlid = connect_data->cntlid;
	if (conn->qid > 0) {
		conn->type = CONN_TYPE_IOQ;
	} else {
			/* When session first created, set some attributes */
		conn->type = CONN_TYPE_AQ;
	}

	session = nvmf_connect(conn, connect, connect_data, response);
	if (session != NULL) {
		conn->sess = session;
		if (conn->type == CONN_TYPE_AQ) {
			nvmf_init_conn_properites(conn, session, response);
		}
	}
+30 −79
Original line number Diff line number Diff line
@@ -236,118 +236,69 @@ nvmf_find_session_by_id(const char *subnqn, uint16_t cntl_id)
}

struct nvmf_session *
nvmf_connect(void *fabric_conn,
nvmf_connect(struct spdk_nvmf_conn *conn,
	     struct spdk_nvmf_fabric_connect_cmd *connect,
	     struct spdk_nvmf_fabric_connect_data *connect_data,
	     struct spdk_nvmf_fabric_connect_rsp *response)
{
	struct nvmf_session *session;
	struct nvmf_connection_entry *connection = NULL;

	connection = calloc(1, sizeof(struct nvmf_connection_entry));
	if (connection == NULL)
		goto connect_fail;
	if (conn->type == CONN_TYPE_AQ) {
		/* For admin connections, establish a new session */
		SPDK_TRACELOG(SPDK_TRACE_NVMF, "CONNECT Admin Queue for controller id %d\n", conn->cntlid);
		if (conn->cntlid != 0xFFFF) {
			/* This NVMf target only supports dynamic mode. */
			SPDK_ERRLOG("The NVMf target only supports dynamic mode.\n");
			response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
			return NULL;
		}

	/* Figure out if this is the first connect and we
	 * need to allocate an nvmf_session or if this is
	 * a subsequent connect for an I/O queue and we need
	 * to return an existing session
	 */
	if (connect->qid == 0) {
		/* first connect for AQ connection */
		SPDK_TRACELOG(SPDK_TRACE_NVMF, "AQ connect capsule\n");
		if (connect_data->cntlid == 0xffff) {
			/* no nvmf session/controller association, allocate one */
		session = nvmf_create_session(connect_data->subnqn);
		if (session == NULL) {
				SPDK_ERRLOG("create session failed\n");
			response->status.sc = SPDK_NVMF_FABRIC_SC_CONTROLLER_BUSY;
				goto connect_fail;
			}
		} else {
			SPDK_ERRLOG("nvmf AQ connection attempt to cntlid %d\n", connect_data->cntlid);
			response->status.sc = SPDK_NVMF_FABRIC_SC_INVALID_PARAM;
			goto connect_fail;
			return NULL;
		}
		connection->is_aq_conn = 1;
	} else {
		SPDK_TRACELOG(SPDK_TRACE_NVMF, "IOQ connect capsule\n");
		/* locate the existing session */
		SPDK_TRACELOG(SPDK_TRACE_NVMF, "CONNECT I/O Queue for controller id %d\n", conn->cntlid);
		session = nvmf_find_session_by_id(connect_data->subnqn, connect_data->cntlid);
		if (session == NULL) {
			SPDK_ERRLOG("invalid nvmf cntlid %d\n", connect_data->cntlid);
			SPDK_ERRLOG("Unknown controller id %d\n", conn->cntlid);
			response->status.sc = SPDK_NVMF_FABRIC_SC_RESTART_DISCOVERY;
			goto connect_fail;
			return NULL;
		}

		/* check if we would exceed session connection limit */
		if (session->num_connections >= session->max_connections_allowed) {
			SPDK_ERRLOG("connection limit %d\n", session->num_connections);
			response->status.sc = SPDK_NVMF_FABRIC_SC_CONTROLLER_BUSY;
			goto connect_fail;
		}

		if (session->is_valid == 0) {
			SPDK_ERRLOG("session invalid or at IO connection limit %d\n", session->num_connections);
			response->status.sc = SPDK_NVMF_FABRIC_SC_RESTART_DISCOVERY;
			goto connect_fail;
			return NULL;
		}
		connection->is_aq_conn = 0;
	}

	connection->fabric_conn = fabric_conn;

	session->num_connections++;
	TAILQ_INSERT_HEAD(&session->connections, connection, entries);
	TAILQ_INSERT_HEAD(&session->connections, conn, link);

	response->status_code_specific.success.cntlid = session->cntlid;
	response->status.sc = 0;

	return session;

connect_fail:
	if (connection)
		free(connection);
	return NULL;
}

void
nvmf_disconnect(void *fabric_conn,
		struct nvmf_session *session)
nvmf_disconnect(struct nvmf_session *session,
		struct spdk_nvmf_conn *conn)
{
	struct nvmf_connection_entry *conn, *tconn, *rconn = NULL;

	/* Indication from the fabric transport that a
	 * specific connection has gone way.  If the
	 * connection is the AQ connection then expect
	 * that the complete session will go away
	 */
	if (session == NULL) {
		SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_disconnect: session not active!\n");
		return;
	}

	TAILQ_FOREACH_SAFE(conn, &session->connections, entries, tconn) {
		if (conn->fabric_conn == fabric_conn) {
			rconn = conn;
			break;
		}
	}
	if (rconn == NULL) {
		SPDK_ERRLOG("Session connection did not exist!\n");
		return;
	}
	SPDK_TRACELOG(SPDK_TRACE_NVMF, "Disconnect NVMf conn %p, sess %p\n", rconn, session);

	if (session) {
		if (session->num_connections > 0) {
			session->num_connections--;
	TAILQ_REMOVE(&session->connections, rconn, entries);
	free(rconn);
			TAILQ_REMOVE(&session->connections, conn, link);
		}

		if (session->num_connections == 0) {
		SPDK_TRACELOG(SPDK_TRACE_NVMF, "Session connection count 0, deleting session %p!\n",
			      session);
			nvmf_delete_session(session);
		}
	}
}

void
nvmf_complete_cmd(void *ctx, const struct spdk_nvme_cpl *cmp)
+4 −15
Original line number Diff line number Diff line
@@ -37,22 +37,11 @@
#include <stdint.h>
#include <stdbool.h>

#include "conn.h"
#include "request.h"
#include "spdk/nvmf_spec.h"
#include "spdk/queue.h"

/*
 * This structure maintains local NVMf library specific connection
 * state that includes an opaque pointer back to its parent fabric
 * transport connection context.
 */
struct nvmf_connection_entry {
	void *fabric_conn;
	int is_aq_conn;

	TAILQ_ENTRY(nvmf_connection_entry) entries;
};

/* define a virtual controller limit to the number of QPs supported */
#define MAX_SESSION_IO_QUEUES 64

@@ -76,7 +65,7 @@ struct nvmf_session {
	} vcprop; /* virtual controller properties */
	struct spdk_nvme_ctrlr_data	vcdata; /* virtual controller data */

	TAILQ_HEAD(connection_q, nvmf_connection_entry) connections;
	TAILQ_HEAD(connection_q, spdk_nvmf_conn) connections;
	int num_connections;
	int max_connections_allowed;

@@ -86,13 +75,13 @@ struct nvmf_session {
};

struct nvmf_session *
nvmf_connect(void *fabric_conn,
nvmf_connect(struct spdk_nvmf_conn *conn,
	     struct spdk_nvmf_fabric_connect_cmd *connect,
	     struct spdk_nvmf_fabric_connect_data *connect_data,
	     struct spdk_nvmf_fabric_connect_rsp *response);

void
nvmf_disconnect(void *fabric_conn, struct nvmf_session *session);
nvmf_disconnect(struct nvmf_session *session, struct spdk_nvmf_conn *conn);

void
nvmf_init_session_properties(struct nvmf_session *session, int aq_depth);