Skip to content

Commit fcfa0d5

Browse files
committed
femu/zns: bound the write cache count by the zones there are
The count comes straight from a property and sizes an allocation, so a large value failed it and aborted QEMU at realize. It is bounded twice: before the allocation by the most zones the geometry could have, and once the zones exist by their actual count, since a cache past that is never used. Only an explicit count is held to the second bound; the default of three predates the property, and a device with fewer zones has always come up with it.
1 parent 2ae58aa commit fcfa0d5

1 file changed

Lines changed: 23 additions & 0 deletions

File tree

hw/femu/zns/zns.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,17 @@ static int zns_init_zone_geometry(NvmeNamespace *ns, Error **errp)
8282
}
8383
}
8484

85+
/*
86+
* A write cache serves one zone, so a count the user asks for above the
87+
* zone count names caches that can never be used. Only an explicit count
88+
* is held to this: the default of three predates the property, and a
89+
* device with fewer zones than that has always come up with it.
90+
*/
91+
if (ns->ctrl->zns_params.zns_num_wc > ns->num_zones) {
92+
error_setg(errp, "zns_num_wc value %u exceeds the number of zones %u",
93+
ns->ctrl->zns_params.zns_num_wc, ns->num_zones);
94+
return -1;
95+
}
8596
if (ns->max_open_zones > ns->num_zones) {
8697
error_setg(errp, "max_open_zones value %u exceeds the number of zones %u",
8798
ns->max_open_zones, ns->num_zones);
@@ -1990,6 +2001,18 @@ static bool zns_check_params(FemuCtrl *n, NvmeNamespace *ns, Error **errp)
19902001
error_setg(errp, "zns_flash_type must be in [%d, %d]", SLC, PLC);
19912002
return false;
19922003
}
2004+
/*
2005+
* The caches are allocated before the zone count is known, so bound the
2006+
* count here by the most zones this geometry could have; the exact bound
2007+
* is applied once the zones exist. Unbounded, a large value failed the
2008+
* allocation and aborted.
2009+
*/
2010+
if (p->zns_num_wc > (uint64_t)p->zns_num_ch * p->zns_num_blk) {
2011+
error_setg(errp, "zns_num_wc (%u) exceeds the %u zones this geometry "
2012+
"can have at most", p->zns_num_wc,
2013+
(unsigned)(p->zns_num_ch * p->zns_num_blk));
2014+
return false;
2015+
}
19932016
if (p->zns_pg_rd_lat < 0 || p->zns_pg_wr_lat < 0 || p->zns_blk_er_lat < 0 ||
19942017
p->zns_cmd_addr_lat < 0 || p->zns_pg_xfer_lat < 0 ||
19952018
p->zns_status_lat < 0 || p->zns_tsusp_ns < 0) {

0 commit comments

Comments
 (0)