[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v11 12/13] hw/block/nvme: Add injection of Offline/Read-Only zone
From: |
Dmitry Fomichev |
Subject: |
[PATCH v11 12/13] hw/block/nvme: Add injection of Offline/Read-Only zones |
Date: |
Wed, 9 Dec 2020 05:04:09 +0900 |
ZNS specification defines two zone conditions for the zones that no
longer can function properly, possibly because of flash wear or other
internal fault. It is useful to be able to "inject" a small number of
such zones for testing purposes.
This commit defines two optional device properties, "offline_zones"
and "rdonly_zones". Users can assign non-zero values to these variables
to specify the number of zones to be initialized as Offline or
Read-Only. The actual number of injected zones may be smaller than the
requested amount - Read-Only and Offline counts are expected to be much
smaller than the total number of zones on a drive.
Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
Reviewed-by: Niklas Cassel <Niklas.Cassel@wdc.com>
---
hw/block/nvme-ns.h | 2 ++
hw/block/nvme-ns.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h
index f8f3c28c36..1196865b7a 100644
--- a/hw/block/nvme-ns.h
+++ b/hw/block/nvme-ns.h
@@ -36,6 +36,8 @@ typedef struct NvmeNamespaceParams {
uint32_t max_active_zones;
uint32_t max_open_zones;
uint32_t zd_extension_size;
+ uint32_t nr_offline_zones;
+ uint32_t nr_rdonly_zones;
} NvmeNamespaceParams;
typedef struct NvmeNamespace {
diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c
index c5a7bafcf7..0a8b741bc9 100644
--- a/hw/block/nvme-ns.c
+++ b/hw/block/nvme-ns.c
@@ -21,6 +21,7 @@
#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
#include "qapi/error.h"
+#include "crypto/random.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-core.h"
@@ -163,6 +164,21 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace
*ns, Error **errp)
}
}
+ if (ns->params.max_open_zones < ns->num_zones) {
+ if (ns->params.nr_offline_zones >
+ ns->num_zones - ns->params.max_open_zones) {
+ error_setg(errp, "offline_zones value %u is too large",
+ ns->params.nr_offline_zones);
+ return -1;
+ }
+ if (ns->params.nr_rdonly_zones + ns->params.nr_offline_zones >
+ ns->num_zones - ns->params.max_open_zones) {
+ error_setg(errp, "rdonly_zones value %u is too large",
+ ns->params.nr_rdonly_zones);
+ return -1;
+ }
+ }
+
return 0;
}
@@ -171,7 +187,9 @@ static void nvme_ns_zoned_init_state(NvmeNamespace *ns)
uint64_t start = 0, zone_size = ns->zone_size;
uint64_t capacity = ns->num_zones * zone_size;
NvmeZone *zone;
+ uint32_t rnd;
int i;
+ uint16_t zs;
ns->zone_array = g_new0(NvmeZone, ns->num_zones);
if (ns->params.zd_extension_size) {
@@ -203,6 +221,37 @@ static void nvme_ns_zoned_init_state(NvmeNamespace *ns)
if (is_power_of_2(ns->zone_size)) {
ns->zone_size_log2 = 63 - clz64(ns->zone_size);
}
+
+ /* If required, make some zones Offline or Read Only */
+
+ for (i = 0; i < ns->params.nr_offline_zones; i++) {
+ do {
+ qcrypto_random_bytes(&rnd, sizeof(rnd), NULL);
+ rnd %= ns->num_zones;
+ } while (rnd < ns->params.max_open_zones);
+ zone = &ns->zone_array[rnd];
+ zs = nvme_get_zone_state(zone);
+ if (zs != NVME_ZONE_STATE_OFFLINE) {
+ nvme_set_zone_state(zone, NVME_ZONE_STATE_OFFLINE);
+ } else {
+ i--;
+ }
+ }
+
+ for (i = 0; i < ns->params.nr_rdonly_zones; i++) {
+ do {
+ qcrypto_random_bytes(&rnd, sizeof(rnd), NULL);
+ rnd %= ns->num_zones;
+ } while (rnd < ns->params.max_open_zones);
+ zone = &ns->zone_array[rnd];
+ zs = nvme_get_zone_state(zone);
+ if (zs != NVME_ZONE_STATE_OFFLINE &&
+ zs != NVME_ZONE_STATE_READ_ONLY) {
+ nvme_set_zone_state(zone, NVME_ZONE_STATE_READ_ONLY);
+ } else {
+ i--;
+ }
+ }
}
static void nvme_ns_init_zoned(NvmeCtrl *n, NvmeNamespace *ns, int lba_index)
@@ -368,6 +417,10 @@ static Property nvme_ns_props[] = {
params.max_open_zones, 0),
DEFINE_PROP_UINT32("zoned.descr_ext_size", NvmeNamespace,
params.zd_extension_size, 0),
+ DEFINE_PROP_UINT32("zoned.offline_zones", NvmeNamespace,
+ params.nr_offline_zones, 0),
+ DEFINE_PROP_UINT32("zoned.rdonly_zones", NvmeNamespace,
+ params.nr_rdonly_zones, 0),
DEFINE_PROP_END_OF_LIST(),
};
--
2.28.0
- [PATCH v11 03/13] hw/block/nvme: Separate read and write handlers, (continued)
- [PATCH v11 03/13] hw/block/nvme: Separate read and write handlers, Dmitry Fomichev, 2020/12/08
- [PATCH v11 05/13] hw/block/nvme: Add Commands Supported and Effects log, Dmitry Fomichev, 2020/12/08
- [PATCH v11 07/13] hw/block/nvme: Support allocated CNS command variants, Dmitry Fomichev, 2020/12/08
- [PATCH v11 08/13] block/nvme: Make ZNS-related definitions, Dmitry Fomichev, 2020/12/08
- [PATCH v11 09/13] hw/block/nvme: Support Zoned Namespace Command Set, Dmitry Fomichev, 2020/12/08
- [PATCH v11 06/13] hw/block/nvme: Add support for Namespace Types, Dmitry Fomichev, 2020/12/08
- [PATCH v11 10/13] hw/block/nvme: Introduce max active and open zone limits, Dmitry Fomichev, 2020/12/08
- [PATCH v11 11/13] hw/block/nvme: Support Zone Descriptor Extensions, Dmitry Fomichev, 2020/12/08
- [PATCH v11 12/13] hw/block/nvme: Add injection of Offline/Read-Only zones,
Dmitry Fomichev <=
- [PATCH v11 13/13] hw/block/nvme: Document zoned parameters in usage text, Dmitry Fomichev, 2020/12/08
- Re: [PATCH v11 00/13] hw/block/nvme: Support Namespace Types and Zoned Namespace Command Set, Klaus Jensen, 2020/12/09
- Re: [PATCH v11 00/13] hw/block/nvme: Support Namespace Types and Zoned Namespace Command Set, Keith Busch, 2020/12/15