Commit 46a9c526 authored by Damien Le Moal's avatar Damien Le Moal

zonefs: Simplify IO error handling

Simplify zonefs_check_zone_condition() by moving the code that changes
an inode access rights to the new function zonefs_inode_update_mode().
Furthermore, since on mount an inode wpoffset is always zero when
zonefs_check_zone_condition() is called during an inode initialization,
the "mount" boolean argument is not necessary for the readonly zone
case. This argument is thus removed.

zonefs_io_error_cb() is also modified to use the inode offline and
zone state flags instead of checking the device zone condition. The
multiple calls to zonefs_check_zone_condition() are reduced to the first
call on entry, which allows removing the "warn" argument.
zonefs_inode_update_mode() is also used to update an inode access rights
as zonefs_io_error_cb() modifies the inode flags depending on the volume
error handling mode (defined with a mount option). Since an inode mode
change differs for read-only zones between mount time and IO error time,
the flag ZONEFS_ZONE_INIT_MODE is used to differentiate both cases.
Signed-off-by: default avatarDamien Le Moal <damien.lemoal@opensource.wdc.com>
Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
parent 4008e2a0
...@@ -155,48 +155,31 @@ void zonefs_update_stats(struct inode *inode, loff_t new_isize) ...@@ -155,48 +155,31 @@ void zonefs_update_stats(struct inode *inode, loff_t new_isize)
* amount of readable data in the zone. * amount of readable data in the zone.
*/ */
static loff_t zonefs_check_zone_condition(struct inode *inode, static loff_t zonefs_check_zone_condition(struct inode *inode,
struct blk_zone *zone, bool warn, struct blk_zone *zone)
bool mount)
{ {
struct zonefs_inode_info *zi = ZONEFS_I(inode); struct zonefs_inode_info *zi = ZONEFS_I(inode);
switch (zone->cond) { switch (zone->cond) {
case BLK_ZONE_COND_OFFLINE: case BLK_ZONE_COND_OFFLINE:
/* zonefs_warn(inode->i_sb, "inode %lu: offline zone\n",
* Dead zone: make the inode immutable, disable all accesses inode->i_ino);
* and set the file size to 0 (zone wp set to zone start).
*/
if (warn)
zonefs_warn(inode->i_sb, "inode %lu: offline zone\n",
inode->i_ino);
inode->i_flags |= S_IMMUTABLE;
inode->i_mode &= ~0777;
zone->wp = zone->start;
zi->i_flags |= ZONEFS_ZONE_OFFLINE; zi->i_flags |= ZONEFS_ZONE_OFFLINE;
return 0; return 0;
case BLK_ZONE_COND_READONLY: case BLK_ZONE_COND_READONLY:
/* /*
* The write pointer of read-only zones is invalid. If such a * The write pointer of read-only zones is invalid, so we cannot
* zone is found during mount, the file size cannot be retrieved * determine the zone wpoffset (inode size). We thus keep the
* so we treat the zone as offline (mount == true case). * zone wpoffset as is, which leads to an empty file
* Otherwise, keep the file size as it was when last updated * (wpoffset == 0) on mount. For a runtime error, this keeps
* so that the user can recover data. In both cases, writes are * the inode size as it was when last updated so that the user
* always disabled for the zone. * can recover data.
*/ */
if (warn) zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n",
zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n", inode->i_ino);
inode->i_ino);
inode->i_flags |= S_IMMUTABLE;
if (mount) {
zone->cond = BLK_ZONE_COND_OFFLINE;
inode->i_mode &= ~0777;
zone->wp = zone->start;
zi->i_flags |= ZONEFS_ZONE_OFFLINE;
return 0;
}
zi->i_flags |= ZONEFS_ZONE_READONLY; zi->i_flags |= ZONEFS_ZONE_READONLY;
inode->i_mode &= ~0222; if (zi->i_ztype == ZONEFS_ZTYPE_CNV)
return i_size_read(inode); return zi->i_max_size;
return zi->i_wpoffset;
case BLK_ZONE_COND_FULL: case BLK_ZONE_COND_FULL:
/* The write pointer of full zones is invalid. */ /* The write pointer of full zones is invalid. */
return zi->i_max_size; return zi->i_max_size;
...@@ -207,6 +190,30 @@ static loff_t zonefs_check_zone_condition(struct inode *inode, ...@@ -207,6 +190,30 @@ static loff_t zonefs_check_zone_condition(struct inode *inode,
} }
} }
/*
* Check a zone condition and adjust its inode access permissions for
* offline and readonly zones.
*/
static void zonefs_inode_update_mode(struct inode *inode)
{
struct zonefs_inode_info *zi = ZONEFS_I(inode);
if (zi->i_flags & ZONEFS_ZONE_OFFLINE) {
/* Offline zones cannot be read nor written */
inode->i_flags |= S_IMMUTABLE;
inode->i_mode &= ~0777;
} else if (zi->i_flags & ZONEFS_ZONE_READONLY) {
/* Readonly zones cannot be written */
inode->i_flags |= S_IMMUTABLE;
if (zi->i_flags & ZONEFS_ZONE_INIT_MODE)
inode->i_mode &= ~0777;
else
inode->i_mode &= ~0222;
}
zi->i_flags &= ~ZONEFS_ZONE_INIT_MODE;
}
struct zonefs_ioerr_data { struct zonefs_ioerr_data {
struct inode *inode; struct inode *inode;
bool write; bool write;
...@@ -228,10 +235,9 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx, ...@@ -228,10 +235,9 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
* as there is no inconsistency between the inode size and the amount of * as there is no inconsistency between the inode size and the amount of
* data writen in the zone (data_size). * data writen in the zone (data_size).
*/ */
data_size = zonefs_check_zone_condition(inode, zone, true, false); data_size = zonefs_check_zone_condition(inode, zone);
isize = i_size_read(inode); isize = i_size_read(inode);
if (zone->cond != BLK_ZONE_COND_OFFLINE && if (!(zi->i_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)) &&
zone->cond != BLK_ZONE_COND_READONLY &&
!err->write && isize == data_size) !err->write && isize == data_size)
return 0; return 0;
...@@ -264,24 +270,22 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx, ...@@ -264,24 +270,22 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
* zone condition to read-only and offline respectively, as if the * zone condition to read-only and offline respectively, as if the
* condition was signaled by the hardware. * condition was signaled by the hardware.
*/ */
if (zone->cond == BLK_ZONE_COND_OFFLINE || if ((zi->i_flags & ZONEFS_ZONE_OFFLINE) ||
sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL) { (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL)) {
zonefs_warn(sb, "inode %lu: read/write access disabled\n", zonefs_warn(sb, "inode %lu: read/write access disabled\n",
inode->i_ino); inode->i_ino);
if (zone->cond != BLK_ZONE_COND_OFFLINE) { if (!(zi->i_flags & ZONEFS_ZONE_OFFLINE))
zone->cond = BLK_ZONE_COND_OFFLINE; zi->i_flags |= ZONEFS_ZONE_OFFLINE;
data_size = zonefs_check_zone_condition(inode, zone, zonefs_inode_update_mode(inode);
false, false); data_size = 0;
} } else if ((zi->i_flags & ZONEFS_ZONE_READONLY) ||
} else if (zone->cond == BLK_ZONE_COND_READONLY || (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO)) {
sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO) {
zonefs_warn(sb, "inode %lu: write access disabled\n", zonefs_warn(sb, "inode %lu: write access disabled\n",
inode->i_ino); inode->i_ino);
if (zone->cond != BLK_ZONE_COND_READONLY) { if (!(zi->i_flags & ZONEFS_ZONE_READONLY))
zone->cond = BLK_ZONE_COND_READONLY; zi->i_flags |= ZONEFS_ZONE_READONLY;
data_size = zonefs_check_zone_condition(inode, zone, zonefs_inode_update_mode(inode);
false, false); data_size = isize;
}
} else if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_RO && } else if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_RO &&
data_size > isize) { data_size > isize) {
/* Do not expose garbage data */ /* Do not expose garbage data */
...@@ -295,8 +299,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx, ...@@ -295,8 +299,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
* close of the zone when the inode file is closed. * close of the zone when the inode file is closed.
*/ */
if ((sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) && if ((sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) &&
(zone->cond == BLK_ZONE_COND_OFFLINE || (zi->i_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)))
zone->cond == BLK_ZONE_COND_READONLY))
zi->i_flags &= ~ZONEFS_ZONE_OPEN; zi->i_flags &= ~ZONEFS_ZONE_OPEN;
/* /*
...@@ -378,6 +381,7 @@ static struct inode *zonefs_alloc_inode(struct super_block *sb) ...@@ -378,6 +381,7 @@ static struct inode *zonefs_alloc_inode(struct super_block *sb)
inode_init_once(&zi->i_vnode); inode_init_once(&zi->i_vnode);
mutex_init(&zi->i_truncate_mutex); mutex_init(&zi->i_truncate_mutex);
zi->i_wpoffset = 0;
zi->i_wr_refcnt = 0; zi->i_wr_refcnt = 0;
zi->i_flags = 0; zi->i_flags = 0;
...@@ -594,7 +598,7 @@ static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone, ...@@ -594,7 +598,7 @@ static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
zi->i_max_size = min_t(loff_t, MAX_LFS_FILESIZE, zi->i_max_size = min_t(loff_t, MAX_LFS_FILESIZE,
zone->capacity << SECTOR_SHIFT); zone->capacity << SECTOR_SHIFT);
zi->i_wpoffset = zonefs_check_zone_condition(inode, zone, true, true); zi->i_wpoffset = zonefs_check_zone_condition(inode, zone);
inode->i_uid = sbi->s_uid; inode->i_uid = sbi->s_uid;
inode->i_gid = sbi->s_gid; inode->i_gid = sbi->s_gid;
...@@ -605,6 +609,10 @@ static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone, ...@@ -605,6 +609,10 @@ static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
inode->i_fop = &zonefs_file_operations; inode->i_fop = &zonefs_file_operations;
inode->i_mapping->a_ops = &zonefs_file_aops; inode->i_mapping->a_ops = &zonefs_file_aops;
/* Update the inode access rights depending on the zone condition */
zi->i_flags |= ZONEFS_ZONE_INIT_MODE;
zonefs_inode_update_mode(inode);
sb->s_maxbytes = max(zi->i_max_size, sb->s_maxbytes); sb->s_maxbytes = max(zi->i_max_size, sb->s_maxbytes);
sbi->s_blocks += zi->i_max_size >> sb->s_blocksize_bits; sbi->s_blocks += zi->i_max_size >> sb->s_blocksize_bits;
sbi->s_used_blocks += zi->i_wpoffset >> sb->s_blocksize_bits; sbi->s_used_blocks += zi->i_wpoffset >> sb->s_blocksize_bits;
......
...@@ -39,10 +39,11 @@ static inline enum zonefs_ztype zonefs_zone_type(struct blk_zone *zone) ...@@ -39,10 +39,11 @@ static inline enum zonefs_ztype zonefs_zone_type(struct blk_zone *zone)
return ZONEFS_ZTYPE_SEQ; return ZONEFS_ZTYPE_SEQ;
} }
#define ZONEFS_ZONE_OPEN (1U << 0) #define ZONEFS_ZONE_INIT_MODE (1U << 0)
#define ZONEFS_ZONE_ACTIVE (1U << 1) #define ZONEFS_ZONE_OPEN (1U << 1)
#define ZONEFS_ZONE_OFFLINE (1U << 2) #define ZONEFS_ZONE_ACTIVE (1U << 2)
#define ZONEFS_ZONE_READONLY (1U << 3) #define ZONEFS_ZONE_OFFLINE (1U << 3)
#define ZONEFS_ZONE_READONLY (1U << 4)
/* /*
* In-memory inode data. * In-memory inode data.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment