[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 13/16] hw/block/nvme: track and enforce zone resources
From: |
Klaus Jensen |
Subject: |
[PATCH 13/16] hw/block/nvme: track and enforce zone resources |
Date: |
Thu, 24 Sep 2020 22:45:13 +0200 |
From: Klaus Jensen <k.jensen@samsung.com>
Track number of open/active resources.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
docs/specs/nvme.txt | 7 +++++
hw/block/nvme-ns.h | 7 +++++
include/block/nvme.h | 2 ++
hw/block/nvme-ns.c | 25 +++++++++++++++--
hw/block/nvme.c | 65 ++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 103 insertions(+), 3 deletions(-)
diff --git a/docs/specs/nvme.txt b/docs/specs/nvme.txt
index 82def65d4c78..921dbce2dc01 100644
--- a/docs/specs/nvme.txt
+++ b/docs/specs/nvme.txt
@@ -30,6 +30,13 @@ nvme-ns Options
zns.zcap; if the zone capacity is a power of two, the zone size will be
set to that, otherwise it will default to the next power of two.
+ `zns.mar`; Specifies the number of active resources available. This is a 0s
+ based value.
+
+ `zns.mor`; Specifies the number of open resources available. This is a 0s
+ based value.
+
+
Reference Specifications
------------------------
diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h
index 5a695334a052..f520ffa89c98 100644
--- a/hw/block/nvme-ns.h
+++ b/hw/block/nvme-ns.h
@@ -28,6 +28,8 @@ typedef struct NvmeNamespaceParams {
uint64_t zcap;
uint64_t zsze;
uint8_t zdes;
+ uint32_t mar;
+ uint32_t mor;
} zns;
} NvmeNamespaceParams;
@@ -71,6 +73,11 @@ typedef struct NvmeNamespace {
NvmeZone *zones;
NvmeZoneDescriptor *zd;
uint8_t *zde;
+
+ struct {
+ uint32_t open;
+ uint32_t active;
+ } resources;
} zns;
} NvmeNamespace;
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 5f8914f594f4..d51f397e7ff1 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -776,6 +776,8 @@ enum NvmeStatusCodes {
NVME_ZONE_IS_READ_ONLY = 0x01ba,
NVME_ZONE_IS_OFFLINE = 0x01bb,
NVME_ZONE_INVALID_WRITE = 0x01bc,
+ NVME_TOO_MANY_ACTIVE_ZONES = 0x01bd,
+ NVME_TOO_MANY_OPEN_ZONES = 0x01be,
NVME_INVALID_ZONE_STATE_TRANSITION = 0x01bf,
NVME_WRITE_FAULT = 0x0280,
NVME_UNRECOVERED_READ = 0x0281,
diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c
index 0fb196c7103e..588fe7a1f018 100644
--- a/hw/block/nvme-ns.c
+++ b/hw/block/nvme-ns.c
@@ -119,8 +119,13 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns)
id_ns->ncap = ns->zns.num_zones * ns->params.zns.zcap;
- id_ns_zns->mar = 0xffffffff;
- id_ns_zns->mor = 0xffffffff;
+ id_ns_zns->mar = cpu_to_le32(ns->params.zns.mar);
+ id_ns_zns->mor = cpu_to_le32(ns->params.zns.mor);
+
+ ns->zns.resources.active = ns->params.zns.mar != 0xffffffff ?
+ ns->params.zns.mar + 1 : ns->zns.num_zones;
+ ns->zns.resources.open = ns->params.zns.mor != 0xffffffff ?
+ ns->params.zns.mor + 1 : ns->zns.num_zones;
}
static void nvme_ns_init(NvmeNamespace *ns)
@@ -249,9 +254,15 @@ static int nvme_ns_setup_blk_pstate(NvmeNamespace *ns,
Error **errp)
if (nvme_wp(zone) == nvme_zslba(zone) &&
!(zone->zd->za & NVME_ZA_ZDEV)) {
nvme_zs_set(zone, NVME_ZS_ZSE);
+ continue;
}
- continue;
+ if (ns->zns.resources.active) {
+ ns->zns.resources.active--;
+ continue;
+ }
+
+ /* fallthrough */
case NVME_ZS_ZSIO:
case NVME_ZS_ZSEO:
@@ -333,6 +344,12 @@ static int nvme_ns_check_constraints(NvmeNamespace *ns,
Error **errp)
return -1;
}
+ if (ns->params.zns.mor > ns->params.zns.mar) {
+ error_setg(errp, "maximum open resources (zns.mor) must be less "
+ "than or equal to maximum active resources (zns.mar)");
+ return -1;
+ }
+
break;
default:
@@ -418,6 +435,8 @@ static Property nvme_ns_props[] = {
DEFINE_PROP_UINT64("zns.zcap", NvmeNamespace, params.zns.zcap, 0),
DEFINE_PROP_UINT64("zns.zsze", NvmeNamespace, params.zns.zsze, 0),
DEFINE_PROP_UINT8("zns.zdes", NvmeNamespace, params.zns.zdes, 0),
+ DEFINE_PROP_UINT32("zns.mar", NvmeNamespace, params.zns.mar, 0xffffffff),
+ DEFINE_PROP_UINT32("zns.mor", NvmeNamespace, params.zns.mor, 0xffffffff),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 294bc2fb719d..79732b8a8574 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -1204,6 +1204,40 @@ static uint16_t nvme_zrm_transition(NvmeNamespace *ns,
NvmeZone *zone,
switch (from) {
case NVME_ZS_ZSE:
+ switch (to) {
+ case NVME_ZS_ZSF:
+ case NVME_ZS_ZSRO:
+ case NVME_ZS_ZSO:
+ break;
+
+ case NVME_ZS_ZSC:
+ if (!ns->zns.resources.active) {
+ return NVME_TOO_MANY_ACTIVE_ZONES;
+ }
+
+ ns->zns.resources.active--;
+
+ break;
+
+ case NVME_ZS_ZSIO:
+ case NVME_ZS_ZSEO:
+ if (!ns->zns.resources.active) {
+ return NVME_TOO_MANY_ACTIVE_ZONES;
+ }
+
+ if (!ns->zns.resources.open) {
+ return NVME_TOO_MANY_OPEN_ZONES;
+ }
+
+ ns->zns.resources.active--;
+ ns->zns.resources.open--;
+
+ break;
+
+ default:
+ return NVME_INVALID_ZONE_STATE_TRANSITION | NVME_DNR;
+ }
+
break;
case NVME_ZS_ZSIO:
@@ -1224,7 +1258,13 @@ static uint16_t nvme_zrm_transition(NvmeNamespace *ns,
NvmeZone *zone,
case NVME_ZS_ZSF:
case NVME_ZS_ZSRO:
+ ns->zns.resources.active++;
+
+ /* fallthrough */
+
case NVME_ZS_ZSC:
+ ns->zns.resources.open++;
+
break;
default:
@@ -1247,8 +1287,18 @@ static uint16_t nvme_zrm_transition(NvmeNamespace *ns,
NvmeZone *zone,
case NVME_ZS_ZSF:
case NVME_ZS_ZSRO:
+ ns->zns.resources.active++;
+
+ break;
+
case NVME_ZS_ZSIO:
case NVME_ZS_ZSEO:
+ if (!ns->zns.resources.open) {
+ return NVME_TOO_MANY_OPEN_ZONES;
+ }
+
+ ns->zns.resources.open--;
+
break;
default:
@@ -1652,6 +1702,7 @@ static uint16_t nvme_zone_mgmt_send_all(NvmeCtrl *n,
NvmeRequest *req)
NvmeZoneManagementSendCmd *send = (NvmeZoneManagementSendCmd *) &req->cmd;
NvmeNamespace *ns = req->ns;
NvmeZone *zone;
+ int count;
uint16_t status = NVME_SUCCESS;
@@ -1701,6 +1752,20 @@ static uint16_t nvme_zone_mgmt_send_all(NvmeCtrl *n,
NvmeRequest *req)
break;
case NVME_CMD_ZONE_MGMT_SEND_OPEN:
+ count = 0;
+
+ for (int i = 0; i < ns->zns.num_zones; i++) {
+ zone = &ns->zns.zones[i];
+
+ if (nvme_zs(zone) == NVME_ZS_ZSC) {
+ count++;
+ }
+ }
+
+ if (count > ns->zns.resources.open) {
+ return NVME_TOO_MANY_OPEN_ZONES;
+ }
+
for (int i = 0; i < ns->zns.num_zones; i++) {
zone = &ns->zns.zones[i];
--
2.28.0
- [PATCH 04/16] hw/block/nvme: reject io commands if only admin command set selected, (continued)
- [PATCH 04/16] hw/block/nvme: reject io commands if only admin command set selected, Klaus Jensen, 2020/09/24
- [PATCH 07/16] hw/block/nvme: add commands supported and effects log page, Klaus Jensen, 2020/09/24
- [PATCH 03/16] hw/block/nvme: make lba data size configurable, Klaus Jensen, 2020/09/24
- [PATCH 06/16] hw/block/nvme: add support for dulbe and block utilization tracking, Klaus Jensen, 2020/09/24
- [PATCH 05/16] hw/block/nvme: consolidate read, write and write zeroes, Klaus Jensen, 2020/09/24
- [PATCH 08/16] hw/block/nvme: support namespace types, Klaus Jensen, 2020/09/24
- [PATCH 09/16] hw/block/nvme: add basic read/write for zoned namespaces, Klaus Jensen, 2020/09/24
- [PATCH 10/16] hw/block/nvme: add the zone management receive command, Klaus Jensen, 2020/09/24
- [PATCH 12/16] hw/block/nvme: add the zone append command, Klaus Jensen, 2020/09/24
- [PATCH 13/16] hw/block/nvme: track and enforce zone resources,
Klaus Jensen <=
- [PATCH 15/16] hw/block/nvme: support zone active excursions, Klaus Jensen, 2020/09/24
- [PATCH 16/16] hw/block/nvme: support reset/finish recommended limits, Klaus Jensen, 2020/09/24
- [PATCH 11/16] hw/block/nvme: add the zone management send command, Klaus Jensen, 2020/09/24
- [PATCH 14/16] hw/block/nvme: allow open to close transitions by controller, Klaus Jensen, 2020/09/24
- Re: [PATCH 00/16] hw/block/nvme: zoned namespace command set, no-reply, 2020/09/24
- Re: [PATCH 00/16] hw/block/nvme: zoned namespace command set, Keith Busch, 2020/09/24
- RE: [PATCH 00/16] hw/block/nvme: zoned namespace command set, Dmitry Fomichev, 2020/09/25