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:
parent
6552b6dac2
commit
99f838a36a
@ -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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user