Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,8 @@ Emulates NVMe ZNS SSDs with zone-based interface.
```bash
zns_max_active=0 # Max active zones (0 = unlimited)
zns_max_open=0 # Max open zones (0 = unlimited)
zns_num_wc=0 # Write caches, one per zone being written
# (0 = zns_max_open, or 3 when that is unlimited)
zns_zd_ext_size=0 # Zone-descriptor extension bytes (0 = none)
zns_num_conv_zones=0 # Leading conventional zones (0 = all sequential)
zns_zone_cap=0 # Usable bytes per zone (0 = the whole zone)
Expand Down
1 change: 1 addition & 0 deletions hw/femu/femu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1907,6 +1907,7 @@ static const Property femu_props[] = {
DEFINE_PROP_INT64("zns_status_lat", FemuCtrl, zns_params.zns_status_lat, 0),
DEFINE_PROP_UINT32("zns_max_active", FemuCtrl, zns_params.zns_max_active, 0),
DEFINE_PROP_UINT32("zns_max_open", FemuCtrl, zns_params.zns_max_open, 0),
DEFINE_PROP_UINT32("zns_num_wc", FemuCtrl, zns_params.zns_num_wc, 0),
DEFINE_PROP_UINT32("zns_zd_ext_size", FemuCtrl, zns_params.zns_zd_ext_size, 0),
DEFINE_PROP_UINT32("zns_num_conv_zones", FemuCtrl,
zns_params.zns_num_conv_zones, 0),
Expand Down
1 change: 1 addition & 0 deletions hw/femu/nvme.h
Original file line number Diff line number Diff line change
Expand Up @@ -1761,6 +1761,7 @@ typedef struct ZNSCtrlParams {
int64_t zns_status_lat;
uint32_t zns_max_active; /* max active zones (0 = unlimited) */
uint32_t zns_max_open; /* max open zones (0 = unlimited) */
uint32_t zns_num_wc; /* write caches (0 = zns_max_open, or 3 when unlimited) */
uint32_t zns_zd_ext_size; /* per-zone descriptor extension bytes (0 = none) */
uint32_t zns_num_conv_zones; /* leading conventional zones (0 = all sequential) */
uint64_t zns_zone_cap; /* usable bytes per zone; 0 = the whole zone */
Expand Down
28 changes: 18 additions & 10 deletions hw/femu/zns/zftl.c
Original file line number Diff line number Diff line change
Expand Up @@ -441,11 +441,22 @@ static uint64_t zns_wc_flush(struct zns_ssd* zns, int wcidx, int type,uint64_t s
while(i < zns->cache.write_cache[wcidx].used)
{
for(p = 0;p<zns->num_plane;p++){
/*
* A partial cache (evicted before its stripe filled) programs
* only the pages that hold data; the untouched planes and
* pages of the stripe stay free for the zone's later writes.
*/
if (i >= zns->cache.write_cache[wcidx].used) {
break;
}
/* new write */
ppa = get_new_page(zns, zone_idx);
ppa.g.pl = p;
for(j = 0; j < flash_type ;j++)
{
if (i >= zns->cache.write_cache[wcidx].used) {
break;
}
ppa.g.pg = get_blk(zns,&ppa)->page_wp;
get_blk(zns,&ppa)->page_wp++;
for(subpage = 0;subpage < ZNS_PAGE_SIZE/LOGICAL_PAGE_SIZE;subpage++)
Expand Down Expand Up @@ -503,19 +514,16 @@ static uint64_t zns_write(struct zns_ssd *zns, NvmeRequest *req)

if(wcidx==-1)
{
//need flush
wcidx = 0;
uint64_t t_used = zns->cache.write_cache[wcidx].used;
for(i = 1;i < zns->cache.num_wc;i++)
{
if(zns->cache.write_cache[i].used==0)
{
/* take an empty cache; failing that, evict the fullest one */
uint64_t t_used = 0;
wcidx = -1;
for (i = 0; i < zns->cache.num_wc; i++) {
if (zns->cache.write_cache[i].used == 0) {
t_used = 0;
wcidx = i; //free wc!
wcidx = i;
break;
}
if(zns->cache.write_cache[i].used > t_used)
{
if (wcidx < 0 || zns->cache.write_cache[i].used > t_used) {
t_used = zns->cache.write_cache[i].used;
wcidx = i;
}
Expand Down
15 changes: 14 additions & 1 deletion hw/femu/zns/zns.c
Original file line number Diff line number Diff line change
Expand Up @@ -1794,7 +1794,20 @@ static void zns_init_params(FemuCtrl *n, NvmeNamespace *ns)
/* one program covers every plane of a die; the flush walks the same set */
id_zns->program_unit = ZNS_PAGE_SIZE * id_zns->flash_type * id_zns->num_plane;
id_zns->stripe_unit = id_zns->program_unit*id_zns->num_ch*id_zns->num_lun;
id_zns->cache.num_wc = ZNS_DEFAULT_NUM_WRITE_CACHE;
/*
* One write cache stages the partial stripe of one zone, so a device
* needs as many as it lets the host keep open: an open-zone limit
* exists to bound exactly these per-zone buffers (Bjorling et al.,
* ATC'21). Fewer caches than concurrent writers makes every write
* evict another zone's cache and pay a synchronous flush.
*/
if (n->zns_params.zns_num_wc) {
id_zns->cache.num_wc = n->zns_params.zns_num_wc;
} else if (n->zns_params.zns_max_open) {
id_zns->cache.num_wc = n->zns_params.zns_max_open;
} else {
id_zns->cache.num_wc = ZNS_DEFAULT_NUM_WRITE_CACHE;
}
id_zns->cache.write_cache = g_malloc0(sizeof(struct zns_write_cache) * id_zns->cache.num_wc);
for(i =0; i < id_zns->cache.num_wc; i++)
{
Expand Down
Loading