|
Jiri Slaby |
ba7816 |
From: Damien Le Moal <damien.lemoal@opensource.wdc.com>
|
|
Jiri Slaby |
ba7816 |
Date: Fri, 25 Nov 2022 11:06:20 +0900
|
|
Jiri Slaby |
ba7816 |
Subject: [PATCH] zonefs: Simplify IO error handling
|
|
Jiri Slaby |
ba7816 |
References: bsc#1012628
|
|
Jiri Slaby |
ba7816 |
Patch-mainline: 6.2.10
|
|
Jiri Slaby |
ba7816 |
Git-commit: 46a9c526eef7fb68a00321e2a9591ce5276ae92b
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
[ Upstream commit 46a9c526eef7fb68a00321e2a9591ce5276ae92b ]
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
Simplify zonefs_check_zone_condition() by moving the code that changes
|
|
Jiri Slaby |
ba7816 |
an inode access rights to the new function zonefs_inode_update_mode().
|
|
Jiri Slaby |
ba7816 |
Furthermore, since on mount an inode wpoffset is always zero when
|
|
Jiri Slaby |
ba7816 |
zonefs_check_zone_condition() is called during an inode initialization,
|
|
Jiri Slaby |
ba7816 |
the "mount" boolean argument is not necessary for the readonly zone
|
|
Jiri Slaby |
ba7816 |
case. This argument is thus removed.
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
zonefs_io_error_cb() is also modified to use the inode offline and
|
|
Jiri Slaby |
ba7816 |
zone state flags instead of checking the device zone condition. The
|
|
Jiri Slaby |
ba7816 |
multiple calls to zonefs_check_zone_condition() are reduced to the first
|
|
Jiri Slaby |
ba7816 |
call on entry, which allows removing the "warn" argument.
|
|
Jiri Slaby |
ba7816 |
zonefs_inode_update_mode() is also used to update an inode access rights
|
|
Jiri Slaby |
ba7816 |
as zonefs_io_error_cb() modifies the inode flags depending on the volume
|
|
Jiri Slaby |
ba7816 |
error handling mode (defined with a mount option). Since an inode mode
|
|
Jiri Slaby |
ba7816 |
change differs for read-only zones between mount time and IO error time,
|
|
Jiri Slaby |
ba7816 |
the flag ZONEFS_ZONE_INIT_MODE is used to differentiate both cases.
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
|
|
Jiri Slaby |
ba7816 |
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
|
|
Jiri Slaby |
ba7816 |
Stable-dep-of: 88b170088ad2 ("zonefs: Fix error message in zonefs_file_dio_append()")
|
|
Jiri Slaby |
ba7816 |
Signed-off-by: Sasha Levin <sashal@kernel.org>
|
|
Jiri Slaby |
ba7816 |
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
|
|
Jiri Slaby |
ba7816 |
---
|
|
Jiri Slaby |
ba7816 |
fs/zonefs/super.c | 110 ++++++++++++++++++++++++---------------------
|
|
Jiri Slaby |
ba7816 |
fs/zonefs/zonefs.h | 9 ++--
|
|
Jiri Slaby |
ba7816 |
2 files changed, 64 insertions(+), 55 deletions(-)
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c
|
|
Jiri Slaby |
ba7816 |
index e808276b..6307cc95 100644
|
|
Jiri Slaby |
ba7816 |
--- a/fs/zonefs/super.c
|
|
Jiri Slaby |
ba7816 |
+++ b/fs/zonefs/super.c
|
|
Jiri Slaby |
ba7816 |
@@ -155,48 +155,31 @@ void zonefs_update_stats(struct inode *inode, loff_t new_isize)
|
|
Jiri Slaby |
ba7816 |
* amount of readable data in the zone.
|
|
Jiri Slaby |
ba7816 |
*/
|
|
Jiri Slaby |
ba7816 |
static loff_t zonefs_check_zone_condition(struct inode *inode,
|
|
Jiri Slaby |
ba7816 |
- struct blk_zone *zone, bool warn,
|
|
Jiri Slaby |
ba7816 |
- bool mount)
|
|
Jiri Slaby |
ba7816 |
+ struct blk_zone *zone)
|
|
Jiri Slaby |
ba7816 |
{
|
|
Jiri Slaby |
ba7816 |
struct zonefs_inode_info *zi = ZONEFS_I(inode);
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
switch (zone->cond) {
|
|
Jiri Slaby |
ba7816 |
case BLK_ZONE_COND_OFFLINE:
|
|
Jiri Slaby |
ba7816 |
- /*
|
|
Jiri Slaby |
ba7816 |
- * Dead zone: make the inode immutable, disable all accesses
|
|
Jiri Slaby |
ba7816 |
- * and set the file size to 0 (zone wp set to zone start).
|
|
Jiri Slaby |
ba7816 |
- */
|
|
Jiri Slaby |
ba7816 |
- if (warn)
|
|
Jiri Slaby |
ba7816 |
- zonefs_warn(inode->i_sb, "inode %lu: offline zone\n",
|
|
Jiri Slaby |
ba7816 |
- inode->i_ino);
|
|
Jiri Slaby |
ba7816 |
- inode->i_flags |= S_IMMUTABLE;
|
|
Jiri Slaby |
ba7816 |
- inode->i_mode &= ~0777;
|
|
Jiri Slaby |
ba7816 |
- zone->wp = zone->start;
|
|
Jiri Slaby |
ba7816 |
+ zonefs_warn(inode->i_sb, "inode %lu: offline zone\n",
|
|
Jiri Slaby |
ba7816 |
+ inode->i_ino);
|
|
Jiri Slaby |
ba7816 |
zi->i_flags |= ZONEFS_ZONE_OFFLINE;
|
|
Jiri Slaby |
ba7816 |
return 0;
|
|
Jiri Slaby |
ba7816 |
case BLK_ZONE_COND_READONLY:
|
|
Jiri Slaby |
ba7816 |
/*
|
|
Jiri Slaby |
ba7816 |
- * The write pointer of read-only zones is invalid. If such a
|
|
Jiri Slaby |
ba7816 |
- * zone is found during mount, the file size cannot be retrieved
|
|
Jiri Slaby |
ba7816 |
- * so we treat the zone as offline (mount == true case).
|
|
Jiri Slaby |
ba7816 |
- * Otherwise, keep the file size as it was when last updated
|
|
Jiri Slaby |
ba7816 |
- * so that the user can recover data. In both cases, writes are
|
|
Jiri Slaby |
ba7816 |
- * always disabled for the zone.
|
|
Jiri Slaby |
ba7816 |
+ * The write pointer of read-only zones is invalid, so we cannot
|
|
Jiri Slaby |
ba7816 |
+ * determine the zone wpoffset (inode size). We thus keep the
|
|
Jiri Slaby |
ba7816 |
+ * zone wpoffset as is, which leads to an empty file
|
|
Jiri Slaby |
ba7816 |
+ * (wpoffset == 0) on mount. For a runtime error, this keeps
|
|
Jiri Slaby |
ba7816 |
+ * the inode size as it was when last updated so that the user
|
|
Jiri Slaby |
ba7816 |
+ * can recover data.
|
|
Jiri Slaby |
ba7816 |
*/
|
|
Jiri Slaby |
ba7816 |
- if (warn)
|
|
Jiri Slaby |
ba7816 |
- zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n",
|
|
Jiri Slaby |
ba7816 |
- inode->i_ino);
|
|
Jiri Slaby |
ba7816 |
- inode->i_flags |= S_IMMUTABLE;
|
|
Jiri Slaby |
ba7816 |
- if (mount) {
|
|
Jiri Slaby |
ba7816 |
- zone->cond = BLK_ZONE_COND_OFFLINE;
|
|
Jiri Slaby |
ba7816 |
- inode->i_mode &= ~0777;
|
|
Jiri Slaby |
ba7816 |
- zone->wp = zone->start;
|
|
Jiri Slaby |
ba7816 |
- zi->i_flags |= ZONEFS_ZONE_OFFLINE;
|
|
Jiri Slaby |
ba7816 |
- return 0;
|
|
Jiri Slaby |
ba7816 |
- }
|
|
Jiri Slaby |
ba7816 |
+ zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n",
|
|
Jiri Slaby |
ba7816 |
+ inode->i_ino);
|
|
Jiri Slaby |
ba7816 |
zi->i_flags |= ZONEFS_ZONE_READONLY;
|
|
Jiri Slaby |
ba7816 |
- inode->i_mode &= ~0222;
|
|
Jiri Slaby |
ba7816 |
- return i_size_read(inode);
|
|
Jiri Slaby |
ba7816 |
+ if (zi->i_ztype == ZONEFS_ZTYPE_CNV)
|
|
Jiri Slaby |
ba7816 |
+ return zi->i_max_size;
|
|
Jiri Slaby |
ba7816 |
+ return zi->i_wpoffset;
|
|
Jiri Slaby |
ba7816 |
case BLK_ZONE_COND_FULL:
|
|
Jiri Slaby |
ba7816 |
/* The write pointer of full zones is invalid. */
|
|
Jiri Slaby |
ba7816 |
return zi->i_max_size;
|
|
Jiri Slaby |
ba7816 |
@@ -207,6 +190,30 @@ static loff_t zonefs_check_zone_condition(struct inode *inode,
|
|
Jiri Slaby |
ba7816 |
}
|
|
Jiri Slaby |
ba7816 |
}
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
+/*
|
|
Jiri Slaby |
ba7816 |
+ * Check a zone condition and adjust its inode access permissions for
|
|
Jiri Slaby |
ba7816 |
+ * offline and readonly zones.
|
|
Jiri Slaby |
ba7816 |
+ */
|
|
Jiri Slaby |
ba7816 |
+static void zonefs_inode_update_mode(struct inode *inode)
|
|
Jiri Slaby |
ba7816 |
+{
|
|
Jiri Slaby |
ba7816 |
+ struct zonefs_inode_info *zi = ZONEFS_I(inode);
|
|
Jiri Slaby |
ba7816 |
+
|
|
Jiri Slaby |
ba7816 |
+ if (zi->i_flags & ZONEFS_ZONE_OFFLINE) {
|
|
Jiri Slaby |
ba7816 |
+ /* Offline zones cannot be read nor written */
|
|
Jiri Slaby |
ba7816 |
+ inode->i_flags |= S_IMMUTABLE;
|
|
Jiri Slaby |
ba7816 |
+ inode->i_mode &= ~0777;
|
|
Jiri Slaby |
ba7816 |
+ } else if (zi->i_flags & ZONEFS_ZONE_READONLY) {
|
|
Jiri Slaby |
ba7816 |
+ /* Readonly zones cannot be written */
|
|
Jiri Slaby |
ba7816 |
+ inode->i_flags |= S_IMMUTABLE;
|
|
Jiri Slaby |
ba7816 |
+ if (zi->i_flags & ZONEFS_ZONE_INIT_MODE)
|
|
Jiri Slaby |
ba7816 |
+ inode->i_mode &= ~0777;
|
|
Jiri Slaby |
ba7816 |
+ else
|
|
Jiri Slaby |
ba7816 |
+ inode->i_mode &= ~0222;
|
|
Jiri Slaby |
ba7816 |
+ }
|
|
Jiri Slaby |
ba7816 |
+
|
|
Jiri Slaby |
ba7816 |
+ zi->i_flags &= ~ZONEFS_ZONE_INIT_MODE;
|
|
Jiri Slaby |
ba7816 |
+}
|
|
Jiri Slaby |
ba7816 |
+
|
|
Jiri Slaby |
ba7816 |
struct zonefs_ioerr_data {
|
|
Jiri Slaby |
ba7816 |
struct inode *inode;
|
|
Jiri Slaby |
ba7816 |
bool write;
|
|
Jiri Slaby |
ba7816 |
@@ -228,10 +235,9 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
|
|
Jiri Slaby |
ba7816 |
* as there is no inconsistency between the inode size and the amount of
|
|
Jiri Slaby |
ba7816 |
* data writen in the zone (data_size).
|
|
Jiri Slaby |
ba7816 |
*/
|
|
Jiri Slaby |
ba7816 |
- data_size = zonefs_check_zone_condition(inode, zone, true, false);
|
|
Jiri Slaby |
ba7816 |
+ data_size = zonefs_check_zone_condition(inode, zone);
|
|
Jiri Slaby |
ba7816 |
isize = i_size_read(inode);
|
|
Jiri Slaby |
ba7816 |
- if (zone->cond != BLK_ZONE_COND_OFFLINE &&
|
|
Jiri Slaby |
ba7816 |
- zone->cond != BLK_ZONE_COND_READONLY &&
|
|
Jiri Slaby |
ba7816 |
+ if (!(zi->i_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)) &&
|
|
Jiri Slaby |
ba7816 |
!err->write && isize == data_size)
|
|
Jiri Slaby |
ba7816 |
return 0;
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
@@ -264,24 +270,22 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
|
|
Jiri Slaby |
ba7816 |
* zone condition to read-only and offline respectively, as if the
|
|
Jiri Slaby |
ba7816 |
* condition was signaled by the hardware.
|
|
Jiri Slaby |
ba7816 |
*/
|
|
Jiri Slaby |
ba7816 |
- if (zone->cond == BLK_ZONE_COND_OFFLINE ||
|
|
Jiri Slaby |
ba7816 |
- sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL) {
|
|
Jiri Slaby |
ba7816 |
+ if ((zi->i_flags & ZONEFS_ZONE_OFFLINE) ||
|
|
Jiri Slaby |
ba7816 |
+ (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL)) {
|
|
Jiri Slaby |
ba7816 |
zonefs_warn(sb, "inode %lu: read/write access disabled\n",
|
|
Jiri Slaby |
ba7816 |
inode->i_ino);
|
|
Jiri Slaby |
ba7816 |
- if (zone->cond != BLK_ZONE_COND_OFFLINE) {
|
|
Jiri Slaby |
ba7816 |
- zone->cond = BLK_ZONE_COND_OFFLINE;
|
|
Jiri Slaby |
ba7816 |
- data_size = zonefs_check_zone_condition(inode, zone,
|
|
Jiri Slaby |
ba7816 |
- false, false);
|
|
Jiri Slaby |
ba7816 |
- }
|
|
Jiri Slaby |
ba7816 |
- } else if (zone->cond == BLK_ZONE_COND_READONLY ||
|
|
Jiri Slaby |
ba7816 |
- sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO) {
|
|
Jiri Slaby |
ba7816 |
+ if (!(zi->i_flags & ZONEFS_ZONE_OFFLINE))
|
|
Jiri Slaby |
ba7816 |
+ zi->i_flags |= ZONEFS_ZONE_OFFLINE;
|
|
Jiri Slaby |
ba7816 |
+ zonefs_inode_update_mode(inode);
|
|
Jiri Slaby |
ba7816 |
+ data_size = 0;
|
|
Jiri Slaby |
ba7816 |
+ } else if ((zi->i_flags & ZONEFS_ZONE_READONLY) ||
|
|
Jiri Slaby |
ba7816 |
+ (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO)) {
|
|
Jiri Slaby |
ba7816 |
zonefs_warn(sb, "inode %lu: write access disabled\n",
|
|
Jiri Slaby |
ba7816 |
inode->i_ino);
|
|
Jiri Slaby |
ba7816 |
- if (zone->cond != BLK_ZONE_COND_READONLY) {
|
|
Jiri Slaby |
ba7816 |
- zone->cond = BLK_ZONE_COND_READONLY;
|
|
Jiri Slaby |
ba7816 |
- data_size = zonefs_check_zone_condition(inode, zone,
|
|
Jiri Slaby |
ba7816 |
- false, false);
|
|
Jiri Slaby |
ba7816 |
- }
|
|
Jiri Slaby |
ba7816 |
+ if (!(zi->i_flags & ZONEFS_ZONE_READONLY))
|
|
Jiri Slaby |
ba7816 |
+ zi->i_flags |= ZONEFS_ZONE_READONLY;
|
|
Jiri Slaby |
ba7816 |
+ zonefs_inode_update_mode(inode);
|
|
Jiri Slaby |
ba7816 |
+ data_size = isize;
|
|
Jiri Slaby |
ba7816 |
} else if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_RO &&
|
|
Jiri Slaby |
ba7816 |
data_size > isize) {
|
|
Jiri Slaby |
ba7816 |
/* Do not expose garbage data */
|
|
Jiri Slaby |
ba7816 |
@@ -295,8 +299,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
|
|
Jiri Slaby |
ba7816 |
* close of the zone when the inode file is closed.
|
|
Jiri Slaby |
ba7816 |
*/
|
|
Jiri Slaby |
ba7816 |
if ((sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) &&
|
|
Jiri Slaby |
ba7816 |
- (zone->cond == BLK_ZONE_COND_OFFLINE ||
|
|
Jiri Slaby |
ba7816 |
- zone->cond == BLK_ZONE_COND_READONLY))
|
|
Jiri Slaby |
ba7816 |
+ (zi->i_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)))
|
|
Jiri Slaby |
ba7816 |
zi->i_flags &= ~ZONEFS_ZONE_OPEN;
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
/*
|
|
Jiri Slaby |
ba7816 |
@@ -378,6 +381,7 @@ static struct inode *zonefs_alloc_inode(struct super_block *sb)
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
inode_init_once(&zi->i_vnode);
|
|
Jiri Slaby |
ba7816 |
mutex_init(&zi->i_truncate_mutex);
|
|
Jiri Slaby |
ba7816 |
+ zi->i_wpoffset = 0;
|
|
Jiri Slaby |
ba7816 |
zi->i_wr_refcnt = 0;
|
|
Jiri Slaby |
ba7816 |
zi->i_flags = 0;
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
@@ -594,7 +598,7 @@ static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
zi->i_max_size = min_t(loff_t, MAX_LFS_FILESIZE,
|
|
Jiri Slaby |
ba7816 |
zone->capacity << SECTOR_SHIFT);
|
|
Jiri Slaby |
ba7816 |
- zi->i_wpoffset = zonefs_check_zone_condition(inode, zone, true, true);
|
|
Jiri Slaby |
ba7816 |
+ zi->i_wpoffset = zonefs_check_zone_condition(inode, zone);
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
inode->i_uid = sbi->s_uid;
|
|
Jiri Slaby |
ba7816 |
inode->i_gid = sbi->s_gid;
|
|
Jiri Slaby |
ba7816 |
@@ -605,6 +609,10 @@ static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
|
|
Jiri Slaby |
ba7816 |
inode->i_fop = &zonefs_file_operations;
|
|
Jiri Slaby |
ba7816 |
inode->i_mapping->a_ops = &zonefs_file_aops;
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
+ /* Update the inode access rights depending on the zone condition */
|
|
Jiri Slaby |
ba7816 |
+ zi->i_flags |= ZONEFS_ZONE_INIT_MODE;
|
|
Jiri Slaby |
ba7816 |
+ zonefs_inode_update_mode(inode);
|
|
Jiri Slaby |
ba7816 |
+
|
|
Jiri Slaby |
ba7816 |
sb->s_maxbytes = max(zi->i_max_size, sb->s_maxbytes);
|
|
Jiri Slaby |
ba7816 |
sbi->s_blocks += zi->i_max_size >> sb->s_blocksize_bits;
|
|
Jiri Slaby |
ba7816 |
sbi->s_used_blocks += zi->i_wpoffset >> sb->s_blocksize_bits;
|
|
Jiri Slaby |
ba7816 |
diff --git a/fs/zonefs/zonefs.h b/fs/zonefs/zonefs.h
|
|
Jiri Slaby |
ba7816 |
index 839ebe9a..43909644 100644
|
|
Jiri Slaby |
ba7816 |
--- a/fs/zonefs/zonefs.h
|
|
Jiri Slaby |
ba7816 |
+++ b/fs/zonefs/zonefs.h
|
|
Jiri Slaby |
ba7816 |
@@ -39,10 +39,11 @@ static inline enum zonefs_ztype zonefs_zone_type(struct blk_zone *zone)
|
|
Jiri Slaby |
ba7816 |
return ZONEFS_ZTYPE_SEQ;
|
|
Jiri Slaby |
ba7816 |
}
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
-#define ZONEFS_ZONE_OPEN (1U << 0)
|
|
Jiri Slaby |
ba7816 |
-#define ZONEFS_ZONE_ACTIVE (1U << 1)
|
|
Jiri Slaby |
ba7816 |
-#define ZONEFS_ZONE_OFFLINE (1U << 2)
|
|
Jiri Slaby |
ba7816 |
-#define ZONEFS_ZONE_READONLY (1U << 3)
|
|
Jiri Slaby |
ba7816 |
+#define ZONEFS_ZONE_INIT_MODE (1U << 0)
|
|
Jiri Slaby |
ba7816 |
+#define ZONEFS_ZONE_OPEN (1U << 1)
|
|
Jiri Slaby |
ba7816 |
+#define ZONEFS_ZONE_ACTIVE (1U << 2)
|
|
Jiri Slaby |
ba7816 |
+#define ZONEFS_ZONE_OFFLINE (1U << 3)
|
|
Jiri Slaby |
ba7816 |
+#define ZONEFS_ZONE_READONLY (1U << 4)
|
|
Jiri Slaby |
ba7816 |
|
|
Jiri Slaby |
ba7816 |
/*
|
|
Jiri Slaby |
ba7816 |
* In-memory inode data.
|
|
Jiri Slaby |
ba7816 |
--
|
|
Jiri Slaby |
ba7816 |
2.35.3
|
|
Jiri Slaby |
ba7816 |
|