nvme: add support for NS Optimal IO Boundary

An optional field was added in NVMe 1.3 to indicate the optimal I/O
boundary that should not be crossed for best performance.  This is
equivalent to the existing Intel-specific stripe size quirk.

Add support for the new NOIOB field and move the current quirk-based
code so it is updated in nvme_ns_identify_update().

Change-Id: Ifc4974f51dcd59e7f24565d8d5159b036458c6e5
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/373132
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Daniel Verkamp 2017-08-07 10:17:29 -07:00
parent 6552b6dac2
commit 99f838a36a
6 changed files with 38 additions and 12 deletions

View File

@ -20,6 +20,12 @@ currently only supported by NVMe block devices.
The AIO bdev now allows the user to override the auto-detected block size.
### NVMe driver
The NVMe driver now recognizes the NVMe 1.3 Namespace Optimal I/O Boundary field.
NVMe 1.3 devices may report an optimal I/O boundary, which the driver will take
into account when splitting I/O requests.
## v17.07: Build system improvements, userspace vhost-blk target, and GPT bdev
### Build System

View File

@ -919,6 +919,15 @@ bool spdk_nvme_ns_supports_extended_lba(struct spdk_nvme_ns *ns);
enum spdk_nvme_dealloc_logical_block_read_value spdk_nvme_ns_get_dealloc_logical_block_read_value(
struct spdk_nvme_ns *ns);
/**
* \brief Get the optimal I/O boundary, in blocks, for the given namespace.
*
* \return Optimal granularity of I/O commands, in blocks, or 0 if no optimal granularity is reported.
*
* Read and write commands should not cross the optimal I/O boundary for best performance.
*/
uint32_t spdk_nvme_ns_get_optimal_io_boundary(struct spdk_nvme_ns *ns);
/**
* \brief Namespace command support flags.
*/

View File

@ -288,7 +288,6 @@ struct spdk_nvme_qpair {
struct spdk_nvme_ns {
struct spdk_nvme_ctrlr *ctrlr;
uint32_t stripe_size;
uint32_t sector_size;
/*

View File

@ -63,7 +63,6 @@ int nvme_ns_identify_update(struct spdk_nvme_ns *ns)
/* This can occur if the namespace is not active. Simply zero the
* namespace data and continue. */
memset(nsdata, 0, sizeof(*nsdata));
ns->stripe_size = 0;
ns->sector_size = 0;
ns->extended_lba_size = 0;
ns->md_size = 0;
@ -86,7 +85,20 @@ int nvme_ns_identify_update(struct spdk_nvme_ns *ns)
}
ns->sectors_per_max_io = spdk_nvme_ns_get_max_io_xfer_size(ns) / ns->extended_lba_size;
ns->sectors_per_stripe = ns->stripe_size / ns->sector_size;
if (nsdata->noiob) {
ns->sectors_per_stripe = nsdata->noiob;
SPDK_TRACELOG(SPDK_TRACE_NVME, "ns %u optimal IO boundary %" PRIu32 " blocks\n",
ns->id, ns->sectors_per_stripe);
} else if (ns->ctrlr->quirks & NVME_INTEL_QUIRK_STRIPING &&
ns->ctrlr->cdata.vs[3] != 0) {
ns->sectors_per_stripe = (1ULL << ns->ctrlr->cdata.vs[3]) * ns->ctrlr->min_page_size /
ns->sector_size;
SPDK_TRACELOG(SPDK_TRACE_NVME, "ns %u stripe size quirk %" PRIu32 " blocks\n",
ns->id, ns->sectors_per_stripe);
} else {
ns->sectors_per_stripe = 0;
}
if (ns->ctrlr->cdata.oncs.dsm) {
ns->flags |= SPDK_NVME_NS_DEALLOCATE_SUPPORTED;
@ -198,6 +210,12 @@ 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)
{
return ns->sectors_per_stripe;
}
int nvme_ns_construct(struct spdk_nvme_ns *ns, uint16_t id,
struct spdk_nvme_ctrlr *ctrlr)
{
@ -205,12 +223,6 @@ int nvme_ns_construct(struct spdk_nvme_ns *ns, uint16_t id,
ns->ctrlr = ctrlr;
ns->id = id;
ns->stripe_size = 0;
if (ctrlr->quirks & NVME_INTEL_QUIRK_STRIPING &&
ctrlr->cdata.vs[3] != 0) {
ns->stripe_size = (1 << ctrlr->cdata.vs[3]) * ctrlr->min_page_size;
}
return nvme_ns_identify_update(ns);
}

View File

@ -39,6 +39,8 @@
#include "lib/test_env.c"
SPDK_LOG_REGISTER_TRACE_FLAG("nvme", SPDK_TRACE_NVME)
int
nvme_ctrlr_cmd_identify_namespace(struct spdk_nvme_ctrlr *ctrlr, uint16_t nsid, void *payload,
spdk_nvme_cmd_cb cb_fn, void *cb_arg)
@ -66,7 +68,6 @@ test_nvme_ns_construct(void)
nvme_ns_construct(&ns, id, &ctrlr);
CU_ASSERT(ns.id == 1);
CU_ASSERT(ns.stripe_size == 0);
}
int main(int argc, char **argv)

View File

@ -211,9 +211,8 @@ prepare_for_test(struct spdk_nvme_ns *ns, struct spdk_nvme_ctrlr *ctrlr,
ns->extended_lba_size += md_size;
}
ns->md_size = md_size;
ns->stripe_size = stripe_size;
ns->sectors_per_max_io = spdk_nvme_ns_get_max_io_xfer_size(ns) / ns->extended_lba_size;
ns->sectors_per_stripe = ns->stripe_size / ns->extended_lba_size;
ns->sectors_per_stripe = stripe_size / ns->extended_lba_size;
memset(qpair, 0, sizeof(*qpair));
qpair->req_buf = calloc(num_requests, sizeof(struct nvme_request));