Skip to content

Commit 7dd12d6

Browse files
author
Damien Le Moal
committed
zonefs: fix zone report size in __zonefs_io_error()
When an IO error occurs, the function __zonefs_io_error() is used to issue a zone report to obtain the latest zone information from the device. This function gets a zone report for all zones used as storage for a file, which is always 1 zone except for files representing aggregated conventional zones. The number of zones of a zone report for a file is calculated in __zonefs_io_error() by doing a bit-shift of the inode i_zone_size field, which is equal to or larger than the device zone size. However, this calculation does not take into account that the last zone of a zoned device may be smaller than the zone size reported by bdev_zone_sectors() (which is used to set the bit shift size). As a result, if an error occurs for an IO targetting such last smaller zone, the zone report will ask for 0 zones, leading to an invalid zone report. Fix this by using the fact that all files require a 1 zone report, except if the inode i_zone_size field indicates a zone size larger than the device zone size. This exception case corresponds to a mount with aggregated conventional zones. A check for this exception is added to the file inode initialization during mount. If an invalid setup is detected, emit an error and fail the mount (check contributed by Johannes Thumshirn). Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
1 parent 094226a commit 7dd12d6

File tree

1 file changed

+27
-10
lines changed

1 file changed

+27
-10
lines changed

fs/zonefs/super.c

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -478,14 +478,22 @@ static void __zonefs_io_error(struct inode *inode, bool write)
478478
struct super_block *sb = inode->i_sb;
479479
struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
480480
unsigned int noio_flag;
481-
unsigned int nr_zones =
482-
zi->i_zone_size >> (sbi->s_zone_sectors_shift + SECTOR_SHIFT);
481+
unsigned int nr_zones = 1;
483482
struct zonefs_ioerr_data err = {
484483
.inode = inode,
485484
.write = write,
486485
};
487486
int ret;
488487

488+
/*
489+
* The only files that have more than one zone are conventional zone
490+
* files with aggregated conventional zones, for which the inode zone
491+
* size is always larger than the device zone size.
492+
*/
493+
if (zi->i_zone_size > bdev_zone_sectors(sb->s_bdev))
494+
nr_zones = zi->i_zone_size >>
495+
(sbi->s_zone_sectors_shift + SECTOR_SHIFT);
496+
489497
/*
490498
* Memory allocations in blkdev_report_zones() can trigger a memory
491499
* reclaim which may in turn cause a recursion into zonefs as well as
@@ -1407,6 +1415,14 @@ static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
14071415
zi->i_ztype = type;
14081416
zi->i_zsector = zone->start;
14091417
zi->i_zone_size = zone->len << SECTOR_SHIFT;
1418+
if (zi->i_zone_size > bdev_zone_sectors(sb->s_bdev) << SECTOR_SHIFT &&
1419+
!(sbi->s_features & ZONEFS_F_AGGRCNV)) {
1420+
zonefs_err(sb,
1421+
"zone size %llu doesn't match device's zone sectors %llu\n",
1422+
zi->i_zone_size,
1423+
bdev_zone_sectors(sb->s_bdev) << SECTOR_SHIFT);
1424+
return -EINVAL;
1425+
}
14101426

14111427
zi->i_max_size = min_t(loff_t, MAX_LFS_FILESIZE,
14121428
zone->capacity << SECTOR_SHIFT);
@@ -1456,11 +1472,11 @@ static struct dentry *zonefs_create_inode(struct dentry *parent,
14561472
struct inode *dir = d_inode(parent);
14571473
struct dentry *dentry;
14581474
struct inode *inode;
1459-
int ret;
1475+
int ret = -ENOMEM;
14601476

14611477
dentry = d_alloc_name(parent, name);
14621478
if (!dentry)
1463-
return NULL;
1479+
return ERR_PTR(ret);
14641480

14651481
inode = new_inode(parent->d_sb);
14661482
if (!inode)
@@ -1485,7 +1501,7 @@ static struct dentry *zonefs_create_inode(struct dentry *parent,
14851501
dput:
14861502
dput(dentry);
14871503

1488-
return NULL;
1504+
return ERR_PTR(ret);
14891505
}
14901506

14911507
struct zonefs_zone_data {
@@ -1505,7 +1521,7 @@ static int zonefs_create_zgroup(struct zonefs_zone_data *zd,
15051521
struct blk_zone *zone, *next, *end;
15061522
const char *zgroup_name;
15071523
char *file_name;
1508-
struct dentry *dir;
1524+
struct dentry *dir, *dent;
15091525
unsigned int n = 0;
15101526
int ret;
15111527

@@ -1523,8 +1539,8 @@ static int zonefs_create_zgroup(struct zonefs_zone_data *zd,
15231539
zgroup_name = "seq";
15241540

15251541
dir = zonefs_create_inode(sb->s_root, zgroup_name, NULL, type);
1526-
if (!dir) {
1527-
ret = -ENOMEM;
1542+
if (IS_ERR(dir)) {
1543+
ret = PTR_ERR(dir);
15281544
goto free;
15291545
}
15301546

@@ -1570,8 +1586,9 @@ static int zonefs_create_zgroup(struct zonefs_zone_data *zd,
15701586
* Use the file number within its group as file name.
15711587
*/
15721588
snprintf(file_name, ZONEFS_NAME_MAX - 1, "%u", n);
1573-
if (!zonefs_create_inode(dir, file_name, zone, type)) {
1574-
ret = -ENOMEM;
1589+
dent = zonefs_create_inode(dir, file_name, zone, type);
1590+
if (IS_ERR(dent)) {
1591+
ret = PTR_ERR(dent);
15751592
goto free;
15761593
}
15771594

0 commit comments

Comments
 (0)