Commit 568c5c3b authored by Alex Michon's avatar Alex Michon Committed by Jim Harris
Browse files

lib/nvmf: Handle RGO field in ANA log



When RGO is set, we should set the number of namespace ids to 0 and the
list of namespace ids should be empty.

Change-Id: I1c1f6282e261ddf00a7cc40b1f301edf407f02b4
Signed-off-by: default avatarAlex Michon <amichon@kalrayinc.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/24872


Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Community-CI: Mellanox Build Bot
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent 0e7362ff
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -2344,7 +2344,7 @@ nvmf_get_error_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec *iovs, int i

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)
		      uint64_t offset, uint32_t length, uint32_t rae, uint32_t rgo)
{
	struct spdk_nvme_ana_page ana_hdr;
	struct spdk_nvme_ana_group_descriptor ana_desc;
@@ -2396,7 +2396,11 @@ nvmf_get_ana_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec *iovs, int iov
			memset(&ana_desc, 0, sizeof(ana_desc));

			ana_desc.ana_group_id = anagrpid;
			if (rgo) {
				ana_desc.num_of_nsid = 0;
			} else {
				ana_desc.num_of_nsid = ctrlr->subsys->ana_group[anagrpid - 1];
			}
			ana_desc.ana_state = nvmf_ctrlr_get_ana_state(ctrlr, anagrpid);

			copy_len = spdk_min(sizeof(ana_desc) - offset, length);
@@ -2411,6 +2415,10 @@ nvmf_get_ana_log_page(struct spdk_nvmf_ctrlr *ctrlr, struct iovec *iovs, int iov
			}
		}

		if (rgo) {
			continue;
		}

		/* TODO: Revisit here about O(n^2) cost if we have subsystem with
		 * many namespaces in the future.
		 */
