nvme: add spdk_nvme_ns_get_uuid() function

This function retrieves the UUID from a namespace, if available.

Change-Id: I98c55375948b92eaf429b41fb36dfea4e2b780a2
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/404734
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Daniel Verkamp 2018-03-21 17:36:06 -07:00 committed by Jim Harris
parent 3d57e4a8f4
commit 15bd6999db
5 changed files with 145 additions and 1 deletions

View File

@ -15,6 +15,8 @@ needed; previously, the response was limited to 32 kilobytes.
EXPERIMENTAL: Adds support for WDS and RDS capable CMBs in NVMe controllers. This support is EXPERIMENTAL: Adds support for WDS and RDS capable CMBs in NVMe controllers. This support is
experimental pending a functional allocator to free and reallocate CMB buffers. experimental pending a functional allocator to free and reallocate CMB buffers.
spdk_nvme_ns_get_uuid() has been added to allow retrieval of per-namespace UUIDs when available.
### NVMe-oF Target ### NVMe-oF Target
Namespaces may now be assigned unique identifiers via new optional "eui64" and "nguid" parameters Namespaces may now be assigned unique identifiers via new optional "eui64" and "nguid" parameters

View File

@ -1052,6 +1052,15 @@ enum spdk_nvme_dealloc_logical_block_read_value spdk_nvme_ns_get_dealloc_logical
*/ */
uint32_t spdk_nvme_ns_get_optimal_io_boundary(struct spdk_nvme_ns *ns); uint32_t spdk_nvme_ns_get_optimal_io_boundary(struct spdk_nvme_ns *ns);
/**
* Get the UUID for the given namespace.
*
* \param ns Namespace to query.
*
* \return Pointer to namespace UUID, or NULL if ns does not have a UUID.
*/
const struct spdk_uuid *spdk_nvme_ns_get_uuid(const struct spdk_nvme_ns *ns);
/** /**
* \brief Namespace command support flags. * \brief Namespace command support flags.
*/ */

View File

