nvmf: clear ctrlr->listener in remove_listener

When removing a listener, there's a small window when the listener is
already freed, while the controllers that were created on that listener
are still active.  It happens, because the listener is removed before
disconnecting its qpairs and in turn destroying the controllers.

The ctrlr->listener pointer is now cleared when a listener is freed and
its value is checked for NULL before each use.

Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com>
Change-Id: Iace65a46eebc5972cc4ef0f1c1822ffc5d3e559e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/9237
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Konrad Sztyber 2021-08-19 15:09:41 +02:00 committed by Tomasz Zawadzki
parent fb4398ef4b
commit 1c81d1afa2
2 changed files with 43 additions and 29 deletions

View File

@ -1948,6 +1948,37 @@ nvmf_ctrlr_mask_aen(struct spdk_nvmf_ctrlr *ctrlr,
}
}
/* we have to use the typedef in the function declaration to appease astyle. */
typedef enum spdk_nvme_ana_state spdk_nvme_ana_state_t;
static inline spdk_nvme_ana_state_t
nvmf_ctrlr_get_ana_state(struct spdk_nvmf_ctrlr *ctrlr, uint32_t anagrpid)
{
if (spdk_unlikely(ctrlr->listener == NULL)) {
return SPDK_NVME_ANA_INACCESSIBLE_STATE;
}
assert(anagrpid - 1 < ctrlr->subsys->max_nsid);
return ctrlr->listener->ana_state[anagrpid - 1];
}
static spdk_nvme_ana_state_t
nvmf_ctrlr_get_ana_state_from_nsid(struct spdk_nvmf_ctrlr *ctrlr, uint32_t nsid)
{
struct spdk_nvmf_ns *ns;
/* We do not have NVM subsystem specific ANA state. Hence if NSID is either
* SPDK_NVMF_GLOBAL_NS_TAG, invalid, or for inactive namespace, return
* the optimized state.
*/
ns = _nvmf_subsystem_get_ns(ctrlr->subsys, nsid);
if (ns == NULL) {
return SPDK_NVME_ANA_OPTIMIZED_STATE;
}
return nvmf_ctrlr_get_ana_state(ctrlr, ns->anagrpid);
}
static void
nvmf_get_ana_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec *iovs, int iovcnt,
uint64_t offset, uint32_t length, uint32_t rae)
@ -2003,7 +2034,7 @@ nvmf_get_ana_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec *iovs, int iov
ana_desc.ana_group_id = anagrpid;
ana_desc.num_of_nsid = ctrlr->subsys->ana_group[anagrpid - 1];
ana_desc.ana_state = ctrlr->listener->ana_state[anagrpid - 1];
ana_desc.ana_state = nvmf_ctrlr_get_ana_state(ctrlr, anagrpid);
copy_len = spdk_min(sizeof(ana_desc) - offset, length);
copied_len = _copy_buf_to_iovs(&copy_ctx, (const char *)&ana_desc + offset,
@ -2335,7 +2366,7 @@ spdk_nvmf_ctrlr_identify_ns(struct spdk_nvmf_ctrlr *ctrlr,
assert(ns->anagrpid - 1 < subsystem->max_nsid);
nsdata->anagrpid = ns->anagrpid;
ana_state = ctrlr->listener->ana_state[ns->anagrpid - 1];
ana_state = nvmf_ctrlr_get_ana_state(ctrlr, ns->anagrpid);
if (ana_state == SPDK_NVME_ANA_INACCESSIBLE_STATE ||
ana_state == SPDK_NVME_ANA_PERSISTENT_LOSS_STATE) {
nsdata->nuse = 0;
@ -2785,28 +2816,6 @@ _nvme_ana_state_to_path_status(enum spdk_nvme_ana_state ana_state)
}
}
/* we have to use the typedef in the function declaration to appease astyle. */
typedef enum spdk_nvme_ana_state spdk_nvme_ana_state_t;
static spdk_nvme_ana_state_t
nvmf_ctrlr_get_ana_state(struct spdk_nvmf_ctrlr *ctrlr, uint32_t nsid)
{
struct spdk_nvmf_ns *ns;
/* We do not have NVM subsystem specific ANA state. Hence if NSID is either
* SPDK_NVMF_GLOBAL_NS_TAG, invalid, or for inactive namespace, return
* the optimized state.
*/
ns = _nvmf_subsystem_get_ns(ctrlr->subsys, nsid);
if (ns == NULL) {
return SPDK_NVME_ANA_OPTIMIZED_STATE;
}
assert(ns->anagrpid - 1 < ctrlr->subsys->max_nsid);
return ctrlr->listener->ana_state[ns->anagrpid];
}
static int
nvmf_ctrlr_get_features(struct spdk_nvmf_request *req)
{
@ -2836,7 +2845,7 @@ nvmf_ctrlr_get_features(struct spdk_nvmf_request *req)
/*
* Process Get Features command for non-discovery controller
*/
ana_state = nvmf_ctrlr_get_ana_state(ctrlr, cmd->nsid);
ana_state = nvmf_ctrlr_get_ana_state_from_nsid(ctrlr, cmd->nsid);
switch (ana_state) {
case SPDK_NVME_ANA_INACCESSIBLE_STATE:
case SPDK_NVME_ANA_PERSISTENT_LOSS_STATE:
@ -2932,7 +2941,7 @@ nvmf_ctrlr_set_features(struct spdk_nvmf_request *req)
/*
* Process Set Features command for non-discovery controller
*/
ana_state = nvmf_ctrlr_get_ana_state(ctrlr, cmd->nsid);
ana_state = nvmf_ctrlr_get_ana_state_from_nsid(ctrlr, cmd->nsid);
switch (ana_state) {
case SPDK_NVME_ANA_INACCESSIBLE_STATE:
case SPDK_NVME_ANA_CHANGE_STATE:
@ -3736,9 +3745,7 @@ nvmf_ctrlr_process_io_cmd(struct spdk_nvmf_request *req)
return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
}
assert(ns->anagrpid - 1 < ctrlr->subsys->max_nsid);
ana_state = ctrlr->listener->ana_state[ns->anagrpid - 1];
ana_state = nvmf_ctrlr_get_ana_state(ctrlr, ns->anagrpid);
if (spdk_unlikely(ana_state != SPDK_NVME_ANA_OPTIMIZED_STATE &&
ana_state != SPDK_NVME_ANA_NON_OPTIMIZED_STATE)) {
SPDK_DEBUGLOG(nvmf, "Fail I/O command due to ANA state %d\n",

View File

@ -342,6 +342,7 @@ _nvmf_subsystem_remove_listener(struct spdk_nvmf_subsystem *subsystem,
bool stop)
{
struct spdk_nvmf_transport *transport;
struct spdk_nvmf_ctrlr *ctrlr;
if (stop) {
transport = spdk_nvmf_tgt_get_transport(subsystem->tgt, listener->trid->trstring);
@ -350,6 +351,12 @@ _nvmf_subsystem_remove_listener(struct spdk_nvmf_subsystem *subsystem,
}
}
TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
if (ctrlr->listener == listener) {
ctrlr->listener = NULL;
}
}
TAILQ_REMOVE(&subsystem->listeners, listener, link);
free(listener->ana_state);
free(listener);