Viewing: ext4-add-IGET_NO_CHECKS-flag.patch

From 1045c6433c50055c58c1bbdab10a1d447cdb00c2 Mon Sep 17 00:00:00 2001
From: Li Dongyang <dongyangli@ddn.com>
Date: Fri, 6 Sep 2024 21:20:24 +1000
Subject: [PATCH] LU-18195 osd-ldiskfs: use IGET_NO_CHECKS for objects under
 lost+found

With e2fsck older than v1.47.1-rc2-10-g849a9e6e1,
e2fsck could link ea inode under lost+found, and this
creates problems on kernels enforce ea_inode flag checks.

Check for lost+found fid and use NO_CHECKS flag
in the lfsck code path.

Add s_lpf_ino in sbi, and set it by find the lost+found
entry during ext4_fill_super().
In ext4_lookup, check if the parent is the lost+found dir.
Note lost+found won't be changed when target mounted as
lustre, so we only lookup once during mount and don't
monitor lost+found entry. Even if it's changed duing e2fsck
or mounted as ldiskfs, we could still detect at next mount.

Test-Parameters: trivial
Test-Parameters: fstype=ldiskfs serverdistro=el9.4 testlist=conf-sanity env=ONLY=61b
Change-Id: I95492fcc2f0ec4188dfb92b1dc1aa6055cab6ca8
Signed-off-by: Li Dongyang <dongyangli@ddn.com>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/56276
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Alex Zhuravlev <bzzz@whamcloud.com>
Reviewed-by: Li Xi <lixi@ddn.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
---
 fs/ext4/ext4.h  |  4 +++-
 fs/ext4/inode.c |  2 ++
 fs/ext4/namei.c |  5 ++++-
 fs/ext4/super.c | 10 ++++++++++
 4 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index c8c9c91b..9e9f7fb7 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1791,6 +1791,7 @@ struct ext4_sb_info {
 	int s_fc_debug_max_replay;
 #endif
 	struct ext4_fc_replay_state s_fc_replay_state;
+	unsigned long s_lpf_ino;
 };
 
 static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
@@ -3183,7 +3184,8 @@ typedef enum {
 	EXT4_IGET_SPECIAL =	0x0001, /* OK to iget a system inode */
 	EXT4_IGET_HANDLE = 	0x0002,	/* Inode # is from a handle */
 	EXT4_IGET_BAD =		0x0004, /* Allow to iget a bad inode */
-	EXT4_IGET_EA_INODE =	0x0008	/* Inode should contain an EA value */
+	EXT4_IGET_EA_INODE =	0x0008,	/* Inode should contain an EA value */
+	EXT4_IGET_NO_CHECKS =	0x0010	/* Allow iget without checking */
 } ext4_iget_flags;
 
 extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index ceb87e69..4a89961f 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4834,6 +4834,8 @@ static inline void ext4_inode_set_iversi
 static const char *check_igot_inode(struct inode *inode, ext4_iget_flags flags)

 {
+	if (flags & EXT4_IGET_NO_CHECKS)
+		return 0;
 	if (flags & EXT4_IGET_EA_INODE) {
 		if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) {
 			err_str = "missing EA_INODE flag";
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index bf051bf2..1c751504 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2147,6 +2147,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
 	struct inode *inode;
 	struct ext4_dir_entry_2 *de;
 	struct buffer_head *bh;
+	struct ext4_sb_info *sbi = EXT4_SB(dir->i_sb);
 
 	if (dentry->d_name.len > EXT4_NAME_LEN)
 		return ERR_PTR(-ENAMETOOLONG);
@@ -2167,7 +2168,9 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
 					 dentry);
 			return ERR_PTR(-EFSCORRUPTED);
 		}
-		inode = ext4_iget(dir->i_sb, ino, EXT4_IGET_NORMAL);
+		inode = ext4_iget(dir->i_sb, ino,
+				  dir->i_ino == sbi->s_lpf_ino ?
+				  EXT4_IGET_NO_CHECKS : EXT4_IGET_NORMAL);
 		if (inode == ERR_PTR(-ESTALE)) {
 			EXT4_ERROR_INODE(dir,
 					 "deleted inode referenced: %u",
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 568ecba5..1b35ed4f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -5722,6 +5722,9 @@ static int ext4_fill_super(struct super_block *sb, struct fs_context *fc)
 {
 	struct ext4_fs_context *ctx = fc->fs_private;
 	struct ext4_sb_info *sbi;
+	struct buffer_head *bh;
+	struct ext4_dir_entry_2 *de;
+	const struct qstr lpf = QSTR_INIT("lost+found", 10);
 	const char *descr;
 	int ret;
 
@@ -5742,6 +5745,13 @@ static int ext4_fill_super(struct super_block *sb, struct fs_context *fc)
 	if (ret < 0)
 		goto free_sbi;
 
+	bh = ext4_find_entry_locked(d_inode(sb->s_root), &lpf, &de, NULL, NULL);
+	if (!IS_ERR(bh) && bh) {
+		if (ext4_valid_inum(sb, le32_to_cpu(de->inode)))
+			sbi->s_lpf_ino = le32_to_cpu(de->inode);
+		brelse(bh);
+	}
+
 	if (sbi->s_journal) {
 		if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
 			descr = " journalled data mode";
-- 
2.45.2