From ec38ec127cf6e06e5cb37ede8770be08ba9b8776 Mon Sep 17 00:00:00 2001 From: Ben Walker Date: Thu, 19 Jan 2017 11:02:17 -0700 Subject: [PATCH] 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: Ben Walker --- lib/nvmf/session.c | 49 ++++++++++++++++++++++++++++-- test/lib/nvmf/session/session_ut.c | 6 ++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/lib/nvmf/session.c b/lib/nvmf/session.c index 040cbef07..397e0a9d8 100644 --- a/lib/nvmf/session.c +++ b/lib/nvmf/session.c @@ -32,6 +32,7 @@ */ #include +#include #include #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; diff --git a/test/lib/nvmf/session/session_ut.c b/test/lib/nvmf/session/session_ut.c index 4224dc2e7..c13b7fa91 100644 --- a/test/lib/nvmf/session/session_ut.c +++ b/test/lib/nvmf/session/session_ut.c @@ -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) {