Commit ec38ec12 authored by Ben Walker's avatar Ben Walker
Browse files

nvmf: Handle wrap-around for global cntlids



64k sessions over the lifetime of a single target is something
that really could happen, so handle this case.

Change-Id: Iaed92b9ff6cd078fcd7c1efe88cf0c860c77c4ac
Signed-off-by: default avatarBen Walker <benjamin.walker@intel.com>
parent d77c0301
Loading
Loading
Loading
Loading
+46 −3
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
 */

#include <arpa/inet.h>
#include <stdint.h>
#include <string.h>

#include "session.h"
@@ -47,8 +48,6 @@

#define MIN_KEEP_ALIVE_TIMEOUT 10000

static uint16_t g_next_cntlid = 1;

static void
nvmf_init_discovery_session_properties(struct spdk_nvmf_session *session)
{
@@ -191,6 +190,44 @@ invalid_connect_response(struct spdk_nvmf_fabric_connect_rsp *rsp, uint8_t iattr
	rsp->status_code_specific.invalid.ipo = ipo;
}

static uint16_t
spdk_nvmf_session_gen_cntlid(void)
{
	static uint16_t cntlid = 0; /* cntlid is static, so its value is preserved */
	struct spdk_nvmf_subsystem *subsystem;
	uint16_t count;

	count = UINT16_MAX - 1;
	do {
		/* cntlid is an unsigned 16-bit integer, so let it overflow
		 * back to 0 if necessary.
		 */
		cntlid++;
		if (cntlid == 0) {
			/* 0 is not a valid cntlid because it is the reserved value in the RDMA
			 * private data for cntlid. This is the value sent by pre-NVMe-oF 1.1
			 * initiators.
			 */
			cntlid++;
		}

		/* Check if a subsystem with this cntlid currently exists. This could
		 * happen for a very long-lived session on a target with many short-lived
		 * sessions, where cntlid wraps around.
		 */
		subsystem = spdk_nvmf_find_subsystem_with_cntlid(cntlid);

		count--;

	} while (subsystem != NULL && count > 0);

	if (count == 0) {
		return 0;
	}

	return cntlid;
}

void
spdk_nvmf_session_connect(struct spdk_nvmf_conn *conn,
			  struct spdk_nvmf_fabric_connect_cmd *cmd,
@@ -260,7 +297,13 @@ spdk_nvmf_session_connect(struct spdk_nvmf_conn *conn,

		TAILQ_INIT(&session->connections);

		session->cntlid = g_next_cntlid++;
		session->cntlid = spdk_nvmf_session_gen_cntlid();
		if (session->cntlid == 0) {
			/* Unable to get a cntlid */
			SPDK_ERRLOG("Reached max simultaneous sessions\n");
			rsp->status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
			return;
		}
		session->kato = cmd->kato;
		session->async_event_config.raw = 0;
		session->num_connections = 0;
+6 −0
Original line number Diff line number Diff line
@@ -44,6 +44,12 @@ SPDK_LOG_REGISTER_TRACE_FLAG("nvmf", SPDK_TRACE_NVMF)

struct spdk_nvmf_globals g_nvmf_tgt;

struct spdk_nvmf_subsystem *
spdk_nvmf_find_subsystem_with_cntlid(uint16_t cntlid)
{
	return NULL;
}

struct spdk_nvmf_subsystem *
nvmf_find_subsystem(const char *subnqn)
{