@ -302,6 +302,9 @@ struct spdk_nvme_ns {
uint32_t sectors_per_stripe; uint32_t sectors_per_stripe;
uint32_t id; uint32_t id;
uint16_t flags; uint16_t flags;
/* Namespace Identification Descriptor List (CNS = 03h) */
uint8_t id_desc_list[4096];
}; };
/** /**

View File

@ -122,6 +122,30 @@ int nvme_ns_identify_update(struct spdk_nvme_ns *ns)
ns->flags |= SPDK_NVME_NS_DPS_PI_SUPPORTED; ns->flags |= SPDK_NVME_NS_DPS_PI_SUPPORTED;
ns->pi_type = nsdata->dps.pit; ns->pi_type = nsdata->dps.pit;
} }
memset(ns->id_desc_list, 0, sizeof(ns->id_desc_list));
if (ns->ctrlr->cdata.ver.raw >= SPDK_NVME_VERSION(1, 3, 0)) {
SPDK_DEBUGLOG(SPDK_LOG_NVME, "Attempting to retrieve NS ID Descriptor List\n");
status.done = false;
rc = nvme_ctrlr_cmd_identify(ns->ctrlr, SPDK_NVME_IDENTIFY_NS_ID_DESCRIPTOR_LIST, 0, ns->id,
ns->id_desc_list, sizeof(ns->id_desc_list),
nvme_completion_poll_cb, &status);
if (rc == 0) {
while (status.done == false) {
nvme_robust_mutex_lock(&ns->ctrlr->ctrlr_lock);
spdk_nvme_qpair_process_completions(ns->ctrlr->adminq, 0);
nvme_robust_mutex_unlock(&ns->ctrlr->ctrlr_lock);
}
}
if (rc != 0 || spdk_nvme_cpl_is_error(&status.cpl)) {
SPDK_WARNLOG("Failed to retrieve NS ID Descriptor List\n");
memset(ns->id_desc_list, 0, sizeof(ns->id_desc_list));
}
} else {
SPDK_DEBUGLOG(SPDK_LOG_NVME, "Version < 1.3; not attempting to retrieve NS ID Descriptor List\n");
}
return rc; return rc;
} }
@ -223,6 +247,55 @@ spdk_nvme_ns_get_optimal_io_boundary(struct spdk_nvme_ns *ns)
return ns->sectors_per_stripe; return ns->sectors_per_stripe;
} }
static const void *
_spdk_nvme_ns_find_id_desc(const struct spdk_nvme_ns *ns, enum spdk_nvme_nidt type, size_t *length)
{
const struct spdk_nvme_ns_id_desc *desc;
size_t offset;
offset = 0;
while (offset + 4 < sizeof(ns->id_desc_list)) {
desc = (const struct spdk_nvme_ns_id_desc *)&ns->id_desc_list[offset];
if (desc->nidl == 0) {
/* End of list */
return NULL;
}
/*
* Check if this descriptor fits within the list.
* 4 is the fixed-size descriptor header (not counted in NIDL).
*/
if (offset + desc->nidl + 4 > sizeof(ns->id_desc_list)) {
/* Descriptor longer than remaining space in list (invalid) */
return NULL;
}
if (desc->nidt == type) {
*length = desc->nidl;
return &desc->nid[0];
}
offset += 4 + desc->nidl;
}
return NULL;
}
const struct spdk_uuid *
spdk_nvme_ns_get_uuid(const struct spdk_nvme_ns *ns)
{
const struct spdk_uuid *uuid;
size_t uuid_size;
uuid = _spdk_nvme_ns_find_id_desc(ns, SPDK_NVME_NIDT_UUID, &uuid_size);
if (uuid == NULL || uuid_size != sizeof(*uuid)) {
return NULL;
}
return uuid;
}
int nvme_ns_construct(struct spdk_nvme_ns *ns, uint32_t id, int nvme_ns_construct(struct spdk_nvme_ns *ns, uint32_t id,
struct spdk_nvme_ctrlr *ctrlr) struct spdk_nvme_ctrlr *ctrlr)
{ {

View File

@ -71,6 +71,62 @@ test_nvme_ns_construct(void)
CU_ASSERT(ns.id == 1); CU_ASSERT(ns.id == 1);
} }
static void
test_nvme_ns_uuid(void)
{
struct spdk_nvme_ns ns = {};
const struct spdk_uuid *uuid;
struct spdk_uuid expected_uuid;
memset(&expected_uuid, 0xA5, sizeof(expected_uuid));
/* Empty list - no UUID should be found */
memset(ns.id_desc_list, 0, sizeof(ns.id_desc_list));
uuid = spdk_nvme_ns_get_uuid(&ns);
CU_ASSERT(uuid == NULL);
/* NGUID only (no UUID in list) */
memset(ns.id_desc_list, 0, sizeof(ns.id_desc_list));
ns.id_desc_list[0] = 0x02; /* NIDT == NGUID */
ns.id_desc_list[1] = 0x10; /* NIDL */
memset(&ns.id_desc_list[4], 0xCC, 0x10);
uuid = spdk_nvme_ns_get_uuid(&ns);
CU_ASSERT(uuid == NULL);
/* Just UUID in the list */
memset(ns.id_desc_list, 0, sizeof(ns.id_desc_list));
ns.id_desc_list[0] = 0x03; /* NIDT == UUID */
ns.id_desc_list[1] = 0x10; /* NIDL */
memcpy(&ns.id_desc_list[4], &expected_uuid, sizeof(expected_uuid));
uuid = spdk_nvme_ns_get_uuid(&ns);
SPDK_CU_ASSERT_FATAL(uuid != NULL);
CU_ASSERT(memcmp(uuid, &expected_uuid, sizeof(*uuid)) == 0);
/* UUID followed by NGUID */
memset(ns.id_desc_list, 0, sizeof(ns.id_desc_list));
ns.id_desc_list[0] = 0x03; /* NIDT == UUID */
ns.id_desc_list[1] = 0x10; /* NIDL */
memcpy(&ns.id_desc_list[4], &expected_uuid, sizeof(expected_uuid));
ns.id_desc_list[20] = 0x02; /* NIDT == NGUID */
ns.id_desc_list[21] = 0x10; /* NIDL */
memset(&ns.id_desc_list[24], 0xCC, 0x10);
uuid = spdk_nvme_ns_get_uuid(&ns);
SPDK_CU_ASSERT_FATAL(uuid != NULL);
CU_ASSERT(memcmp(uuid, &expected_uuid, sizeof(*uuid)) == 0);
/* NGUID followed by UUID */
memset(ns.id_desc_list, 0, sizeof(ns.id_desc_list));
ns.id_desc_list[0] = 0x02; /* NIDT == NGUID */
ns.id_desc_list[1] = 0x10; /* NIDL */
memset(&ns.id_desc_list[4], 0xCC, 0x10);
ns.id_desc_list[20] = 0x03; /* NIDT = UUID */
ns.id_desc_list[21] = 0x10; /* NIDL */
memcpy(&ns.id_desc_list[24], &expected_uuid, sizeof(expected_uuid));
uuid = spdk_nvme_ns_get_uuid(&ns);
SPDK_CU_ASSERT_FATAL(uuid != NULL);
CU_ASSERT(memcmp(uuid, &expected_uuid, sizeof(*uuid)) == 0);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
CU_pSuite suite = NULL; CU_pSuite suite = NULL;
@ -87,7 +143,8 @@ int main(int argc, char **argv)
} }
if ( if (
CU_add_test(suite, "test_nvme_ns", test_nvme_ns_construct) == NULL CU_add_test(suite, "test_nvme_ns", test_nvme_ns_construct) == NULL ||
CU_add_test(suite, "test_nvme_ns_uuid", test_nvme_ns_uuid) == NULL
) { ) {
CU_cleanup_registry(); CU_cleanup_registry();
return CU_get_error(); return CU_get_error();