@@ -2705,7 +2713,8 @@ nvmf_ctrlr_get_log_page(struct spdk_nvmf_request *req)
			return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
		case SPDK_NVME_LOG_ASYMMETRIC_NAMESPACE_ACCESS:
			if (subsystem->flags.ana_reporting) {
				nvmf_get_ana_log_page(ctrlr, req->iov, req->iovcnt, offset, len, rae);
				uint32_t rgo = cmd->cdw10_bits.get_log_page.lsp & 1;
				nvmf_get_ana_log_page(ctrlr, req->iov, req->iovcnt, offset, len, rae, rgo);
				return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
			} else {
				goto invalid_log_page;
+126 −100
Original line number Diff line number Diff line
@@ -2165,8 +2165,10 @@ test_multi_async_event_reqs(void)
static void
test_get_ana_log_page_one_ns_per_anagrp(void)
{
#define UT_ANA_DESC_SIZE (sizeof(struct spdk_nvme_ana_group_descriptor) + sizeof(uint32_t))
#define UT_ANA_LOG_PAGE_SIZE (sizeof(struct spdk_nvme_ana_page) + 3 * UT_ANA_DESC_SIZE)
#define UT_ANA_DESC_MAX_SIZE (sizeof(struct spdk_nvme_ana_group_descriptor) + sizeof(uint32_t))
#define UT_ANA_LOG_PAGE_MAX_SIZE (sizeof(struct spdk_nvme_ana_page) + 3 * UT_ANA_DESC_MAX_SIZE)
#define UT_ANA_DESC_SIZE(rgo) (sizeof(struct spdk_nvme_ana_group_descriptor) + (rgo ? 0 : sizeof(uint32_t)))
#define UT_ANA_LOG_PAGE_SIZE(rgo) (sizeof(struct spdk_nvme_ana_page) + 3 * UT_ANA_DESC_SIZE(rgo))
	uint32_t ana_group[3];
	struct spdk_nvmf_subsystem subsystem = { .ana_group = ana_group };
	struct spdk_nvmf_ctrlr ctrlr = {};
@@ -2177,12 +2179,13 @@ test_get_ana_log_page_one_ns_per_anagrp(void)
	uint64_t offset;
	uint32_t length;
	int i;
	char expected_page[UT_ANA_LOG_PAGE_SIZE] = {0};
	char actual_page[UT_ANA_LOG_PAGE_SIZE] = {0};
	char expected_page[UT_ANA_LOG_PAGE_MAX_SIZE] = {0};
	char actual_page[UT_ANA_LOG_PAGE_MAX_SIZE] = {0};
	struct iovec iov, iovs[2];
	struct spdk_nvme_ana_page *ana_hdr;
	char _ana_desc[UT_ANA_DESC_SIZE];
	char _ana_desc[UT_ANA_DESC_MAX_SIZE];
	struct spdk_nvme_ana_group_descriptor *ana_desc;
	uint32_t rgo;

	subsystem.ns = ns_arr;
	subsystem.max_nsid = 3;
@@ -2201,6 +2204,10 @@ test_get_ana_log_page_one_ns_per_anagrp(void)
		ns_arr[i]->anagrpid = i + 1;
	}

	for (rgo = 0; rgo <= 1; rgo++) {
		memset(expected_page, 0, sizeof(expected_page));
		memset(actual_page, 0, sizeof(actual_page));

		/* create expected page */
		ana_hdr = (void *)&expected_page[0];
		ana_hdr->num_ana_group_desc = 3;
@@ -2211,48 +2218,56 @@ test_get_ana_log_page_one_ns_per_anagrp(void)
		offset = sizeof(struct spdk_nvme_ana_page);

		for (i = 0; i < 3; i++) {
		memset(ana_desc, 0, UT_ANA_DESC_SIZE);
			memset(ana_desc, 0, UT_ANA_DESC_MAX_SIZE);
			ana_desc->ana_group_id = ns_arr[i]->nsid;
		ana_desc->num_of_nsid = 1;
			ana_desc->num_of_nsid = rgo ? 0 : 1;
			ana_desc->change_count = 0;
			ana_desc->ana_state = ctrlr.listener->ana_state[i];
			if (!rgo) {
				ana_desc->nsid[0] = ns_arr[i]->nsid;
		memcpy(&expected_page[offset], ana_desc, UT_ANA_DESC_SIZE);
		offset += UT_ANA_DESC_SIZE;
			}
			memcpy(&expected_page[offset], ana_desc, UT_ANA_DESC_SIZE(rgo));
			offset += UT_ANA_DESC_SIZE(rgo);
		}

		/* read entire actual log page */
		offset = 0;
	while (offset < UT_ANA_LOG_PAGE_SIZE) {
		length = spdk_min(16, UT_ANA_LOG_PAGE_SIZE - offset);
		while (offset < UT_ANA_LOG_PAGE_MAX_SIZE) {
			length = spdk_min(16, UT_ANA_LOG_PAGE_MAX_SIZE - offset);
			iov.iov_base = &actual_page[offset];
			iov.iov_len = length;
		nvmf_get_ana_log_page(&ctrlr, &iov, 1, offset, length, 0);
			nvmf_get_ana_log_page(&ctrlr, &iov, 1, offset, length, 0, rgo);
			offset += length;
		}

		/* compare expected page and actual page */
	CU_ASSERT(memcmp(expected_page, actual_page, UT_ANA_LOG_PAGE_SIZE) == 0);
		CU_ASSERT(memcmp(expected_page, actual_page, UT_ANA_LOG_PAGE_MAX_SIZE) == 0);

	memset(&actual_page[0], 0, UT_ANA_LOG_PAGE_SIZE);
		memset(&actual_page[0], 0, UT_ANA_LOG_PAGE_MAX_SIZE);
		offset = 0;
		iovs[0].iov_base = &actual_page[offset];
	iovs[0].iov_len = UT_ANA_LOG_PAGE_SIZE - UT_ANA_DESC_SIZE + 4;
	offset += UT_ANA_LOG_PAGE_SIZE - UT_ANA_DESC_SIZE + 4;
		iovs[0].iov_len = UT_ANA_LOG_PAGE_MAX_SIZE - UT_ANA_DESC_MAX_SIZE + 4;
		offset += UT_ANA_LOG_PAGE_MAX_SIZE - UT_ANA_DESC_MAX_SIZE + 4;
		iovs[1].iov_base = &actual_page[offset];
	iovs[1].iov_len = UT_ANA_LOG_PAGE_SIZE - offset;
	nvmf_get_ana_log_page(&ctrlr, &iovs[0], 2, 0, UT_ANA_LOG_PAGE_SIZE, 0);
		iovs[1].iov_len = UT_ANA_LOG_PAGE_MAX_SIZE - offset;
		nvmf_get_ana_log_page(&ctrlr, &iovs[0], 2, 0, UT_ANA_LOG_PAGE_MAX_SIZE, 0, rgo);

	CU_ASSERT(memcmp(expected_page, actual_page, UT_ANA_LOG_PAGE_SIZE) == 0);
		CU_ASSERT(memcmp(expected_page, actual_page, UT_ANA_LOG_PAGE_MAX_SIZE) == 0);
	}

#undef UT_ANA_DESC_SIZE
#undef UT_ANA_LOG_PAGE_SIZE
#undef UT_ANA_DESC_MAX_SIZE
#undef UT_ANA_LOG_PAGE_MAX_SIZE
}

static void
test_get_ana_log_page_multi_ns_per_anagrp(void)
{
#define UT_ANA_LOG_PAGE_SIZE	(sizeof(struct spdk_nvme_ana_page) +	\
#define UT_ANA_LOG_PAGE_SIZE(rgo)	(sizeof(struct spdk_nvme_ana_page) +	\
					 sizeof(struct spdk_nvme_ana_group_descriptor) * 2 +	\
					 (rgo ? 0 : (sizeof(uint32_t) * 5)))
#define UT_ANA_LOG_PAGE_MAX_SIZE	(sizeof(struct spdk_nvme_ana_page) +	\
					 sizeof(struct spdk_nvme_ana_group_descriptor) * 2 +	\
					 sizeof(uint32_t) * 5)
	struct spdk_nvmf_ns ns[5];
