nvme: get changed ns log once AER notice of ns changed received.

Each time the following file
"/sys/kernel/config/nvmet/subsystems/nqn_name/namespaces/ns_id/enable"
on the target side was changed, the SPDK initiator should receive an
async event (type: SPDK_NVME_ASYNC_EVENT_TYPE_NOTICE, info:
SPDK_NVME_ASYNC_EVENT_NS_ATTR_CHANGED).
But actually not.
Since for SPDK, when target sent the non-first event, the condition
"nvmet_aen_bit_disabled(ctrl, NVME_AEN_BIT_NS_ATTR)" that prevents
target from sending event was matched.
This commit fix this issue by issuing a get_log_page cmd for each async
event received, just as the kernel initiator does.

Fixes #1825.

Signed-off-by: tyler.sun <tyler.sun@dell.com>
Change-Id: I2973470a81893456ca12e86ac390ea1de0eed62c
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/7107
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
Reviewed-by: Ziye Yang <ziye.yang@intel.com>
This commit is contained in:
tyler_sun 2021-04-24 15:58:44 +08:00 committed by Tomasz Zawadzki
parent d63fbc8a8e
commit 4f4f505c77
2 changed files with 85 additions and 6 deletions

View File

@ -72,6 +72,11 @@ extern "C" {
*/
#define SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS 0xFFFFFFFFu
/**
* Maximum number of entries in the log page of Changed Namespace List.
*/
#define SPDK_NVME_MAX_CHANGED_NAMESPACES 1024
union spdk_nvme_cap_register {
uint64_t raw;
struct {

View File

@ -38,6 +38,7 @@
#include "spdk/env.h"
#include "spdk/string.h"
#include "spdk/endian.h"
struct nvme_active_ns_ctx;
@ -2614,24 +2615,81 @@ fail:
return rc;
}
static int
nvme_ctrlr_clear_changed_ns_log(struct spdk_nvme_ctrlr *ctrlr)
{
struct nvme_completion_poll_status *status;
int rc = -ENOMEM;
char *buffer = NULL;
uint32_t nsid;
size_t buf_size = (SPDK_NVME_MAX_CHANGED_NAMESPACES * sizeof(uint32_t));
buffer = spdk_dma_zmalloc(buf_size, 4096, NULL);
if (!buffer) {
NVME_CTRLR_ERRLOG(ctrlr, "Failed to allocate buffer for getting "
"changed ns log.\n");
return rc;
}
status = calloc(1, sizeof(*status));
if (!status) {
NVME_CTRLR_ERRLOG(ctrlr, "Failed to allocate status tracker\n");
goto free_buffer;
}
rc = spdk_nvme_ctrlr_cmd_get_log_page(ctrlr,
SPDK_NVME_LOG_CHANGED_NS_LIST,
SPDK_NVME_GLOBAL_NS_TAG,
buffer, buf_size, 0,
nvme_completion_poll_cb, status);
if (rc) {
NVME_CTRLR_ERRLOG(ctrlr, "spdk_nvme_ctrlr_cmd_get_log_page() failed: rc=%d\n", rc);
free(status);
goto free_buffer;
}
rc = nvme_wait_for_completion_timeout(ctrlr->adminq, status,
ctrlr->opts.admin_timeout_ms * 1000);
if (!status->timed_out) {
free(status);
}
if (rc) {
NVME_CTRLR_ERRLOG(ctrlr, "wait for spdk_nvme_ctrlr_cmd_get_log_page failed: rc=%d\n", rc);
goto free_buffer;
}
/* only check the case of overflow. */
nsid = from_le32(buffer);
if (nsid == 0xffffffffu) {
NVME_CTRLR_WARNLOG(ctrlr, "changed ns log overflowed.\n");
}
free_buffer:
spdk_dma_free(buffer);
return rc;
}
void
nvme_ctrlr_process_async_event(struct spdk_nvme_ctrlr *ctrlr,
const struct spdk_nvme_cpl *cpl)
{
union spdk_nvme_async_event_completion event;
struct spdk_nvme_ctrlr_process *active_proc;
bool ns_changed = false;
int rc;
event.raw = cpl->cdw0;
if ((event.bits.async_event_type == SPDK_NVME_ASYNC_EVENT_TYPE_NOTICE) &&
(event.bits.async_event_info == SPDK_NVME_ASYNC_EVENT_NS_ATTR_CHANGED)) {
rc = nvme_ctrlr_identify_active_ns(ctrlr);
if (rc) {
return;
}
nvme_ctrlr_update_namespaces(ctrlr);
nvme_io_msg_ctrlr_update(ctrlr);
/*
* apps (e.g., test/nvme/aer/aer.c) may also get changed ns log (through
* active_proc->aer_cb_fn). To avoid impaction, move our operations
* behind call of active_proc->aer_cb_fn.
*/
ns_changed = true;
}
if ((event.bits.async_event_type == SPDK_NVME_ASYNC_EVENT_TYPE_NOTICE) &&
@ -2647,6 +2705,22 @@ nvme_ctrlr_process_async_event(struct spdk_nvme_ctrlr *ctrlr,
if (active_proc && active_proc->aer_cb_fn) {
active_proc->aer_cb_fn(active_proc->aer_cb_arg, cpl);
}
if (ns_changed) {
/*
* Must have the changed ns log cleared by getting it.
* Otherwise, the target won't send
* the subsequent ns enabling/disabling events to us.
*/
nvme_ctrlr_clear_changed_ns_log(ctrlr);
rc = nvme_ctrlr_identify_active_ns(ctrlr);
if (rc) {
return;
}
nvme_ctrlr_update_namespaces(ctrlr);
nvme_io_msg_ctrlr_update(ctrlr);
}
}
static void