Skip to content

Commit 2c7062e

Browse files
committed
femu/zns: a zone taken out of service gives its resources back
The write-fault injector moves a zone to read only, and Offline moves it on from there. Neither released what the state the zone was leaving held, so an open and an active resource stayed counted for a zone that holds nothing: with a limit configured, that many faults exhaust the namespace for good, and the shutdown walk -- which finds the zone on no list -- ends on an assertion that the open count reached zero. A zone read-write window went the same way, cleared by the state change without being handed back.
1 parent 0b82aa5 commit 2c7062e

1 file changed

Lines changed: 34 additions & 0 deletions

File tree

hw/femu/zns/zns.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,30 @@ static void zns_zrwa_release(NvmeNamespace *ns, NvmeZone *zone)
934934
}
935935
}
936936

937+
/*
938+
* Give back whatever the state a zone is leaving was holding. The transitions a
939+
* host drives walk this ladder themselves on the way through; the two that take
940+
* a zone out of service do not reach a state that holds anything, so they have
941+
* to do it here. Call before the state changes: the ladder is chosen by the
942+
* state the zone is in now.
943+
*/
944+
static void zns_release_zone_resources(NvmeNamespace *ns, NvmeZone *zone)
945+
{
946+
switch (zns_get_zone_state(zone)) {
947+
case NVME_ZONE_STATE_EXPLICITLY_OPEN:
948+
case NVME_ZONE_STATE_IMPLICITLY_OPEN:
949+
zns_aor_dec_open(ns);
950+
/* fall through */
951+
case NVME_ZONE_STATE_CLOSED:
952+
zns_aor_dec_active(ns);
953+
break;
954+
default:
955+
break;
956+
}
957+
958+
zns_zrwa_release(ns, zone);
959+
}
960+
937961
static uint16_t zns_finish_zone(NvmeNamespace *ns, NvmeZone *zone,
938962
NvmeZoneState state, NvmeRequest *req)
939963
{
@@ -992,6 +1016,7 @@ static uint16_t zns_offline_zone(NvmeNamespace *ns, NvmeZone *zone,
9921016
{
9931017
switch (state) {
9941018
case NVME_ZONE_STATE_READ_ONLY:
1019+
zns_release_zone_resources(ns, zone);
9951020
zns_assign_zone_state(ns, zone, NVME_ZONE_STATE_OFFLINE);
9961021
zns_deallocate_zone(ns, zone);
9971022
/* fall through */
@@ -1296,6 +1321,15 @@ static uint16_t zns_nvme_rw(FemuCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
12961321

12971322
if (failed && zns_get_zone_state(failed) !=
12981323
NVME_ZONE_STATE_READ_ONLY) {
1324+
/*
1325+
* Read only is the end of the line for the zone, so the open
1326+
* and active resources it held have to go back. Left counted,
1327+
* they exhaust the namespace's budget for zones that can never
1328+
* be opened again, and the shutdown walk -- which finds the
1329+
* zone on no list -- ends on an assertion that the open count
1330+
* reached zero.
1331+
*/
1332+
zns_release_zone_resources(ns, failed);
12991333
zns_assign_zone_state(ns, failed, NVME_ZONE_STATE_READ_ONLY);
13001334
zns_record_changed_zone(ns, failed->d.zslba);
13011335
zns->err_write_injected++;

0 commit comments

Comments
 (0)