@@ -2262,15 +2277,16 @@ test_get_ana_log_page_multi_ns_per_anagrp(void)
	enum spdk_nvme_ana_state ana_state[5];
	struct spdk_nvmf_subsystem_listener listener = { .ana_state = ana_state, };
	struct spdk_nvmf_ctrlr ctrlr = { .subsys = &subsystem, .listener = &listener, };
	char expected_page[UT_ANA_LOG_PAGE_SIZE] = {0};
	char actual_page[UT_ANA_LOG_PAGE_SIZE] = {0};
	char expected_page[UT_ANA_LOG_PAGE_MAX_SIZE] = {0};
	char actual_page[UT_ANA_LOG_PAGE_MAX_SIZE] = {0};
	struct iovec iov, iovs[2];
	struct spdk_nvme_ana_page *ana_hdr;
	char _ana_desc[UT_ANA_LOG_PAGE_SIZE];
	char _ana_desc[UT_ANA_LOG_PAGE_MAX_SIZE];
	struct spdk_nvme_ana_group_descriptor *ana_desc;
	uint64_t offset;
	uint32_t length;
	int i;
	uint32_t rgo;

	subsystem.max_nsid = 5;
	subsystem.ana_group[1] = 3;
@@ -2288,6 +2304,10 @@ test_get_ana_log_page_multi_ns_per_anagrp(void)
	ns_arr[3]->anagrpid = 3;
	ns_arr[4]->anagrpid = 2;

	for (rgo = 0; rgo <= 1; rgo++) {
		memset(expected_page, 0, sizeof(expected_page));
		memset(actual_page, 0, sizeof(actual_page));

		/* create expected page */
		ana_hdr = (void *)&expected_page[0];
		ana_hdr->num_ana_group_desc = 2;
@@ -2299,50 +2319,56 @@ test_get_ana_log_page_multi_ns_per_anagrp(void)

		memset(_ana_desc, 0, sizeof(_ana_desc));
		ana_desc->ana_group_id = 2;
	ana_desc->num_of_nsid = 3;
		ana_desc->num_of_nsid = rgo ? 0 : 3;
		ana_desc->change_count = 0;
		ana_desc->ana_state = SPDK_NVME_ANA_OPTIMIZED_STATE;
		if (!rgo) {
			ana_desc->nsid[0] = 1;
			ana_desc->nsid[1] = 3;
			ana_desc->nsid[2] = 5;
		}
		memcpy(&expected_page[offset], ana_desc, sizeof(struct spdk_nvme_ana_group_descriptor) +
	       sizeof(uint32_t) * 3);
	offset += sizeof(struct spdk_nvme_ana_group_descriptor) + sizeof(uint32_t) * 3;
		       (rgo ? 0 : (sizeof(uint32_t) * 3)));
		offset += sizeof(struct spdk_nvme_ana_group_descriptor) + (rgo ? 0 : (sizeof(uint32_t) * 3));

		memset(_ana_desc, 0, sizeof(_ana_desc));
		ana_desc->ana_group_id = 3;
	ana_desc->num_of_nsid = 2;
		ana_desc->num_of_nsid = rgo ? 0 : 2;
		ana_desc->change_count = 0;
		ana_desc->ana_state = SPDK_NVME_ANA_OPTIMIZED_STATE;
		if (!rgo) {
			ana_desc->nsid[0] = 2;
			ana_desc->nsid[1] = 4;
		}
		memcpy(&expected_page[offset], ana_desc, sizeof(struct spdk_nvme_ana_group_descriptor) +
	       sizeof(uint32_t) * 2);
		       (rgo ? 0 : (sizeof(uint32_t) * 2)));

		/* read entire actual log page, and compare expected page and actual page. */
		offset = 0;
	while (offset < UT_ANA_LOG_PAGE_SIZE) {
		length = spdk_min(16, UT_ANA_LOG_PAGE_SIZE - offset);
		while (offset < UT_ANA_LOG_PAGE_MAX_SIZE) {
			length = spdk_min(16, UT_ANA_LOG_PAGE_MAX_SIZE - offset);
			iov.iov_base = &actual_page[offset];
			iov.iov_len = length;
		nvmf_get_ana_log_page(&ctrlr, &iov, 1, offset, length, 0);
			nvmf_get_ana_log_page(&ctrlr, &iov, 1, offset, length, 0, rgo);
			offset += length;
		}

	CU_ASSERT(memcmp(expected_page, actual_page, UT_ANA_LOG_PAGE_SIZE) == 0);
		CU_ASSERT(memcmp(expected_page, actual_page, UT_ANA_LOG_PAGE_MAX_SIZE) == 0);

	memset(&actual_page[0], 0, UT_ANA_LOG_PAGE_SIZE);
		memset(&actual_page[0], 0, UT_ANA_LOG_PAGE_MAX_SIZE);
		offset = 0;
		iovs[0].iov_base = &actual_page[offset];
	iovs[0].iov_len = UT_ANA_LOG_PAGE_SIZE - sizeof(uint32_t) * 5;
	offset += UT_ANA_LOG_PAGE_SIZE - sizeof(uint32_t) * 5;
		iovs[0].iov_len = UT_ANA_LOG_PAGE_MAX_SIZE - sizeof(uint32_t) * 5;
		offset += UT_ANA_LOG_PAGE_MAX_SIZE - sizeof(uint32_t) * 5;
		iovs[1].iov_base = &actual_page[offset];
		iovs[1].iov_len = sizeof(uint32_t) * 5;
	nvmf_get_ana_log_page(&ctrlr, &iovs[0], 2, 0, UT_ANA_LOG_PAGE_SIZE, 0);
		nvmf_get_ana_log_page(&ctrlr, &iovs[0], 2, 0, UT_ANA_LOG_PAGE_MAX_SIZE, 0, rgo);

	CU_ASSERT(memcmp(expected_page, actual_page, UT_ANA_LOG_PAGE_SIZE) == 0);
		CU_ASSERT(memcmp(expected_page, actual_page, UT_ANA_LOG_PAGE_MAX_SIZE) == 0);
	}

#undef UT_ANA_LOG_PAGE_SIZE
#undef UT_ANA_LOG_PAGE_MAX_SIZE
}
static void
test_multi_async_events(void)