Skip to content

Commit 1da18a2

Browse files
author
Damien Le Moal
committed
zonefs: Fix management of open zones
The mount option "explicit_open" manages the device open zone resources to ensure that if an application opens a sequential file for writing, the file zone can always be written by explicitly opening the zone and accounting for that state with the s_open_zones counter. However, if some zones are already open when mounting, the device open zone resource usage status will be larger than the initial s_open_zones value of 0. Ensure that this inconsistency does not happen by closing any sequential zone that is open when mounting. Furthermore, with ZNS drives, closing an explicitly open zone that has not been written will change the zone state to "closed", that is, the zone will remain in an active state. Since this can then cause failures of explicit open operations on other zones if the drive active zone resources are exceeded, we need to make sure that the zone is not active anymore by resetting it instead of closing it. To address this, zonefs_zone_mgmt() is modified to change a REQ_OP_ZONE_CLOSE request into a REQ_OP_ZONE_RESET for sequential zones that have not been written. Fixes: b5c00e9 ("zonefs: open/close zone on file open/close") Cc: <[email protected]> Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Johannes Thumshirn <[email protected]> Reviewed-by: Hans Holmberg <[email protected]>
1 parent 694852e commit 1da18a2

File tree

1 file changed

+40
-5
lines changed

1 file changed

+40
-5
lines changed

fs/zonefs/super.c

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ static inline int zonefs_zone_mgmt(struct inode *inode,
3535

3636
lockdep_assert_held(&zi->i_truncate_mutex);
3737

38+
/*
39+
* With ZNS drives, closing an explicitly open zone that has not been
40+
* written will change the zone state to "closed", that is, the zone
41+
* will remain active. Since this can then cause failure of explicit
42+
* open operation on other zones if the drive active zone resources
43+
* are exceeded, make sure that the zone does not remain active by
44+
* resetting it.
45+
*/
46+
if (op == REQ_OP_ZONE_CLOSE && !zi->i_wpoffset)
47+
op = REQ_OP_ZONE_RESET;
48+
3849
trace_zonefs_zone_mgmt(inode, op);
3950
ret = blkdev_zone_mgmt(inode->i_sb->s_bdev, op, zi->i_zsector,
4051
zi->i_zone_size >> SECTOR_SHIFT, GFP_NOFS);
@@ -1294,12 +1305,13 @@ static void zonefs_init_dir_inode(struct inode *parent, struct inode *inode,
12941305
inc_nlink(parent);
12951306
}
12961307

1297-
static void zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
1298-
enum zonefs_ztype type)
1308+
static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
1309+
enum zonefs_ztype type)
12991310
{
13001311
struct super_block *sb = inode->i_sb;
13011312
struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
13021313
struct zonefs_inode_info *zi = ZONEFS_I(inode);
1314+
int ret = 0;
13031315

13041316
inode->i_ino = zone->start >> sbi->s_zone_sectors_shift;
13051317
inode->i_mode = S_IFREG | sbi->s_perm;
@@ -1324,6 +1336,22 @@ static void zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
13241336
sb->s_maxbytes = max(zi->i_max_size, sb->s_maxbytes);
13251337
sbi->s_blocks += zi->i_max_size >> sb->s_blocksize_bits;
13261338
sbi->s_used_blocks += zi->i_wpoffset >> sb->s_blocksize_bits;
1339+
1340+
/*
1341+
* For sequential zones, make sure that any open zone is closed first
1342+
* to ensure that the initial number of open zones is 0, in sync with
1343+
* the open zone accounting done when the mount option
1344+
* ZONEFS_MNTOPT_EXPLICIT_OPEN is used.
1345+
*/
1346+
if (type == ZONEFS_ZTYPE_SEQ &&
1347+
(zone->cond == BLK_ZONE_COND_IMP_OPEN ||
1348+
zone->cond == BLK_ZONE_COND_EXP_OPEN)) {
1349+
mutex_lock(&zi->i_truncate_mutex);
1350+
ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_CLOSE);
1351+
mutex_unlock(&zi->i_truncate_mutex);
1352+
}
1353+
1354+
return ret;
13271355
}
13281356

13291357
static struct dentry *zonefs_create_inode(struct dentry *parent,
@@ -1333,6 +1361,7 @@ static struct dentry *zonefs_create_inode(struct dentry *parent,
13331361
struct inode *dir = d_inode(parent);
13341362
struct dentry *dentry;
13351363
struct inode *inode;
1364+
int ret;
13361365

13371366
dentry = d_alloc_name(parent, name);
13381367
if (!dentry)
@@ -1343,10 +1372,16 @@ static struct dentry *zonefs_create_inode(struct dentry *parent,
13431372
goto dput;
13441373

13451374
inode->i_ctime = inode->i_mtime = inode->i_atime = dir->i_ctime;
1346-
if (zone)
1347-
zonefs_init_file_inode(inode, zone, type);
1348-
else
1375+
if (zone) {
1376+
ret = zonefs_init_file_inode(inode, zone, type);
1377+
if (ret) {
1378+
iput(inode);
1379+
goto dput;
1380+
}
1381+
} else {
13491382
zonefs_init_dir_inode(dir, inode, type);
1383+
}
1384+
13501385
d_add(dentry, inode);
13511386
dir->i_size++;
13521387

0 commit comments

Comments
 (0)