--- /dev/null
+From 6213f5d4d23c50d393a31dc8e351e63a1fd10dbe Mon Sep 17 00:00:00 2001
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Thu, 5 May 2022 17:40:25 -0700
+Subject: f2fs: don't need inode lock for system hidden quota
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit 6213f5d4d23c50d393a31dc8e351e63a1fd10dbe upstream.
+
+Let's avoid false-alarmed lockdep warning.
+
+[ 58.914674] [T1501146] -> #2 (&sb->s_type->i_mutex_key#20){+.+.}-{3:3}:
+[ 58.915975] [T1501146] system_server: down_write+0x7c/0xe0
+[ 58.916738] [T1501146] system_server: f2fs_quota_sync+0x60/0x1a8
+[ 58.917563] [T1501146] system_server: block_operations+0x16c/0x43c
+[ 58.918410] [T1501146] system_server: f2fs_write_checkpoint+0x114/0x318
+[ 58.919312] [T1501146] system_server: f2fs_issue_checkpoint+0x178/0x21c
+[ 58.920214] [T1501146] system_server: f2fs_sync_fs+0x48/0x6c
+[ 58.920999] [T1501146] system_server: f2fs_do_sync_file+0x334/0x738
+[ 58.921862] [T1501146] system_server: f2fs_sync_file+0x30/0x48
+[ 58.922667] [T1501146] system_server: __arm64_sys_fsync+0x84/0xf8
+[ 58.923506] [T1501146] system_server: el0_svc_common.llvm.12821150825140585682+0xd8/0x20c
+[ 58.924604] [T1501146] system_server: do_el0_svc+0x28/0xa0
+[ 58.925366] [T1501146] system_server: el0_svc+0x24/0x38
+[ 58.926094] [T1501146] system_server: el0_sync_handler+0x88/0xec
+[ 58.926920] [T1501146] system_server: el0_sync+0x1b4/0x1c0
+
+[ 58.927681] [T1501146] -> #1 (&sbi->cp_global_sem){+.+.}-{3:3}:
+[ 58.928889] [T1501146] system_server: down_write+0x7c/0xe0
+[ 58.929650] [T1501146] system_server: f2fs_write_checkpoint+0xbc/0x318
+[ 58.930541] [T1501146] system_server: f2fs_issue_checkpoint+0x178/0x21c
+[ 58.931443] [T1501146] system_server: f2fs_sync_fs+0x48/0x6c
+[ 58.932226] [T1501146] system_server: sync_filesystem+0xac/0x130
+[ 58.933053] [T1501146] system_server: generic_shutdown_super+0x38/0x150
+[ 58.933958] [T1501146] system_server: kill_block_super+0x24/0x58
+[ 58.934791] [T1501146] system_server: kill_f2fs_super+0xcc/0x124
+[ 58.935618] [T1501146] system_server: deactivate_locked_super+0x90/0x120
+[ 58.936529] [T1501146] system_server: deactivate_super+0x74/0xac
+[ 58.937356] [T1501146] system_server: cleanup_mnt+0x128/0x168
+[ 58.938150] [T1501146] system_server: __cleanup_mnt+0x18/0x28
+[ 58.938944] [T1501146] system_server: task_work_run+0xb8/0x14c
+[ 58.939749] [T1501146] system_server: do_notify_resume+0x114/0x1e8
+[ 58.940595] [T1501146] system_server: work_pending+0xc/0x5f0
+
+[ 58.941375] [T1501146] -> #0 (&sbi->gc_lock){+.+.}-{3:3}:
+[ 58.942519] [T1501146] system_server: __lock_acquire+0x1270/0x2868
+[ 58.943366] [T1501146] system_server: lock_acquire+0x114/0x294
+[ 58.944169] [T1501146] system_server: down_write+0x7c/0xe0
+[ 58.944930] [T1501146] system_server: f2fs_issue_checkpoint+0x13c/0x21c
+[ 58.945831] [T1501146] system_server: f2fs_sync_fs+0x48/0x6c
+[ 58.946614] [T1501146] system_server: f2fs_do_sync_file+0x334/0x738
+[ 58.947472] [T1501146] system_server: f2fs_ioc_commit_atomic_write+0xc8/0x14c
+[ 58.948439] [T1501146] system_server: __f2fs_ioctl+0x674/0x154c
+[ 58.949253] [T1501146] system_server: f2fs_ioctl+0x54/0x88
+[ 58.950018] [T1501146] system_server: __arm64_sys_ioctl+0xa8/0x110
+[ 58.950865] [T1501146] system_server: el0_svc_common.llvm.12821150825140585682+0xd8/0x20c
+[ 58.951965] [T1501146] system_server: do_el0_svc+0x28/0xa0
+[ 58.952727] [T1501146] system_server: el0_svc+0x24/0x38
+[ 58.953454] [T1501146] system_server: el0_sync_handler+0x88/0xec
+[ 58.954279] [T1501146] system_server: el0_sync+0x1b4/0x1c0
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/super.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -2684,7 +2684,8 @@ int f2fs_quota_sync(struct super_block *
+ if (!sb_has_quota_active(sb, cnt))
+ continue;
+
+- inode_lock(dqopt->files[cnt]);
++ if (!f2fs_sb_has_quota_ino(sbi))
++ inode_lock(dqopt->files[cnt]);
+
+ /*
+ * do_quotactl
+@@ -2703,7 +2704,8 @@ int f2fs_quota_sync(struct super_block *
+ f2fs_up_read(&sbi->quota_sem);
+ f2fs_unlock_op(sbi);
+
+- inode_unlock(dqopt->files[cnt]);
++ if (!f2fs_sb_has_quota_ino(sbi))
++ inode_unlock(dqopt->files[cnt]);
+
+ if (ret)
+ break;
--- /dev/null
+From b5639bb4313b9d455fc9fc4768d23a5e4ca8cb9d Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Sat, 14 May 2022 10:59:29 -0700
+Subject: f2fs: don't use casefolded comparison for "." and ".."
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit b5639bb4313b9d455fc9fc4768d23a5e4ca8cb9d upstream.
+
+Tryng to rename a directory that has all following properties fails with
+EINVAL and triggers the 'WARN_ON_ONCE(!fscrypt_has_encryption_key(dir))'
+in f2fs_match_ci_name():
+
+ - The directory is casefolded
+ - The directory is encrypted
+ - The directory's encryption key is not yet set up
+ - The parent directory is *not* encrypted
+
+The problem is incorrect handling of the lookup of ".." to get the
+parent reference to update. fscrypt_setup_filename() treats ".." (and
+".") specially, as it's never encrypted. It's passed through as-is, and
+setting up the directory's key is not attempted. As the name isn't a
+no-key name, f2fs treats it as a "normal" name and attempts a casefolded
+comparison. That breaks the assumption of the WARN_ON_ONCE() in
+f2fs_match_ci_name() which assumes that for encrypted directories,
+casefolded comparisons only happen when the directory's key is set up.
+
+We could just remove this WARN_ON_ONCE(). However, since casefolding is
+always a no-op on "." and ".." anyway, let's instead just not casefold
+these names. This results in the standard bytewise comparison.
+
+Fixes: 7ad08a58bf67 ("f2fs: Handle casefolding with Encryption")
+Cc: <stable@vger.kernel.org> # v5.11+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Reviewed-by: Gabriel Krisman Bertazi <krisman@collabora.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/dir.c | 3 ++-
+ fs/f2fs/f2fs.h | 10 +++++-----
+ fs/f2fs/hash.c | 11 ++++++-----
+ 3 files changed, 13 insertions(+), 11 deletions(-)
+
+--- a/fs/f2fs/dir.c
++++ b/fs/f2fs/dir.c
+@@ -82,7 +82,8 @@ int f2fs_init_casefolded_name(const stru
+ #if IS_ENABLED(CONFIG_UNICODE)
+ struct super_block *sb = dir->i_sb;
+
+- if (IS_CASEFOLDED(dir)) {
++ if (IS_CASEFOLDED(dir) &&
++ !is_dot_dotdot(fname->usr_fname->name, fname->usr_fname->len)) {
+ fname->cf_name.name = f2fs_kmem_cache_alloc(f2fs_cf_name_slab,
+ GFP_NOFS, false, F2FS_SB(sb));
+ if (!fname->cf_name.name)
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -508,11 +508,11 @@ struct f2fs_filename {
+ #if IS_ENABLED(CONFIG_UNICODE)
+ /*
+ * For casefolded directories: the casefolded name, but it's left NULL
+- * if the original name is not valid Unicode, if the directory is both
+- * casefolded and encrypted and its encryption key is unavailable, or if
+- * the filesystem is doing an internal operation where usr_fname is also
+- * NULL. In all these cases we fall back to treating the name as an
+- * opaque byte sequence.
++ * if the original name is not valid Unicode, if the original name is
++ * "." or "..", if the directory is both casefolded and encrypted and
++ * its encryption key is unavailable, or if the filesystem is doing an
++ * internal operation where usr_fname is also NULL. In all these cases
++ * we fall back to treating the name as an opaque byte sequence.
+ */
+ struct fscrypt_str cf_name;
+ #endif
+--- a/fs/f2fs/hash.c
++++ b/fs/f2fs/hash.c
+@@ -91,7 +91,7 @@ static u32 TEA_hash_name(const u8 *p, si
+ /*
+ * Compute @fname->hash. For all directories, @fname->disk_name must be set.
+ * For casefolded directories, @fname->usr_fname must be set, and also
+- * @fname->cf_name if the filename is valid Unicode.
++ * @fname->cf_name if the filename is valid Unicode and is not "." or "..".
+ */
+ void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
+ {
+@@ -110,10 +110,11 @@ void f2fs_hash_filename(const struct ino
+ /*
+ * If the casefolded name is provided, hash it instead of the
+ * on-disk name. If the casefolded name is *not* provided, that
+- * should only be because the name wasn't valid Unicode, so fall
+- * back to treating the name as an opaque byte sequence. Note
+- * that to handle encrypted directories, the fallback must use
+- * usr_fname (plaintext) rather than disk_name (ciphertext).
++ * should only be because the name wasn't valid Unicode or was
++ * "." or "..", so fall back to treating the name as an opaque
++ * byte sequence. Note that to handle encrypted directories,
++ * the fallback must use usr_fname (plaintext) rather than
++ * disk_name (ciphertext).
+ */
+ WARN_ON_ONCE(!fname->usr_fname->name);
+ if (fname->cf_name.name) {
--- /dev/null
+From cfd66bb715fd11fde3338d0660cffa1396adc27d Mon Sep 17 00:00:00 2001
+From: Chao Yu <chao@kernel.org>
+Date: Wed, 4 May 2022 14:09:22 +0800
+Subject: f2fs: fix deadloop in foreground GC
+
+From: Chao Yu <chao@kernel.org>
+
+commit cfd66bb715fd11fde3338d0660cffa1396adc27d upstream.
+
+As Yanming reported in bugzilla:
+
+https://bugzilla.kernel.org/show_bug.cgi?id=215914
+
+The root cause is: in a very small sized image, it's very easy to
+exceed threshold of foreground GC, if we calculate free space and
+dirty data based on section granularity, in corner case,
+has_not_enough_free_secs() will always return true, result in
+deadloop in f2fs_gc().
+
+So this patch refactors has_not_enough_free_secs() as below to fix
+this issue:
+1. calculate needed space based on block granularity, and separate
+all blocks to two parts, section part, and block part, comparing
+section part to free section, and comparing block part to free space
+in openned log.
+2. account F2FS_DIRTY_NODES, F2FS_DIRTY_IMETA and F2FS_DIRTY_DENTS
+as node block consumer;
+3. account F2FS_DIRTY_DENTS as data block consumer;
+
+Cc: stable@vger.kernel.org
+Reported-by: Ming Yan <yanming@tju.edu.cn>
+Signed-off-by: Chao Yu <chao.yu@oppo.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/segment.h | 32 ++++++++++++++++++++------------
+ 1 file changed, 20 insertions(+), 12 deletions(-)
+
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -572,11 +572,10 @@ static inline int reserved_sections(stru
+ return GET_SEC_FROM_SEG(sbi, reserved_segments(sbi));
+ }
+
+-static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi)
++static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi,
++ unsigned int node_blocks, unsigned int dent_blocks)
+ {
+- unsigned int node_blocks = get_pages(sbi, F2FS_DIRTY_NODES) +
+- get_pages(sbi, F2FS_DIRTY_DENTS);
+- unsigned int dent_blocks = get_pages(sbi, F2FS_DIRTY_DENTS);
++
+ unsigned int segno, left_blocks;
+ int i;
+
+@@ -602,19 +601,28 @@ static inline bool has_curseg_enough_spa
+ static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi,
+ int freed, int needed)
+ {
+- int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
+- int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
+- int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
++ unsigned int total_node_blocks = get_pages(sbi, F2FS_DIRTY_NODES) +
++ get_pages(sbi, F2FS_DIRTY_DENTS) +
++ get_pages(sbi, F2FS_DIRTY_IMETA);
++ unsigned int total_dent_blocks = get_pages(sbi, F2FS_DIRTY_DENTS);
++ unsigned int node_secs = total_node_blocks / BLKS_PER_SEC(sbi);
++ unsigned int dent_secs = total_dent_blocks / BLKS_PER_SEC(sbi);
++ unsigned int node_blocks = total_node_blocks % BLKS_PER_SEC(sbi);
++ unsigned int dent_blocks = total_dent_blocks % BLKS_PER_SEC(sbi);
++ unsigned int free, need_lower, need_upper;
+
+ if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
+ return false;
+
+- if (free_sections(sbi) + freed == reserved_sections(sbi) + needed &&
+- has_curseg_enough_space(sbi))
++ free = free_sections(sbi) + freed;
++ need_lower = node_secs + dent_secs + reserved_sections(sbi) + needed;
++ need_upper = need_lower + (node_blocks ? 1 : 0) + (dent_blocks ? 1 : 0);
++
++ if (free > need_upper)
+ return false;
+- return (free_sections(sbi) + freed) <=
+- (node_secs + 2 * dent_secs + imeta_secs +
+- reserved_sections(sbi) + needed);
++ else if (free <= need_lower)
++ return true;
++ return !has_curseg_enough_space(sbi, node_blocks, dent_blocks);
+ }
+
+ static inline bool f2fs_is_checkpoint_ready(struct f2fs_sb_info *sbi)
--- /dev/null
+From 958ed92922028ec67f504dcdc72bfdfd0f43936a Mon Sep 17 00:00:00 2001
+From: Chao Yu <chao@kernel.org>
+Date: Tue, 17 May 2022 11:37:23 +0800
+Subject: f2fs: fix fallocate to use file_modified to update permissions consistently
+
+From: Chao Yu <chao@kernel.org>
+
+commit 958ed92922028ec67f504dcdc72bfdfd0f43936a upstream.
+
+This patch tries to fix permission consistency issue as all other
+mainline filesystems.
+
+Since the initial introduction of (posix) fallocate back at the turn of
+the century, it has been possible to use this syscall to change the
+user-visible contents of files. This can happen by extending the file
+size during a preallocation, or through any of the newer modes (punch,
+zero, collapse, insert range). Because the call can be used to change
+file contents, we should treat it like we do any other modification to a
+file -- update the mtime, and drop set[ug]id privileges/capabilities.
+
+The VFS function file_modified() does all this for us if pass it a
+locked inode, so let's make fallocate drop permissions correctly.
+
+Cc: stable@kernel.org
+Signed-off-by: Chao Yu <chao.yu@oppo.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/file.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/fs/f2fs/file.c
++++ b/fs/f2fs/file.c
+@@ -1774,6 +1774,10 @@ static long f2fs_fallocate(struct file *
+
+ inode_lock(inode);
+
++ ret = file_modified(file);
++ if (ret)
++ goto out;
++
+ if (mode & FALLOC_FL_PUNCH_HOLE) {
+ if (offset >= inode->i_size)
+ goto out;
--- /dev/null
+From f2db71053dc0409fae785096ad19cce4c8a95af7 Mon Sep 17 00:00:00 2001
+From: Chao Yu <chao@kernel.org>
+Date: Sat, 30 Apr 2022 21:19:24 +0800
+Subject: f2fs: fix to clear dirty inode in f2fs_evict_inode()
+
+From: Chao Yu <chao@kernel.org>
+
+commit f2db71053dc0409fae785096ad19cce4c8a95af7 upstream.
+
+As Yanming reported in bugzilla:
+
+https://bugzilla.kernel.org/show_bug.cgi?id=215904
+
+The kernel message is shown below:
+
+kernel BUG at fs/f2fs/inode.c:825!
+Call Trace:
+ evict+0x282/0x4e0
+ __dentry_kill+0x2b2/0x4d0
+ shrink_dentry_list+0x17c/0x4f0
+ shrink_dcache_parent+0x143/0x1e0
+ do_one_tree+0x9/0x30
+ shrink_dcache_for_umount+0x51/0x120
+ generic_shutdown_super+0x5c/0x3a0
+ kill_block_super+0x90/0xd0
+ kill_f2fs_super+0x225/0x310
+ deactivate_locked_super+0x78/0xc0
+ cleanup_mnt+0x2b7/0x480
+ task_work_run+0xc8/0x150
+ exit_to_user_mode_prepare+0x14a/0x150
+ syscall_exit_to_user_mode+0x1d/0x40
+ do_syscall_64+0x48/0x90
+
+The root cause is: inode node and dnode node share the same nid,
+so during f2fs_evict_inode(), dnode node truncation will invalidate
+its NAT entry, so when truncating inode node, it fails due to
+invalid NAT entry, result in inode is still marked as dirty, fix
+this issue by clearing dirty for inode and setting SBI_NEED_FSCK
+flag in filesystem.
+
+output from dump.f2fs:
+[print_node_info: 354] Node ID [0xf:15] is inode
+i_nid[0] [0x f : 15]
+
+Cc: stable@vger.kernel.org
+Reported-by: Ming Yan <yanming@tju.edu.cn>
+Signed-off-by: Chao Yu <chao.yu@oppo.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/inode.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -796,8 +796,22 @@ retry:
+ f2fs_lock_op(sbi);
+ err = f2fs_remove_inode_page(inode);
+ f2fs_unlock_op(sbi);
+- if (err == -ENOENT)
++ if (err == -ENOENT) {
+ err = 0;
++
++ /*
++ * in fuzzed image, another node may has the same
++ * block address as inode's, if it was truncated
++ * previously, truncation of inode node will fail.
++ */
++ if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
++ f2fs_warn(F2FS_I_SB(inode),
++ "f2fs_evict_inode: inconsistent node id, ino:%lu",
++ inode->i_ino);
++ f2fs_inode_synced(inode);
++ set_sbi_flag(sbi, SBI_NEED_FSCK);
++ }
++ }
+ }
+
+ /* give more chances, if ENOMEM case */
--- /dev/null
+From 677a82b44ebf263d4f9a0cfbd576a6ade797a07b Mon Sep 17 00:00:00 2001
+From: Chao Yu <chao@kernel.org>
+Date: Wed, 18 May 2022 20:28:41 +0800
+Subject: f2fs: fix to do sanity check for inline inode
+
+From: Chao Yu <chao@kernel.org>
+
+commit 677a82b44ebf263d4f9a0cfbd576a6ade797a07b upstream.
+
+Yanming reported a kernel bug in Bugzilla kernel [1], which can be
+reproduced. The bug message is:
+
+The kernel message is shown below:
+
+kernel BUG at fs/inode.c:611!
+Call Trace:
+ evict+0x282/0x4e0
+ __dentry_kill+0x2b2/0x4d0
+ dput+0x2dd/0x720
+ do_renameat2+0x596/0x970
+ __x64_sys_rename+0x78/0x90
+ do_syscall_64+0x3b/0x90
+
+[1] https://bugzilla.kernel.org/show_bug.cgi?id=215895
+
+The bug is due to fuzzed inode has both inline_data and encrypted flags.
+During f2fs_evict_inode(), as the inode was deleted by rename(), it
+will cause inline data conversion due to conflicting flags. The page
+cache will be polluted and the panic will be triggered in clear_inode().
+
+Try fixing the bug by doing more sanity checks for inline data inode in
+sanity_check_inode().
+
+Cc: stable@vger.kernel.org
+Reported-by: Ming Yan <yanming@tju.edu.cn>
+Signed-off-by: Chao Yu <chao.yu@oppo.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/f2fs.h | 1 +
+ fs/f2fs/inline.c | 29 ++++++++++++++++++++++++-----
+ fs/f2fs/inode.c | 3 +--
+ 3 files changed, 26 insertions(+), 7 deletions(-)
+
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -4052,6 +4052,7 @@ extern struct kmem_cache *f2fs_inode_ent
+ * inline.c
+ */
+ bool f2fs_may_inline_data(struct inode *inode);
++bool f2fs_sanity_check_inline_data(struct inode *inode);
+ bool f2fs_may_inline_dentry(struct inode *inode);
+ void f2fs_do_read_inline_data(struct page *page, struct page *ipage);
+ void f2fs_truncate_inline_inode(struct inode *inode,
+--- a/fs/f2fs/inline.c
++++ b/fs/f2fs/inline.c
+@@ -14,21 +14,40 @@
+ #include "node.h"
+ #include <trace/events/f2fs.h>
+
+-bool f2fs_may_inline_data(struct inode *inode)
++static bool support_inline_data(struct inode *inode)
+ {
+ if (f2fs_is_atomic_file(inode))
+ return false;
+-
+ if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode))
+ return false;
+-
+ if (i_size_read(inode) > MAX_INLINE_DATA(inode))
+ return false;
++ return true;
++}
++
++bool f2fs_may_inline_data(struct inode *inode)
++{
++ if (!support_inline_data(inode))
++ return false;
++
++ return !f2fs_post_read_required(inode);
++}
+
+- if (f2fs_post_read_required(inode))
++bool f2fs_sanity_check_inline_data(struct inode *inode)
++{
++ if (!f2fs_has_inline_data(inode))
+ return false;
+
+- return true;
++ if (!support_inline_data(inode))
++ return true;
++
++ /*
++ * used by sanity_check_inode(), when disk layout fields has not
++ * been synchronized to inmem fields.
++ */
++ return (S_ISREG(inode->i_mode) &&
++ (file_is_encrypt(inode) || file_is_verity(inode) ||
++ (F2FS_I(inode)->i_flags & F2FS_COMPR_FL)));
+ }
+
+ bool f2fs_may_inline_dentry(struct inode *inode)
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -276,8 +276,7 @@ static bool sanity_check_inode(struct in
+ }
+ }
+
+- if (f2fs_has_inline_data(inode) &&
+- (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode))) {
++ if (f2fs_sanity_check_inline_data(inode)) {
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ f2fs_warn(sbi, "%s: inode (ino=%lx, mode=%u) should not have inline_data, run fsck to fix",
+ __func__, inode->i_ino, inode->i_mode);
--- /dev/null
+From 6b8beca0edd32075a769bfe4178ca00c0dcd22a9 Mon Sep 17 00:00:00 2001
+From: Chao Yu <chao@kernel.org>
+Date: Fri, 6 May 2022 09:33:06 +0800
+Subject: f2fs: fix to do sanity check on total_data_blocks
+
+From: Chao Yu <chao@kernel.org>
+
+commit 6b8beca0edd32075a769bfe4178ca00c0dcd22a9 upstream.
+
+As Yanming reported in bugzilla:
+
+https://bugzilla.kernel.org/show_bug.cgi?id=215916
+
+The kernel message is shown below:
+
+kernel BUG at fs/f2fs/segment.c:2560!
+Call Trace:
+ allocate_segment_by_default+0x228/0x440
+ f2fs_allocate_data_block+0x13d1/0x31f0
+ do_write_page+0x18d/0x710
+ f2fs_outplace_write_data+0x151/0x250
+ f2fs_do_write_data_page+0xef9/0x1980
+ move_data_page+0x6af/0xbc0
+ do_garbage_collect+0x312f/0x46f0
+ f2fs_gc+0x6b0/0x3bc0
+ f2fs_balance_fs+0x921/0x2260
+ f2fs_write_single_data_page+0x16be/0x2370
+ f2fs_write_cache_pages+0x428/0xd00
+ f2fs_write_data_pages+0x96e/0xd50
+ do_writepages+0x168/0x550
+ __writeback_single_inode+0x9f/0x870
+ writeback_sb_inodes+0x47d/0xb20
+ __writeback_inodes_wb+0xb2/0x200
+ wb_writeback+0x4bd/0x660
+ wb_workfn+0x5f3/0xab0
+ process_one_work+0x79f/0x13e0
+ worker_thread+0x89/0xf60
+ kthread+0x26a/0x300
+ ret_from_fork+0x22/0x30
+RIP: 0010:new_curseg+0xe8d/0x15f0
+
+The root cause is: ckpt.valid_block_count is inconsistent with SIT table,
+stat info indicates filesystem has free blocks, but SIT table indicates
+filesystem has no free segment.
+
+So that during garbage colloection, it triggers panic when LFS allocator
+fails to find free segment.
+
+This patch tries to fix this issue by checking consistency in between
+ckpt.valid_block_count and block accounted from SIT.
+
+Cc: stable@vger.kernel.org
+Reported-by: Ming Yan <yanming@tju.edu.cn>
+Signed-off-by: Chao Yu <chao.yu@oppo.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/f2fs.h | 4 ++--
+ fs/f2fs/segment.c | 33 ++++++++++++++++++++++-----------
+ fs/f2fs/segment.h | 1 +
+ 3 files changed, 25 insertions(+), 13 deletions(-)
+
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -1117,8 +1117,8 @@ enum count_type {
+ */
+ #define PAGE_TYPE_OF_BIO(type) ((type) > META ? META : (type))
+ enum page_type {
+- DATA,
+- NODE,
++ DATA = 0,
++ NODE = 1, /* should not change this */
+ META,
+ NR_PAGE_TYPE,
+ META_FLUSH,
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -4460,7 +4460,7 @@ static int build_sit_entries(struct f2fs
+ unsigned int i, start, end;
+ unsigned int readed, start_blk = 0;
+ int err = 0;
+- block_t total_node_blocks = 0;
++ block_t sit_valid_blocks[2] = {0, 0};
+
+ do {
+ readed = f2fs_ra_meta_pages(sbi, start_blk, BIO_MAX_VECS,
+@@ -4485,8 +4485,8 @@ static int build_sit_entries(struct f2fs
+ if (err)
+ return err;
+ seg_info_from_raw_sit(se, &sit);
+- if (IS_NODESEG(se->type))
+- total_node_blocks += se->valid_blocks;
++
++ sit_valid_blocks[SE_PAGETYPE(se)] += se->valid_blocks;
+
+ if (f2fs_block_unit_discard(sbi)) {
+ /* build discard map only one time */
+@@ -4526,15 +4526,15 @@ static int build_sit_entries(struct f2fs
+ sit = sit_in_journal(journal, i);
+
+ old_valid_blocks = se->valid_blocks;
+- if (IS_NODESEG(se->type))
+- total_node_blocks -= old_valid_blocks;
++
++ sit_valid_blocks[SE_PAGETYPE(se)] -= old_valid_blocks;
+
+ err = check_block_count(sbi, start, &sit);
+ if (err)
+ break;
+ seg_info_from_raw_sit(se, &sit);
+- if (IS_NODESEG(se->type))
+- total_node_blocks += se->valid_blocks;
++
++ sit_valid_blocks[SE_PAGETYPE(se)] += se->valid_blocks;
+
+ if (f2fs_block_unit_discard(sbi)) {
+ if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
+@@ -4556,13 +4556,24 @@ static int build_sit_entries(struct f2fs
+ }
+ up_read(&curseg->journal_rwsem);
+
+- if (!err && total_node_blocks != valid_node_count(sbi)) {
++ if (err)
++ return err;
++
++ if (sit_valid_blocks[NODE] != valid_node_count(sbi)) {
+ f2fs_err(sbi, "SIT is corrupted node# %u vs %u",
+- total_node_blocks, valid_node_count(sbi));
+- err = -EFSCORRUPTED;
++ sit_valid_blocks[NODE], valid_node_count(sbi));
++ return -EFSCORRUPTED;
++ }
++
++ if (sit_valid_blocks[DATA] + sit_valid_blocks[NODE] >
++ valid_user_blocks(sbi)) {
++ f2fs_err(sbi, "SIT is corrupted data# %u %u vs %u",
++ sit_valid_blocks[DATA], sit_valid_blocks[NODE],
++ valid_user_blocks(sbi));
++ return -EFSCORRUPTED;
+ }
+
+- return err;
++ return 0;
+ }
+
+ static void init_free_segmap(struct f2fs_sb_info *sbi)
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -24,6 +24,7 @@
+
+ #define IS_DATASEG(t) ((t) <= CURSEG_COLD_DATA)
+ #define IS_NODESEG(t) ((t) >= CURSEG_HOT_NODE && (t) <= CURSEG_COLD_NODE)
++#define SE_PAGETYPE(se) ((IS_NODESEG((se)->type) ? NODE : DATA))
+
+ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi,
+ unsigned short seg_type)
nfsv4.1-mark-qualified-async-operations-as-moveable-.patch
f2fs-fix-to-avoid-f2fs_bug_on-in-dec_valid_node_count.patch
f2fs-fix-to-do-sanity-check-on-block-address-in-f2fs_do_zero_range.patch
+f2fs-fix-to-clear-dirty-inode-in-f2fs_evict_inode.patch
+f2fs-fix-deadloop-in-foreground-gc.patch
+f2fs-don-t-need-inode-lock-for-system-hidden-quota.patch
+f2fs-fix-to-do-sanity-check-on-total_data_blocks.patch
+f2fs-don-t-use-casefolded-comparison-for-.-and.patch
+f2fs-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch
+f2fs-fix-to-do-sanity-check-for-inline-inode.patch