]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 6 Jun 2022 11:33:34 +0000 (13:33 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 6 Jun 2022 11:33:34 +0000 (13:33 +0200)
added patches:
f2fs-don-t-need-inode-lock-for-system-hidden-quota.patch
f2fs-fix-deadloop-in-foreground-gc.patch
f2fs-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch
f2fs-fix-to-clear-dirty-inode-in-f2fs_evict_inode.patch
f2fs-fix-to-do-sanity-check-for-inline-inode.patch
f2fs-fix-to-do-sanity-check-on-total_data_blocks.patch

queue-5.10/f2fs-don-t-need-inode-lock-for-system-hidden-quota.patch [new file with mode: 0644]
queue-5.10/f2fs-fix-deadloop-in-foreground-gc.patch [new file with mode: 0644]
queue-5.10/f2fs-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch [new file with mode: 0644]
queue-5.10/f2fs-fix-to-clear-dirty-inode-in-f2fs_evict_inode.patch [new file with mode: 0644]
queue-5.10/f2fs-fix-to-do-sanity-check-for-inline-inode.patch [new file with mode: 0644]
queue-5.10/f2fs-fix-to-do-sanity-check-on-total_data_blocks.patch [new file with mode: 0644]
queue-5.10/series

diff --git a/queue-5.10/f2fs-don-t-need-inode-lock-for-system-hidden-quota.patch b/queue-5.10/f2fs-don-t-need-inode-lock-for-system-hidden-quota.patch
new file mode 100644 (file)
index 0000000..071fe28
--- /dev/null
@@ -0,0 +1,90 @@
+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
+@@ -2292,7 +2292,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
+@@ -2311,7 +2312,8 @@ int f2fs_quota_sync(struct super_block *
+               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;
diff --git a/queue-5.10/f2fs-fix-deadloop-in-foreground-gc.patch b/queue-5.10/f2fs-fix-deadloop-in-foreground-gc.patch
new file mode 100644 (file)
index 0000000..2c98f06
--- /dev/null
@@ -0,0 +1,92 @@
+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
+@@ -573,11 +573,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;
+@@ -603,19 +602,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)
diff --git a/queue-5.10/f2fs-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch b/queue-5.10/f2fs-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch
new file mode 100644 (file)
index 0000000..2df2f26
--- /dev/null
@@ -0,0 +1,44 @@
+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
+@@ -1744,6 +1744,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;
diff --git a/queue-5.10/f2fs-fix-to-clear-dirty-inode-in-f2fs_evict_inode.patch b/queue-5.10/f2fs-fix-to-clear-dirty-inode-in-f2fs_evict_inode.patch
new file mode 100644 (file)
index 0000000..56cefe4
--- /dev/null
@@ -0,0 +1,79 @@
+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
+@@ -757,8 +757,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 */
diff --git a/queue-5.10/f2fs-fix-to-do-sanity-check-for-inline-inode.patch b/queue-5.10/f2fs-fix-to-do-sanity-check-for-inline-inode.patch
new file mode 100644 (file)
index 0000000..2909a2f
--- /dev/null
@@ -0,0 +1,114 @@
+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
+@@ -3735,6 +3735,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
+@@ -272,8 +272,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);
diff --git a/queue-5.10/f2fs-fix-to-do-sanity-check-on-total_data_blocks.patch b/queue-5.10/f2fs-fix-to-do-sanity-check-on-total_data_blocks.patch
new file mode 100644 (file)
index 0000000..cf3c8d0
--- /dev/null
@@ -0,0 +1,156 @@
+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
+@@ -1021,8 +1021,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
+@@ -4423,7 +4423,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_PAGES,
+@@ -4448,8 +4448,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;
+                       /* build discard map only one time */
+                       if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
+@@ -4487,15 +4487,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 (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
+                       memset(se->discard_map, 0xff, SIT_VBLOCK_MAP_SIZE);
+@@ -4515,13 +4515,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)
index af8b9f434ea038a3bc75f75c24a6cc72e2f389e8..f4e2d6e2cfa8dfded6114c0816916f510bacffff 100644 (file)
@@ -343,3 +343,9 @@ perf-c2c-use-stdio-interface-if-slang-is-not-support.patch
 perf-jevents-fix-event-syntax-error-caused-by-extsel.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-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch
+f2fs-fix-to-do-sanity-check-for-inline-inode.patch