From: Damien Le Moal <damien.lemoal@opensource.wdc.com>
To: linux-fsdevel@vger.kernel.org
Cc: Johannes Thumshirn <johannes.thumshirn@wdc.com>,
Jorgen Hansen <Jorgen.Hansen@wdc.com>
Subject: [PATCH 3/7] zonefs: Simplify IO error handling
Date: Tue, 10 Jan 2023 22:08:26 +0900 [thread overview]
Message-ID: <20230110130830.246019-4-damien.lemoal@opensource.wdc.com> (raw)
In-Reply-To: <20230110130830.246019-1-damien.lemoal@opensource.wdc.com>
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: Damien Le Moal <damien.lemoal@opensource.wdc.com>
---
fs/zonefs/super.c | 110 ++++++++++++++++++++++++---------------------
fs/zonefs/zonefs.h | 9 ++--
2 files changed, 64 insertions(+), 55 deletions(-)
diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c
index e808276b8801..6307cc95be06 100644
--- a/fs/zonefs/super.c
+++ b/fs/zonefs/super.c
@@ -155,48 +155,31 @@ void zonefs_update_stats(struct inode *inode, loff_t new_isize)
* amount of readable data in the zone.
*/
static loff_t zonefs_check_zone_condition(struct inode *inode,
- struct blk_zone *zone, bool warn,
- bool mount)
+ struct blk_zone *zone)
{
struct zonefs_inode_info *zi = ZONEFS_I(inode);
switch (zone->cond) {
case BLK_ZONE_COND_OFFLINE:
- /*
- * Dead zone: make the inode immutable, disable all accesses
- * 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;
+ zonefs_warn(inode->i_sb, "inode %lu: offline zone\n",
+ inode->i_ino);
zi->i_flags |= ZONEFS_ZONE_OFFLINE;
return 0;
case BLK_ZONE_COND_READONLY:
/*
- * The write pointer of read-only zones is invalid. If such a
- * zone is found during mount, the file size cannot be retrieved
- * so we treat the zone as offline (mount == true case).
- * Otherwise, keep the file size as it was when last updated
- * so that the user can recover data. In both cases, writes are
- * always disabled for the zone.
+ * The write pointer of read-only zones is invalid, so we cannot
+ * determine the zone wpoffset (inode size). We thus keep the
+ * zone wpoffset as is, which leads to an empty file
+ * (wpoffset == 0) on mount. For a runtime error, this keeps
+ * the inode size as it was when last updated so that the user
+ * can recover data.
*/
- if (warn)
- zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n",
- 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;
- }
+ zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n",
+ inode->i_ino);
zi->i_flags |= ZONEFS_ZONE_READONLY;
- inode->i_mode &= ~0222;
- return i_size_read(inode);
+ if (zi->i_ztype == ZONEFS_ZTYPE_CNV)
+ return zi->i_max_size;
+ return zi->i_wpoffset;
case BLK_ZONE_COND_FULL:
/* The write pointer of full zones is invalid. */
return zi->i_max_size;
@@ -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 inode *inode;
bool write;
@@ -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
* 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);
- if (zone->cond != BLK_ZONE_COND_OFFLINE &&
- zone->cond != BLK_ZONE_COND_READONLY &&
+ if (!(zi->i_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)) &&
!err->write && isize == data_size)
return 0;
@@ -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
* condition was signaled by the hardware.
*/
- if (zone->cond == BLK_ZONE_COND_OFFLINE ||
- sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL) {
+ if ((zi->i_flags & ZONEFS_ZONE_OFFLINE) ||
+ (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL)) {
zonefs_warn(sb, "inode %lu: read/write access disabled\n",
inode->i_ino);
- if (zone->cond != BLK_ZONE_COND_OFFLINE) {
- zone->cond = BLK_ZONE_COND_OFFLINE;
- data_size = zonefs_check_zone_condition(inode, zone,
- false, false);
- }
- } else if (zone->cond == BLK_ZONE_COND_READONLY ||
- sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO) {
+ if (!(zi->i_flags & ZONEFS_ZONE_OFFLINE))
+ zi->i_flags |= ZONEFS_ZONE_OFFLINE;
+ zonefs_inode_update_mode(inode);
+ data_size = 0;
+ } else if ((zi->i_flags & ZONEFS_ZONE_READONLY) ||
+ (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO)) {
zonefs_warn(sb, "inode %lu: write access disabled\n",
inode->i_ino);
- if (zone->cond != BLK_ZONE_COND_READONLY) {
- zone->cond = BLK_ZONE_COND_READONLY;
- data_size = zonefs_check_zone_condition(inode, zone,
- false, false);
- }
+ if (!(zi->i_flags & ZONEFS_ZONE_READONLY))
+ zi->i_flags |= ZONEFS_ZONE_READONLY;
+ zonefs_inode_update_mode(inode);
+ data_size = isize;
} else if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_RO &&
data_size > isize) {
/* Do not expose garbage data */
@@ -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.
*/
if ((sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) &&
- (zone->cond == BLK_ZONE_COND_OFFLINE ||
- zone->cond == BLK_ZONE_COND_READONLY))
+ (zi->i_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)))
zi->i_flags &= ~ZONEFS_ZONE_OPEN;
/*
@@ -378,6 +381,7 @@ static struct inode *zonefs_alloc_inode(struct super_block *sb)
inode_init_once(&zi->i_vnode);
mutex_init(&zi->i_truncate_mutex);
+ zi->i_wpoffset = 0;
zi->i_wr_refcnt = 0;
zi->i_flags = 0;
@@ -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,
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_gid = sbi->s_gid;
@@ -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_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);
sbi->s_blocks += zi->i_max_size >> sb->s_blocksize_bits;
sbi->s_used_blocks += zi->i_wpoffset >> sb->s_blocksize_bits;
diff --git a/fs/zonefs/zonefs.h b/fs/zonefs/zonefs.h
index 839ebe9afb6c..439096445ee5 100644
--- a/fs/zonefs/zonefs.h
+++ b/fs/zonefs/zonefs.h
@@ -39,10 +39,11 @@ static inline enum zonefs_ztype zonefs_zone_type(struct blk_zone *zone)
return ZONEFS_ZTYPE_SEQ;
}
-#define ZONEFS_ZONE_OPEN (1U << 0)
-#define ZONEFS_ZONE_ACTIVE (1U << 1)
-#define ZONEFS_ZONE_OFFLINE (1U << 2)
-#define ZONEFS_ZONE_READONLY (1U << 3)
+#define ZONEFS_ZONE_INIT_MODE (1U << 0)
+#define ZONEFS_ZONE_OPEN (1U << 1)
+#define ZONEFS_ZONE_ACTIVE (1U << 2)
+#define ZONEFS_ZONE_OFFLINE (1U << 3)
+#define ZONEFS_ZONE_READONLY (1U << 4)
/*
* In-memory inode data.
--
2.39.0
next prev parent reply other threads:[~2023-01-10 13:08 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-01-10 13:08 [PATCH 0/7] Reduce zonefs memory usage Damien Le Moal
2023-01-10 13:08 ` [PATCH 1/7] zonefs: Detect append writes at invalid locations Damien Le Moal
2023-01-11 12:23 ` Johannes Thumshirn
2023-01-11 22:08 ` Damien Le Moal
2023-01-12 5:18 ` Damien Le Moal
2023-01-12 7:33 ` Johannes Thumshirn
2023-01-12 8:26 ` Damien Le Moal
2023-01-10 13:08 ` [PATCH 2/7] zonefs: Reorganize code Damien Le Moal
2023-01-11 16:12 ` Johannes Thumshirn
2023-01-10 13:08 ` Damien Le Moal [this message]
2023-01-13 10:09 ` [PATCH 3/7] zonefs: Simplify IO error handling Johannes Thumshirn
2023-01-10 13:08 ` [PATCH 4/7] zonefs: Reduce struct zonefs_inode_info size Damien Le Moal
2023-01-13 10:11 ` Johannes Thumshirn
2023-01-10 13:08 ` [PATCH 5/7] zonefs: Separate zone information from inode information Damien Le Moal
2023-01-13 11:30 ` Johannes Thumshirn
2023-01-10 13:08 ` [PATCH 6/7] zonefs: Dynamically create file inodes when needed Damien Le Moal
2023-01-16 11:46 ` Johannes Thumshirn
2023-01-16 12:17 ` Damien Le Moal
2023-01-10 13:08 ` [PATCH 7/7] zonefs: Cache zone group directory inodes Damien Le Moal
2023-01-16 11:49 ` Johannes Thumshirn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230110130830.246019-4-damien.lemoal@opensource.wdc.com \
--to=damien.lemoal@opensource.wdc.com \
--cc=Jorgen.Hansen@wdc.com \
--cc=johannes.thumshirn@wdc.com \
--cc=linux-fsdevel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).