diff --git a/CHANGELOG.md b/CHANGELOG.md index d33664516..7c137a59f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index 683b74f78..adf46c669 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -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. */ diff --git a/lib/nvme/nvme_internal.h b/lib/nvme/nvme_internal.h index b68fafa07..0ced7b354 100644 --- a/lib/nvme/nvme_internal.h +++ b/lib/nvme/nvme_internal.h @@ -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; /* diff --git a/lib/nvme/nvme_ns.c b/lib/nvme/nvme_ns.c index dadd86525..3cd5d08ee 100644 --- a/lib/nvme/nvme_ns.c +++ b/lib/nvme/nvme_ns.c @@ -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); } diff --git a/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c b/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c index b91d70aa1..f816ce512 100644 --- a/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c +++ b/test/unit/lib/nvme/nvme_ns.c/nvme_ns_ut.c @@ -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) diff --git a/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c b/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c index f7aad6202..9485d37b8 100644 --- a/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c +++ b/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c @@ -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));