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 <niklas.cassel@wdc.com>
Change-Id: I0ee972b4cc40bc5ebd476105d0b180a07cfe5a76
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4683
Tested-by: SPDK CI Jenkins <sys_sgci@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:
Niklas Cassel 2020-10-13 15:35:19 +00:00 committed by Tomasz Zawadzki
parent 67475a58f4
commit 998ec7b094

View File

@ -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