From 998ec7b094d0fe62c9154ea4a2c7151ef625df87 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 13 Oct 2020 15:35:19 +0000 Subject: [PATCH] nvme/hello_world: for zoned namespaces, reset the zone before write If the namespace is a zoned namespace, reset the zone starting at LBA 0, before doing the "Hello world!" write to LBA 0. This is done to ensure that the write pointer for the first zone is at LBA 0. We need to do this since a regular write on a zoned namespace to an LBA that is not equal to the write pointer results in a Zone Invalid Write I/O error. Therefore, if we don't do a zone reset before doing the write, the write would fail if there already were data written to the first zone. (E.g. if the user ran the hello_world example twice.) Signed-off-by: Niklas Cassel Change-Id: I0ee972b4cc40bc5ebd476105d0b180a07cfe5a76 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4683 Tested-by: SPDK CI Jenkins Reviewed-by: Shuhei Matsumoto Reviewed-by: Jim Harris --- examples/nvme/hello_world/hello_world.c | 47 +++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/examples/nvme/hello_world/hello_world.c b/examples/nvme/hello_world/hello_world.c index 351fec99f..d11b3b1dc 100644 --- a/examples/nvme/hello_world/hello_world.c +++ b/examples/nvme/hello_world/hello_world.c @@ -35,6 +35,7 @@ #include "spdk/nvme.h" #include "spdk/vmd.h" +#include "spdk/nvme_zns.h" #include "spdk/env.h" struct ctrlr_entry { @@ -153,6 +154,43 @@ write_complete(void *arg, const struct spdk_nvme_cpl *completion) } } +static void +reset_zone_complete(void *arg, const struct spdk_nvme_cpl *completion) +{ + struct hello_world_sequence *sequence = arg; + + /* Assume the I/O was successful */ + sequence->is_completed = 1; + /* See if an error occurred. If so, display information + * about it, and set completion value so that I/O + * caller is aware that an error occurred. + */ + if (spdk_nvme_cpl_is_error(completion)) { + spdk_nvme_qpair_print_completion(sequence->ns_entry->qpair, (struct spdk_nvme_cpl *)completion); + fprintf(stderr, "I/O error status: %s\n", spdk_nvme_cpl_get_status_string(&completion->status)); + fprintf(stderr, "Reset zone I/O failed, aborting run\n"); + sequence->is_completed = 2; + exit(1); + } +} + +static void +reset_zone_and_wait_for_completion(struct hello_world_sequence *sequence) +{ + if (spdk_nvme_zns_reset_zone(sequence->ns_entry->ns, sequence->ns_entry->qpair, + 0, /* starting LBA of the zone to reset */ + false, /* don't reset all zones */ + reset_zone_complete, + sequence)) { + fprintf(stderr, "starting reset zone I/O failed\n"); + exit(1); + } + while (!sequence->is_completed) { + spdk_nvme_qpair_process_completions(sequence->ns_entry->qpair, 0); + } + sequence->is_completed = 0; +} + static void hello_world(void) { @@ -203,6 +241,15 @@ hello_world(void) sequence.is_completed = 0; sequence.ns_entry = ns_entry; + /* + * If the namespace is a Zoned Namespace, rather than a regular + * NVM namespace, we need to reset the first zone, before we + * write to it. This not needed for regular NVM namespaces. + */ + if (spdk_nvme_ns_get_csi(ns_entry->ns) == SPDK_NVME_CSI_ZNS) { + reset_zone_and_wait_for_completion(&sequence); + } + /* * Print "Hello world!" to sequence.buf. We will write this data to LBA * 0 on the namespace, and then later read it back into a separate buffer