]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 18 Jan 2019 08:21:38 +0000 (09:21 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 18 Jan 2019 08:21:38 +0000 (09:21 +0100)
added patches:
f2fs-add-sanity_check_inode-function.patch
f2fs-avoid-unneeded-loop-in-build_sit_entries.patch
f2fs-check-blkaddr-more-accuratly-before-issue-a-bio.patch
f2fs-clean-up-argument-of-recover_data.patch
f2fs-clean-up-with-is_valid_blkaddr.patch
f2fs-cover-more-area-with-nat_tree_lock.patch
f2fs-detect-wrong-layout.patch
f2fs-enhance-sanity_check_raw_super-to-avoid-potential-overflow.patch
f2fs-factor-out-fsync-inode-entry-operations.patch
f2fs-fix-inode-cache-leak.patch
f2fs-fix-invalid-memory-access.patch
f2fs-fix-missing-up_read.patch
f2fs-fix-race-condition-in-between-free-nid-allocator-initializer.patch
f2fs-fix-to-avoid-reading-out-encrypted-data-in-page-cache.patch
f2fs-fix-to-convert-inline-directory-correctly.patch
f2fs-fix-to-determine-start_cp_addr-by-sbi-cur_cp_pack.patch
f2fs-fix-to-do-sanity-check-with-block-address-in-main-area-v2.patch
f2fs-fix-to-do-sanity-check-with-block-address-in-main-area.patch
f2fs-fix-to-do-sanity-check-with-cp_pack_start_sum.patch
f2fs-fix-to-do-sanity-check-with-node-footer-and-iblocks.patch
f2fs-fix-to-do-sanity-check-with-reserved-blkaddr-of-inline-inode.patch
f2fs-fix-to-do-sanity-check-with-secs_per_zone.patch
f2fs-fix-to-do-sanity-check-with-user_block_count.patch
f2fs-fix-validation-of-the-block-count-in-sanity_check_raw_super.patch
f2fs-free-meta-pages-if-sanity-check-for-ckpt-is-failed.patch
f2fs-give-einval-for-norecovery-and-rw-mount.patch
f2fs-introduce-and-spread-verify_blkaddr.patch
f2fs-introduce-get_checkpoint_version-for-cleanup.patch
f2fs-move-sanity-checking-of-cp-into-get_valid_checkpoint.patch
f2fs-not-allow-to-write-illegal-blkaddr.patch
f2fs-put-directory-inodes-before-checkpoint-in-roll-forward-recovery.patch
f2fs-remove-an-obsolete-variable.patch
f2fs-return-error-during-fill_super.patch
f2fs-sanity-check-on-sit-entry.patch
f2fs-use-crc-and-cp-version-to-determine-roll-forward-recovery.patch

36 files changed:
queue-4.4/f2fs-add-sanity_check_inode-function.patch [new file with mode: 0644]
queue-4.4/f2fs-avoid-unneeded-loop-in-build_sit_entries.patch [new file with mode: 0644]
queue-4.4/f2fs-check-blkaddr-more-accuratly-before-issue-a-bio.patch [new file with mode: 0644]
queue-4.4/f2fs-clean-up-argument-of-recover_data.patch [new file with mode: 0644]
queue-4.4/f2fs-clean-up-with-is_valid_blkaddr.patch [new file with mode: 0644]
queue-4.4/f2fs-cover-more-area-with-nat_tree_lock.patch [new file with mode: 0644]
queue-4.4/f2fs-detect-wrong-layout.patch [new file with mode: 0644]
queue-4.4/f2fs-enhance-sanity_check_raw_super-to-avoid-potential-overflow.patch [new file with mode: 0644]
queue-4.4/f2fs-factor-out-fsync-inode-entry-operations.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-inode-cache-leak.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-invalid-memory-access.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-missing-up_read.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-race-condition-in-between-free-nid-allocator-initializer.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-to-avoid-reading-out-encrypted-data-in-page-cache.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-to-convert-inline-directory-correctly.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-to-determine-start_cp_addr-by-sbi-cur_cp_pack.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-to-do-sanity-check-with-block-address-in-main-area-v2.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-to-do-sanity-check-with-block-address-in-main-area.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-to-do-sanity-check-with-cp_pack_start_sum.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-to-do-sanity-check-with-node-footer-and-iblocks.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-to-do-sanity-check-with-reserved-blkaddr-of-inline-inode.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-to-do-sanity-check-with-secs_per_zone.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-to-do-sanity-check-with-user_block_count.patch [new file with mode: 0644]
queue-4.4/f2fs-fix-validation-of-the-block-count-in-sanity_check_raw_super.patch [new file with mode: 0644]
queue-4.4/f2fs-free-meta-pages-if-sanity-check-for-ckpt-is-failed.patch [new file with mode: 0644]
queue-4.4/f2fs-give-einval-for-norecovery-and-rw-mount.patch [new file with mode: 0644]
queue-4.4/f2fs-introduce-and-spread-verify_blkaddr.patch [new file with mode: 0644]
queue-4.4/f2fs-introduce-get_checkpoint_version-for-cleanup.patch [new file with mode: 0644]
queue-4.4/f2fs-move-sanity-checking-of-cp-into-get_valid_checkpoint.patch [new file with mode: 0644]
queue-4.4/f2fs-not-allow-to-write-illegal-blkaddr.patch [new file with mode: 0644]
queue-4.4/f2fs-put-directory-inodes-before-checkpoint-in-roll-forward-recovery.patch [new file with mode: 0644]
queue-4.4/f2fs-remove-an-obsolete-variable.patch [new file with mode: 0644]
queue-4.4/f2fs-return-error-during-fill_super.patch [new file with mode: 0644]
queue-4.4/f2fs-sanity-check-on-sit-entry.patch [new file with mode: 0644]
queue-4.4/f2fs-use-crc-and-cp-version-to-determine-roll-forward-recovery.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/f2fs-add-sanity_check_inode-function.patch b/queue-4.4/f2fs-add-sanity_check_inode-function.patch
new file mode 100644 (file)
index 0000000..e820ce2
--- /dev/null
@@ -0,0 +1,48 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Date: Thu, 29 Nov 2018 19:17:34 +0000
+Subject: f2fs: Add sanity_check_inode() function
+
+From: Ben Hutchings <ben.hutchings@codethink.co.uk>
+
+This was done as part of commits 5d64600d4f33 "f2fs: avoid bug_on on
+corrupted inode" and 76d56d4ab4f2 "f2fs: fix to do sanity check with
+extra_attr feature" upstream, but the specific checks they added are
+not applicable to 4.4.
+
+Cc: Jaegeuk Kim <jaegeuk@kernel.org>
+Cc: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/inode.c |   12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -95,6 +95,13 @@ static void __recover_inline_status(stru
+       return;
+ }
++static bool sanity_check_inode(struct inode *inode)
++{
++      struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
++
++      return true;
++}
++
+ static int do_read_inode(struct inode *inode)
+ {
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+@@ -143,6 +150,11 @@ static int do_read_inode(struct inode *i
+       get_inline_info(fi, ri);
++      if (!sanity_check_inode(inode)) {
++              f2fs_put_page(node_page, 1);
++              return -EINVAL;
++      }
++
+       /* check data exist */
+       if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode))
+               __recover_inline_status(inode, node_page);
diff --git a/queue-4.4/f2fs-avoid-unneeded-loop-in-build_sit_entries.patch b/queue-4.4/f2fs-avoid-unneeded-loop-in-build_sit_entries.patch
new file mode 100644 (file)
index 0000000..5c29788
--- /dev/null
@@ -0,0 +1,98 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Fri, 19 Aug 2016 23:13:47 +0800
+Subject: f2fs: avoid unneeded loop in build_sit_entries
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit d600af236da51d9e3b90d21a23f95b820bd02e2f upstream.
+
+When building each sit entry in cache, firstly, we will load it from
+sit page, and then check all entries in sit journal, if there is one
+updated entry in journal, cover cached entry with the journaled one.
+
+Actually, most of check operation is unneeded since we only need
+to update cached entries with journaled entries in batch, so
+changing the flow as below for more efficient:
+1. load all sit entries into cache from sit pages;
+2. update sit entries with journal.
+
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4:
+ - Keep using curseg->curseg_mutex for serialisation
+ - Use sum instead of journal
+ - Don't add f2fs_discard_en() condition]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/segment.c |   44 ++++++++++++++++++++++++++++----------------
+ 1 file changed, 28 insertions(+), 16 deletions(-)
+
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -2145,22 +2145,11 @@ static void build_sit_entries(struct f2f
+                       struct f2fs_sit_entry sit;
+                       struct page *page;
+-                      mutex_lock(&curseg->curseg_mutex);
+-                      for (i = 0; i < sits_in_cursum(sum); i++) {
+-                              if (le32_to_cpu(segno_in_journal(sum, i))
+-                                                              == start) {
+-                                      sit = sit_in_journal(sum, i);
+-                                      mutex_unlock(&curseg->curseg_mutex);
+-                                      goto got_it;
+-                              }
+-                      }
+-                      mutex_unlock(&curseg->curseg_mutex);
+-
+                       page = get_current_sit_page(sbi, start);
+                       sit_blk = (struct f2fs_sit_block *)page_address(page);
+                       sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)];
+                       f2fs_put_page(page, 1);
+-got_it:
++
+                       check_block_count(sbi, start, &sit);
+                       seg_info_from_raw_sit(se, &sit);
+@@ -2168,13 +2157,36 @@ got_it:
+                       memcpy(se->discard_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
+                       sbi->discard_blks += sbi->blocks_per_seg - se->valid_blocks;
+-                      if (sbi->segs_per_sec > 1) {
+-                              struct sec_entry *e = get_sec_entry(sbi, start);
+-                              e->valid_blocks += se->valid_blocks;
+-                      }
++                      if (sbi->segs_per_sec > 1)
++                              get_sec_entry(sbi, start)->valid_blocks +=
++                                                      se->valid_blocks;
+               }
+               start_blk += readed;
+       } while (start_blk < sit_blk_cnt);
++
++      mutex_lock(&curseg->curseg_mutex);
++      for (i = 0; i < sits_in_cursum(sum); i++) {
++              struct f2fs_sit_entry sit;
++              struct seg_entry *se;
++              unsigned int old_valid_blocks;
++
++              start = le32_to_cpu(segno_in_journal(sum, i));
++              se = &sit_i->sentries[start];
++              sit = sit_in_journal(sum, i);
++
++              old_valid_blocks = se->valid_blocks;
++
++              check_block_count(sbi, start, &sit);
++              seg_info_from_raw_sit(se, &sit);
++
++              memcpy(se->discard_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
++              sbi->discard_blks += old_valid_blocks - se->valid_blocks;
++
++              if (sbi->segs_per_sec > 1)
++                      get_sec_entry(sbi, start)->valid_blocks +=
++                              se->valid_blocks - old_valid_blocks;
++      }
++      mutex_unlock(&curseg->curseg_mutex);
+ }
+ static void init_free_segmap(struct f2fs_sb_info *sbi)
diff --git a/queue-4.4/f2fs-check-blkaddr-more-accuratly-before-issue-a-bio.patch b/queue-4.4/f2fs-check-blkaddr-more-accuratly-before-issue-a-bio.patch
new file mode 100644 (file)
index 0000000..96937ba
--- /dev/null
@@ -0,0 +1,122 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Yunlei He <heyunlei@huawei.com>
+Date: Thu, 8 Mar 2018 16:29:13 +0800
+Subject: f2fs: check blkaddr more accuratly before issue a bio
+
+From: Yunlei He <heyunlei@huawei.com>
+
+commit 0833721ec3658a4e9d5e58b6fa82cf9edc431e59 upstream.
+
+This patch check blkaddr more accuratly before issue a
+write or read bio.
+
+Signed-off-by: Yunlei He <heyunlei@huawei.com>
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4:
+ - CoW is not implemented so check f2fs_io_info::blk_addr instead of
+   f2fs_io_info::{old,new}_blkaddr
+ - Operation code is f2fs_io_info::rw instead of f2fs_io_info::op
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c |    2 ++
+ fs/f2fs/data.c       |    3 ++-
+ fs/f2fs/f2fs.h       |    1 +
+ fs/f2fs/segment.h    |   25 +++++++++++++++++++------
+ 4 files changed, 24 insertions(+), 7 deletions(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -58,6 +58,7 @@ static struct page *__get_meta_page(stru
+               .rw = READ_SYNC | REQ_META | REQ_PRIO,
+               .blk_addr = index,
+               .encrypted_page = NULL,
++              .is_meta = is_meta,
+       };
+       if (unlikely(!is_meta))
+@@ -151,6 +152,7 @@ int ra_meta_pages(struct f2fs_sb_info *s
+               .type = META,
+               .rw = sync ? (READ_SYNC | REQ_META | REQ_PRIO) : READA,
+               .encrypted_page = NULL,
++              .is_meta = (type != META_POR),
+       };
+       if (unlikely(type == META_POR))
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -147,6 +147,7 @@ int f2fs_submit_page_bio(struct f2fs_io_
+       struct bio *bio;
+       struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page;
++      verify_block_addr(fio, fio->blk_addr);
+       trace_f2fs_submit_page_bio(page, fio);
+       f2fs_trace_ios(fio, 0);
+@@ -172,7 +173,7 @@ void f2fs_submit_page_mbio(struct f2fs_i
+       io = is_read ? &sbi->read_io : &sbi->write_io[btype];
+-      verify_block_addr(sbi, fio->blk_addr);
++      verify_block_addr(fio, fio->blk_addr);
+       down_write(&io->io_rwsem);
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -684,6 +684,7 @@ struct f2fs_io_info {
+       block_t blk_addr;       /* block address to be written */
+       struct page *page;      /* page to be written */
+       struct page *encrypted_page;    /* encrypted page */
++      bool is_meta;           /* indicate borrow meta inode mapping or not */
+ };
+ #define is_read_io(rw)        (((rw) & 1) == READ)
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -48,13 +48,19 @@
+        (secno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno /             \
+         sbi->segs_per_sec))   \
+-#define MAIN_BLKADDR(sbi)     (SM_I(sbi)->main_blkaddr)
+-#define SEG0_BLKADDR(sbi)     (SM_I(sbi)->seg0_blkaddr)
++#define MAIN_BLKADDR(sbi)                                             \
++      (SM_I(sbi) ? SM_I(sbi)->main_blkaddr :                          \
++              le32_to_cpu(F2FS_RAW_SUPER(sbi)->main_blkaddr))
++#define SEG0_BLKADDR(sbi)                                             \
++      (SM_I(sbi) ? SM_I(sbi)->seg0_blkaddr :                          \
++              le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment0_blkaddr))
+ #define MAIN_SEGS(sbi)        (SM_I(sbi)->main_segments)
+ #define MAIN_SECS(sbi)        (sbi->total_sections)
+-#define TOTAL_SEGS(sbi)       (SM_I(sbi)->segment_count)
++#define TOTAL_SEGS(sbi)                                                       \
++      (SM_I(sbi) ? SM_I(sbi)->segment_count :                                 \
++              le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count))
+ #define TOTAL_BLKS(sbi)       (TOTAL_SEGS(sbi) << sbi->log_blocks_per_seg)
+ #define MAX_BLKADDR(sbi)      (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi))
+@@ -576,10 +582,17 @@ static inline void check_seg_range(struc
+       f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1);
+ }
+-static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
++static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
+ {
+-      BUG_ON(blk_addr < SEG0_BLKADDR(sbi)
+-                      || blk_addr >= MAX_BLKADDR(sbi));
++      struct f2fs_sb_info *sbi = fio->sbi;
++
++      if (PAGE_TYPE_OF_BIO(fio->type) == META &&
++                              (!is_read_io(fio->rw) || fio->is_meta))
++              BUG_ON(blk_addr < SEG0_BLKADDR(sbi) ||
++                              blk_addr >= MAIN_BLKADDR(sbi));
++      else
++              BUG_ON(blk_addr < MAIN_BLKADDR(sbi) ||
++                              blk_addr >= MAX_BLKADDR(sbi));
+ }
+ /*
diff --git a/queue-4.4/f2fs-clean-up-argument-of-recover_data.patch b/queue-4.4/f2fs-clean-up-argument-of-recover_data.patch
new file mode 100644 (file)
index 0000000..6c850cf
--- /dev/null
@@ -0,0 +1,52 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <chao2.yu@samsung.com>
+Date: Tue, 1 Dec 2015 11:43:59 +0800
+Subject: f2fs: clean up argument of recover_data
+
+From: Chao Yu <chao2.yu@samsung.com>
+
+commit b7973f2378c619d0e17a075f13350bd58a9ebe3d upstream.
+
+In recover_data, value of argument 'type' will be CURSEG_WARM_NODE all
+the time, remove it for cleanup.
+
+Signed-off-by: Chao Yu <chao2.yu@samsung.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Picked as dependency of commit 6781eabba1bd "f2fs: give -EINVAL for
+ norecovery and rw mount"]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/recovery.c |    7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+--- a/fs/f2fs/recovery.c
++++ b/fs/f2fs/recovery.c
+@@ -459,8 +459,7 @@ out:
+       return err;
+ }
+-static int recover_data(struct f2fs_sb_info *sbi,
+-                              struct list_head *head, int type)
++static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head)
+ {
+       unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
+       struct curseg_info *curseg;
+@@ -469,7 +468,7 @@ static int recover_data(struct f2fs_sb_i
+       block_t blkaddr;
+       /* get node pages in the current segment */
+-      curseg = CURSEG_I(sbi, type);
++      curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
+       blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
+       while (1) {
+@@ -556,7 +555,7 @@ int recover_fsync_data(struct f2fs_sb_in
+       need_writecp = true;
+       /* step #2: recover data */
+-      err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE);
++      err = recover_data(sbi, &inode_list);
+       if (!err)
+               f2fs_bug_on(sbi, !list_empty(&inode_list));
+ out:
diff --git a/queue-4.4/f2fs-clean-up-with-is_valid_blkaddr.patch b/queue-4.4/f2fs-clean-up-with-is_valid_blkaddr.patch
new file mode 100644 (file)
index 0000000..9dfeab0
--- /dev/null
@@ -0,0 +1,201 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Wed, 23 May 2018 22:25:08 +0800
+Subject: f2fs: clean up with is_valid_blkaddr()
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit 7b525dd01365c6764018e374d391c92466be1b7a upstream.
+
+- rename is_valid_blkaddr() to is_valid_meta_blkaddr() for readability.
+- introduce is_valid_blkaddr() for cleanup.
+
+No logic change in this patch.
+
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4:
+ - Drop inapplicable change to check on f2fs_fio_info::old_blkaddr
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c |    4 ++--
+ fs/f2fs/data.c       |    4 ++--
+ fs/f2fs/f2fs.h       |    9 ++++++++-
+ fs/f2fs/file.c       |    2 +-
+ fs/f2fs/inode.c      |    2 +-
+ fs/f2fs/node.c       |    5 ++---
+ fs/f2fs/recovery.c   |    6 +++---
+ fs/f2fs/segment.c    |    4 ++--
+ fs/f2fs/segment.h    |    2 +-
+ 9 files changed, 22 insertions(+), 16 deletions(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -107,7 +107,7 @@ struct page *get_tmp_page(struct f2fs_sb
+       return __get_meta_page(sbi, index, false);
+ }
+-bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
++bool is_valid_meta_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
+ {
+       switch (type) {
+       case META_NAT:
+@@ -160,7 +160,7 @@ int ra_meta_pages(struct f2fs_sb_info *s
+       for (; nrpages-- > 0; blkno++) {
+-              if (!is_valid_blkaddr(sbi, blkno, type))
++              if (!is_valid_meta_blkaddr(sbi, blkno, type))
+                       goto out;
+               switch (type) {
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -604,7 +604,7 @@ static int f2fs_map_blocks(struct inode
+               goto unlock_out;
+       }
+-      if (dn.data_blkaddr == NEW_ADDR || dn.data_blkaddr == NULL_ADDR) {
++      if (!is_valid_blkaddr(dn.data_blkaddr)) {
+               if (create) {
+                       if (unlikely(f2fs_cp_error(sbi))) {
+                               err = -EIO;
+@@ -1090,7 +1090,7 @@ int do_write_data_page(struct f2fs_io_in
+        * If current allocation needs SSR,
+        * it had better in-place writes for updated data.
+        */
+-      if (unlikely(fio->blk_addr != NEW_ADDR &&
++      if (unlikely(is_valid_blkaddr(fio->blk_addr) &&
+                       !is_cold_data(page) &&
+                       need_inplace_update(inode))) {
+               rewrite_data_page(fio);
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -1647,6 +1647,13 @@ static inline void *f2fs_kvzalloc(size_t
+       (pgofs - ADDRS_PER_INODE(fi) + ADDRS_PER_BLOCK) /       \
+       ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi))
++static inline bool is_valid_blkaddr(block_t blkaddr)
++{
++      if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
++              return false;
++      return true;
++}
++
+ /*
+  * file.c
+  */
+@@ -1818,7 +1825,7 @@ void destroy_segment_manager_caches(void
+ struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
+ struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
+ struct page *get_tmp_page(struct f2fs_sb_info *, pgoff_t);
+-bool is_valid_blkaddr(struct f2fs_sb_info *, block_t, int);
++bool is_valid_meta_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type);
+ int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int, bool);
+ void ra_meta_pages_cond(struct f2fs_sb_info *, pgoff_t);
+ long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
+--- a/fs/f2fs/file.c
++++ b/fs/f2fs/file.c
+@@ -311,7 +311,7 @@ static bool __found_offset(block_t blkad
+       switch (whence) {
+       case SEEK_DATA:
+               if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
+-                      (blkaddr != NEW_ADDR && blkaddr != NULL_ADDR))
++                      is_valid_blkaddr(blkaddr))
+                       return true;
+               break;
+       case SEEK_HOLE:
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -54,7 +54,7 @@ static bool __written_first_block(struct
+ {
+       block_t addr = le32_to_cpu(ri->i_addr[0]);
+-      if (addr != NEW_ADDR && addr != NULL_ADDR)
++      if (is_valid_blkaddr(addr))
+               return true;
+       return false;
+ }
+--- a/fs/f2fs/node.c
++++ b/fs/f2fs/node.c
+@@ -296,8 +296,7 @@ static void set_node_addr(struct f2fs_sb
+                       new_blkaddr == NULL_ADDR);
+       f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR &&
+                       new_blkaddr == NEW_ADDR);
+-      f2fs_bug_on(sbi, nat_get_blkaddr(e) != NEW_ADDR &&
+-                      nat_get_blkaddr(e) != NULL_ADDR &&
++      f2fs_bug_on(sbi, is_valid_blkaddr(nat_get_blkaddr(e)) &&
+                       new_blkaddr == NEW_ADDR);
+       /* increment version no as node is removed */
+@@ -312,7 +311,7 @@ static void set_node_addr(struct f2fs_sb
+       /* change address */
+       nat_set_blkaddr(e, new_blkaddr);
+-      if (new_blkaddr == NEW_ADDR || new_blkaddr == NULL_ADDR)
++      if (!is_valid_blkaddr(new_blkaddr))
+               set_nat_flag(e, IS_CHECKPOINTED, false);
+       __set_nat_cache_dirty(nm_i, e);
+--- a/fs/f2fs/recovery.c
++++ b/fs/f2fs/recovery.c
+@@ -208,7 +208,7 @@ static int find_fsync_dnodes(struct f2fs
+       while (1) {
+               struct fsync_inode_entry *entry;
+-              if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
++              if (!is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
+                       return 0;
+               page = get_tmp_page(sbi, blkaddr);
+@@ -443,7 +443,7 @@ static int do_recover_data(struct f2fs_s
+               }
+               /* dest is valid block, try to recover from src to dest */
+-              if (is_valid_blkaddr(sbi, dest, META_POR)) {
++              if (is_valid_meta_blkaddr(sbi, dest, META_POR)) {
+                       if (src == NULL_ADDR) {
+                               err = reserve_new_block(&dn);
+@@ -494,7 +494,7 @@ static int recover_data(struct f2fs_sb_i
+       while (1) {
+               struct fsync_inode_entry *entry;
+-              if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
++              if (!is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
+                       break;
+               ra_meta_pages_cond(sbi, blkaddr);
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -752,7 +752,7 @@ bool is_checkpointed_data(struct f2fs_sb
+       struct seg_entry *se;
+       bool is_cp = false;
+-      if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
++      if (!is_valid_blkaddr(blkaddr))
+               return true;
+       mutex_lock(&sit_i->sentry_lock);
+@@ -1466,7 +1466,7 @@ void f2fs_wait_on_encrypted_page_writeba
+ {
+       struct page *cpage;
+-      if (blkaddr == NEW_ADDR)
++      if (!is_valid_blkaddr(blkaddr))
+               return;
+       f2fs_bug_on(sbi, blkaddr == NULL_ADDR);
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -80,7 +80,7 @@
+       (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (sbi->blocks_per_seg - 1))
+ #define GET_SEGNO(sbi, blk_addr)                                      \
+-      (((blk_addr == NULL_ADDR) || (blk_addr == NEW_ADDR)) ?          \
++      ((!is_valid_blkaddr(blk_addr)) ?                        \
+       NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi),                 \
+               GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
+ #define GET_SECNO(sbi, segno)                                 \
diff --git a/queue-4.4/f2fs-cover-more-area-with-nat_tree_lock.patch b/queue-4.4/f2fs-cover-more-area-with-nat_tree_lock.patch
new file mode 100644 (file)
index 0000000..93b00a6
--- /dev/null
@@ -0,0 +1,164 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Sat, 2 Jan 2016 09:19:41 -0800
+Subject: f2fs: cover more area with nat_tree_lock
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit a51311938e14c17f5a94d30baac9d7bec71f5858 upstream.
+
+There was a subtle bug on nat cache management which incurs wrong nid allocation
+or wrong block addresses when try_to_free_nats is triggered heavily.
+This patch enlarges the previous coverage of nat_tree_lock to avoid data race.
+
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/node.c |   29 ++++++++++++-----------------
+ 1 file changed, 12 insertions(+), 17 deletions(-)
+
+--- a/fs/f2fs/node.c
++++ b/fs/f2fs/node.c
+@@ -261,13 +261,11 @@ static void cache_nat_entry(struct f2fs_
+ {
+       struct nat_entry *e;
+-      down_write(&nm_i->nat_tree_lock);
+       e = __lookup_nat_cache(nm_i, nid);
+       if (!e) {
+               e = grab_nat_entry(nm_i, nid);
+               node_info_from_raw_nat(&e->ni, ne);
+       }
+-      up_write(&nm_i->nat_tree_lock);
+ }
+ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
+@@ -379,6 +377,8 @@ void get_node_info(struct f2fs_sb_info *
+       memset(&ne, 0, sizeof(struct f2fs_nat_entry));
++      down_write(&nm_i->nat_tree_lock);
++
+       /* Check current segment summary */
+       mutex_lock(&curseg->curseg_mutex);
+       i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0);
+@@ -399,6 +399,7 @@ void get_node_info(struct f2fs_sb_info *
+ cache:
+       /* cache nat entry */
+       cache_nat_entry(NM_I(sbi), nid, &ne);
++      up_write(&nm_i->nat_tree_lock);
+ }
+ /*
+@@ -1440,13 +1441,10 @@ static int add_free_nid(struct f2fs_sb_i
+       if (build) {
+               /* do not add allocated nids */
+-              down_read(&nm_i->nat_tree_lock);
+               ne = __lookup_nat_cache(nm_i, nid);
+-              if (ne &&
+-                      (!get_nat_flag(ne, IS_CHECKPOINTED) ||
++              if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
+                               nat_get_blkaddr(ne) != NULL_ADDR))
+                       allocated = true;
+-              up_read(&nm_i->nat_tree_lock);
+               if (allocated)
+                       return 0;
+       }
+@@ -1532,6 +1530,8 @@ static void build_free_nids(struct f2fs_
+       ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), FREE_NID_PAGES,
+                                                       META_NAT, true);
++      down_read(&nm_i->nat_tree_lock);
++
+       while (1) {
+               struct page *page = get_current_nat_page(sbi, nid);
+@@ -1560,6 +1560,7 @@ static void build_free_nids(struct f2fs_
+                       remove_free_nid(nm_i, nid);
+       }
+       mutex_unlock(&curseg->curseg_mutex);
++      up_read(&nm_i->nat_tree_lock);
+       ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nm_i->next_scan_nid),
+                                       nm_i->ra_nid_pages, META_NAT, false);
+@@ -1842,14 +1843,12 @@ static void remove_nats_in_journal(struc
+               raw_ne = nat_in_journal(sum, i);
+-              down_write(&nm_i->nat_tree_lock);
+               ne = __lookup_nat_cache(nm_i, nid);
+               if (!ne) {
+                       ne = grab_nat_entry(nm_i, nid);
+                       node_info_from_raw_nat(&ne->ni, &raw_ne);
+               }
+               __set_nat_cache_dirty(nm_i, ne);
+-              up_write(&nm_i->nat_tree_lock);
+       }
+       update_nats_in_cursum(sum, -i);
+       mutex_unlock(&curseg->curseg_mutex);
+@@ -1883,7 +1882,6 @@ static void __flush_nat_entry_set(struct
+       struct f2fs_nat_block *nat_blk;
+       struct nat_entry *ne, *cur;
+       struct page *page = NULL;
+-      struct f2fs_nm_info *nm_i = NM_I(sbi);
+       /*
+        * there are two steps to flush nat entries:
+@@ -1920,12 +1918,8 @@ static void __flush_nat_entry_set(struct
+                       raw_ne = &nat_blk->entries[nid - start_nid];
+               }
+               raw_nat_from_node_info(raw_ne, &ne->ni);
+-
+-              down_write(&NM_I(sbi)->nat_tree_lock);
+               nat_reset_flag(ne);
+               __clear_nat_cache_dirty(NM_I(sbi), ne);
+-              up_write(&NM_I(sbi)->nat_tree_lock);
+-
+               if (nat_get_blkaddr(ne) == NULL_ADDR)
+                       add_free_nid(sbi, nid, false);
+       }
+@@ -1937,9 +1931,7 @@ static void __flush_nat_entry_set(struct
+       f2fs_bug_on(sbi, set->entry_cnt);
+-      down_write(&nm_i->nat_tree_lock);
+       radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set);
+-      up_write(&nm_i->nat_tree_lock);
+       kmem_cache_free(nat_entry_set_slab, set);
+ }
+@@ -1959,6 +1951,9 @@ void flush_nat_entries(struct f2fs_sb_in
+       if (!nm_i->dirty_nat_cnt)
+               return;
++
++      down_write(&nm_i->nat_tree_lock);
++
+       /*
+        * if there are no enough space in journal to store dirty nat
+        * entries, remove all entries from journal and merge them
+@@ -1967,7 +1962,6 @@ void flush_nat_entries(struct f2fs_sb_in
+       if (!__has_cursum_space(sum, nm_i->dirty_nat_cnt, NAT_JOURNAL))
+               remove_nats_in_journal(sbi);
+-      down_write(&nm_i->nat_tree_lock);
+       while ((found = __gang_lookup_nat_set(nm_i,
+                                       set_idx, SETVEC_SIZE, setvec))) {
+               unsigned idx;
+@@ -1976,12 +1970,13 @@ void flush_nat_entries(struct f2fs_sb_in
+                       __adjust_nat_entry_set(setvec[idx], &sets,
+                                                       MAX_NAT_JENTRIES(sum));
+       }
+-      up_write(&nm_i->nat_tree_lock);
+       /* flush dirty nats in nat entry set */
+       list_for_each_entry_safe(set, tmp, &sets, set_list)
+               __flush_nat_entry_set(sbi, set);
++      up_write(&nm_i->nat_tree_lock);
++
+       f2fs_bug_on(sbi, nm_i->dirty_nat_cnt);
+ }
diff --git a/queue-4.4/f2fs-detect-wrong-layout.patch b/queue-4.4/f2fs-detect-wrong-layout.patch
new file mode 100644 (file)
index 0000000..13f6d42
--- /dev/null
@@ -0,0 +1,64 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Mon, 5 Dec 2016 13:56:04 -0800
+Subject: f2fs: detect wrong layout
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit 2040fce83fe17763b07c97c1f691da2bb85e4135 upstream.
+
+Previous mkfs.f2fs allows small partition inappropriately, so f2fs should detect
+that as well.
+
+Refer this in f2fs-tools.
+
+mkfs.f2fs: detect small partition by overprovision ratio and # of segments
+
+Reported-and-Tested-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/segment.h |    2 ++
+ fs/f2fs/super.c   |   11 +++++++++++
+ 2 files changed, 13 insertions(+)
+
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -17,6 +17,8 @@
+ #define DEF_RECLAIM_PREFREE_SEGMENTS  5       /* 5% over total segments */
++#define F2FS_MIN_SEGMENTS     9 /* SB + 2 (CP + SIT + NAT) + SSA + MAIN */
++
+ /* L: Logical segment # in volume, R: Relative segment # in main area */
+ #define GET_L2R_SEGNO(free_i, segno)  (segno - free_i->start_segno)
+ #define GET_R2L_SEGNO(free_i, segno)  (segno + free_i->start_segno)
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1078,6 +1078,7 @@ int sanity_check_ckpt(struct f2fs_sb_inf
+       unsigned int total, fsmeta;
+       struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
++      unsigned int ovp_segments, reserved_segments;
+       unsigned int main_segs, blocks_per_seg;
+       unsigned int sit_segs, nat_segs;
+       unsigned int sit_bitmap_size, nat_bitmap_size;
+@@ -1096,6 +1097,16 @@ int sanity_check_ckpt(struct f2fs_sb_inf
+       if (unlikely(fsmeta >= total))
+               return 1;
++      ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
++      reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count);
++
++      if (unlikely(fsmeta < F2FS_MIN_SEGMENTS ||
++                      ovp_segments == 0 || reserved_segments == 0)) {
++              f2fs_msg(sbi->sb, KERN_ERR,
++                      "Wrong layout: check mkfs.f2fs version");
++              return 1;
++      }
++
+       main_segs = le32_to_cpu(raw_super->segment_count_main);
+       blocks_per_seg = sbi->blocks_per_seg;
diff --git a/queue-4.4/f2fs-enhance-sanity_check_raw_super-to-avoid-potential-overflow.patch b/queue-4.4/f2fs-enhance-sanity_check_raw_super-to-avoid-potential-overflow.patch
new file mode 100644 (file)
index 0000000..dcb98dd
--- /dev/null
@@ -0,0 +1,181 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Fri, 27 Apr 2018 19:03:22 -0700
+Subject: f2fs: enhance sanity_check_raw_super() to avoid potential overflow
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit 0cfe75c5b011994651a4ca6d74f20aa997bfc69a upstream.
+
+In order to avoid the below overflow issue, we should have checked the
+boundaries in superblock before reaching out to allocation. As Linus suggested,
+the right place should be sanity_check_raw_super().
+
+Dr Silvio Cesare of InfoSect reported:
+
+There are integer overflows with using the cp_payload superblock field in the
+f2fs filesystem potentially leading to memory corruption.
+
+include/linux/f2fs_fs.h
+
+struct f2fs_super_block {
+...
+        __le32 cp_payload;
+
+fs/f2fs/f2fs.h
+
+typedef u32 block_t;    /*
+                         * should not change u32, since it is the on-disk block
+                         * address format, __le32.
+                         */
+...
+
+static inline block_t __cp_payload(struct f2fs_sb_info *sbi)
+{
+        return le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
+}
+
+fs/f2fs/checkpoint.c
+
+        block_t start_blk, orphan_blocks, i, j;
+...
+        start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
+        orphan_blocks = __start_sum_addr(sbi) - 1 - __cp_payload(sbi);
+
++++ integer overflows
+
+...
+        unsigned int cp_blks = 1 + __cp_payload(sbi);
+...
+        sbi->ckpt = kzalloc(cp_blks * blk_size, GFP_KERNEL);
+
++++ integer overflow leading to incorrect heap allocation.
+
+        int cp_payload_blks = __cp_payload(sbi);
+...
+        ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
+                        orphan_blocks);
+
++++ sign bug and integer overflow
+
+...
+        for (i = 1; i < 1 + cp_payload_blks; i++)
+
++++ integer overflow
+
+...
+
+      sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS -
+                        NR_CURSEG_TYPE - __cp_payload(sbi)) *
+                                F2FS_ORPHANS_PER_BLOCK;
+
++++ integer overflow
+
+Reported-by: Greg KH <greg@kroah.com>
+Reported-by: Silvio Cesare <silvio.cesare@gmail.com>
+Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4:
+ - No hot file extension support
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/super.c |   71 ++++++++++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 64 insertions(+), 7 deletions(-)
+
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -994,6 +994,8 @@ static inline bool sanity_check_area_bou
+ static int sanity_check_raw_super(struct super_block *sb,
+                       struct f2fs_super_block *raw_super)
+ {
++      block_t segment_count, segs_per_sec, secs_per_zone;
++      block_t total_sections, blocks_per_seg;
+       unsigned int blocksize;
+       if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) {
+@@ -1047,6 +1049,68 @@ static int sanity_check_raw_super(struct
+               return 1;
+       }
++      segment_count = le32_to_cpu(raw_super->segment_count);
++      segs_per_sec = le32_to_cpu(raw_super->segs_per_sec);
++      secs_per_zone = le32_to_cpu(raw_super->secs_per_zone);
++      total_sections = le32_to_cpu(raw_super->section_count);
++
++      /* blocks_per_seg should be 512, given the above check */
++      blocks_per_seg = 1 << le32_to_cpu(raw_super->log_blocks_per_seg);
++
++      if (segment_count > F2FS_MAX_SEGMENT ||
++                              segment_count < F2FS_MIN_SEGMENTS) {
++              f2fs_msg(sb, KERN_INFO,
++                      "Invalid segment count (%u)",
++                      segment_count);
++              return 1;
++      }
++
++      if (total_sections > segment_count ||
++                      total_sections < F2FS_MIN_SEGMENTS ||
++                      segs_per_sec > segment_count || !segs_per_sec) {
++              f2fs_msg(sb, KERN_INFO,
++                      "Invalid segment/section count (%u, %u x %u)",
++                      segment_count, total_sections, segs_per_sec);
++              return 1;
++      }
++
++      if ((segment_count / segs_per_sec) < total_sections) {
++              f2fs_msg(sb, KERN_INFO,
++                      "Small segment_count (%u < %u * %u)",
++                      segment_count, segs_per_sec, total_sections);
++              return 1;
++      }
++
++      if (segment_count > (le32_to_cpu(raw_super->block_count) >> 9)) {
++              f2fs_msg(sb, KERN_INFO,
++                      "Wrong segment_count / block_count (%u > %u)",
++                      segment_count, le32_to_cpu(raw_super->block_count));
++              return 1;
++      }
++
++      if (secs_per_zone > total_sections) {
++              f2fs_msg(sb, KERN_INFO,
++                      "Wrong secs_per_zone (%u > %u)",
++                      secs_per_zone, total_sections);
++              return 1;
++      }
++      if (le32_to_cpu(raw_super->extension_count) > F2FS_MAX_EXTENSION) {
++              f2fs_msg(sb, KERN_INFO,
++                      "Corrupted extension count (%u > %u)",
++                      le32_to_cpu(raw_super->extension_count),
++                      F2FS_MAX_EXTENSION);
++              return 1;
++      }
++
++      if (le32_to_cpu(raw_super->cp_payload) >
++                              (blocks_per_seg - F2FS_CP_PACKS)) {
++              f2fs_msg(sb, KERN_INFO,
++                      "Insane cp_payload (%u > %u)",
++                      le32_to_cpu(raw_super->cp_payload),
++                      blocks_per_seg - F2FS_CP_PACKS);
++              return 1;
++      }
++
+       /* check reserved ino info */
+       if (le32_to_cpu(raw_super->node_ino) != 1 ||
+               le32_to_cpu(raw_super->meta_ino) != 2 ||
+@@ -1059,13 +1123,6 @@ static int sanity_check_raw_super(struct
+               return 1;
+       }
+-      if (le32_to_cpu(raw_super->segment_count) > F2FS_MAX_SEGMENT) {
+-              f2fs_msg(sb, KERN_INFO,
+-                      "Invalid segment count (%u)",
+-                      le32_to_cpu(raw_super->segment_count));
+-              return 1;
+-      }
+-
+       /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
+       if (sanity_check_area_boundary(sb, raw_super))
+               return 1;
diff --git a/queue-4.4/f2fs-factor-out-fsync-inode-entry-operations.patch b/queue-4.4/f2fs-factor-out-fsync-inode-entry-operations.patch
new file mode 100644 (file)
index 0000000..a6c4264
--- /dev/null
@@ -0,0 +1,125 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Fri, 29 Apr 2016 20:13:37 +0800
+Subject: f2fs: factor out fsync inode entry operations
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit 3f8ab270855b0b461995da5dc48dce9461c85d94 upstream.
+
+Factor out fsync inode entry operations into {add,del}_fsync_inode.
+
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/recovery.c |   59 ++++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 38 insertions(+), 21 deletions(-)
+
+--- a/fs/f2fs/recovery.c
++++ b/fs/f2fs/recovery.c
+@@ -67,6 +67,28 @@ static struct fsync_inode_entry *get_fsy
+       return NULL;
+ }
++static struct fsync_inode_entry *add_fsync_inode(struct list_head *head,
++                                                      struct inode *inode)
++{
++      struct fsync_inode_entry *entry;
++
++      entry = kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO);
++      if (!entry)
++              return NULL;
++
++      entry->inode = inode;
++      list_add_tail(&entry->list, head);
++
++      return entry;
++}
++
++static void del_fsync_inode(struct fsync_inode_entry *entry)
++{
++      iput(entry->inode);
++      list_del(&entry->list);
++      kmem_cache_free(fsync_entry_slab, entry);
++}
++
+ static int recover_dentry(struct inode *inode, struct page *ipage)
+ {
+       struct f2fs_inode *raw_inode = F2FS_INODE(ipage);
+@@ -172,6 +194,7 @@ static int find_fsync_dnodes(struct f2fs
+ {
+       unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
+       struct curseg_info *curseg;
++      struct inode *inode;
+       struct page *page = NULL;
+       block_t blkaddr;
+       int err = 0;
+@@ -204,27 +227,27 @@ static int find_fsync_dnodes(struct f2fs
+                                       break;
+                       }
+-                      /* add this fsync inode to the list */
+-                      entry = kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO);
+-                      if (!entry) {
+-                              err = -ENOMEM;
+-                              break;
+-                      }
+                       /*
+                        * CP | dnode(F) | inode(DF)
+                        * For this case, we should not give up now.
+                        */
+-                      entry->inode = f2fs_iget(sbi->sb, ino_of_node(page));
+-                      if (IS_ERR(entry->inode)) {
+-                              err = PTR_ERR(entry->inode);
+-                              kmem_cache_free(fsync_entry_slab, entry);
++                      inode = f2fs_iget(sbi->sb, ino_of_node(page));
++                      if (IS_ERR(inode)) {
++                              err = PTR_ERR(inode);
+                               if (err == -ENOENT) {
+                                       err = 0;
+                                       goto next;
+                               }
+                               break;
+                       }
+-                      list_add_tail(&entry->list, head);
++
++                      /* add this fsync inode to the list */
++                      entry = add_fsync_inode(head, inode);
++                      if (!entry) {
++                              err = -ENOMEM;
++                              iput(inode);
++                              break;
++                      }
+               }
+               entry->blkaddr = blkaddr;
+@@ -248,11 +271,8 @@ static void destroy_fsync_dnodes(struct
+ {
+       struct fsync_inode_entry *entry, *tmp;
+-      list_for_each_entry_safe(entry, tmp, head, list) {
+-              iput(entry->inode);
+-              list_del(&entry->list);
+-              kmem_cache_free(fsync_entry_slab, entry);
+-      }
++      list_for_each_entry_safe(entry, tmp, head, list)
++              del_fsync_inode(entry);
+ }
+ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
+@@ -509,11 +529,8 @@ static int recover_data(struct f2fs_sb_i
+                       break;
+               }
+-              if (entry->blkaddr == blkaddr) {
+-                      iput(entry->inode);
+-                      list_del(&entry->list);
+-                      kmem_cache_free(fsync_entry_slab, entry);
+-              }
++              if (entry->blkaddr == blkaddr)
++                      del_fsync_inode(entry);
+ next:
+               /* check next segment */
+               blkaddr = next_blkaddr_of_node(page);
diff --git a/queue-4.4/f2fs-fix-inode-cache-leak.patch b/queue-4.4/f2fs-fix-inode-cache-leak.patch
new file mode 100644 (file)
index 0000000..65c9b31
--- /dev/null
@@ -0,0 +1,297 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Sat, 7 May 2016 16:15:05 +0800
+Subject: f2fs: fix inode cache leak
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit f61cce5b81f91ba336184008b24baec84afbb3dd upstream.
+
+When testing f2fs with inline_dentry option, generic/342 reports:
+VFS: Busy inodes after unmount of dm-0. Self-destruct in 5 seconds.  Have a nice day...
+
+After rmmod f2fs module, kenrel shows following dmesg:
+ =============================================================================
+ BUG f2fs_inode_cache (Tainted: G           O   ): Objects remaining in f2fs_inode_cache on __kmem_cache_shutdown()
+ -----------------------------------------------------------------------------
+
+ Disabling lock debugging due to kernel taint
+ INFO: Slab 0xf51ca0e0 objects=22 used=1 fp=0xd1e6fc60 flags=0x40004080
+ CPU: 3 PID: 7455 Comm: rmmod Tainted: G    B      O    4.6.0-rc4+ #16
+ Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
+  00000086 00000086 d062fe18 c13a83a0 f51ca0e0 d062fe38 d062fea4 c11c7276
+  c1981040 f51ca0e0 00000016 00000001 d1e6fc60 40004080 656a624f 20737463
+  616d6572 6e696e69 6e692067 66326620 6e695f73 5f65646f 68636163 6e6f2065
+ Call Trace:
+  [<c13a83a0>] dump_stack+0x5f/0x8f
+  [<c11c7276>] slab_err+0x76/0x80
+  [<c11cbfc0>] ? __kmem_cache_shutdown+0x100/0x2f0
+  [<c11cbfc0>] ? __kmem_cache_shutdown+0x100/0x2f0
+  [<c11cbfe5>] __kmem_cache_shutdown+0x125/0x2f0
+  [<c1198a38>] kmem_cache_destroy+0x158/0x1f0
+  [<c176b43d>] ? mutex_unlock+0xd/0x10
+  [<f8f15aa3>] exit_f2fs_fs+0x4b/0x5a8 [f2fs]
+  [<c10f596c>] SyS_delete_module+0x16c/0x1d0
+  [<c1001b10>] ? do_fast_syscall_32+0x30/0x1c0
+  [<c13c59bf>] ? __this_cpu_preempt_check+0xf/0x20
+  [<c10afa7d>] ? trace_hardirqs_on_caller+0xdd/0x210
+  [<c10ad50b>] ? trace_hardirqs_off+0xb/0x10
+  [<c1001b81>] do_fast_syscall_32+0xa1/0x1c0
+  [<c176d888>] sysenter_past_esp+0x45/0x74
+ INFO: Object 0xd1e6d9e0 @offset=6624
+ kmem_cache_destroy f2fs_inode_cache: Slab cache still has objects
+ CPU: 3 PID: 7455 Comm: rmmod Tainted: G    B      O    4.6.0-rc4+ #16
+ Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
+  00000286 00000286 d062fef4 c13a83a0 f174b000 d062ff14 d062ff28 c1198ac7
+  c197fe18 f3c5b980 d062ff20 000d04f2 d062ff0c d062ff0c d062ff14 d062ff14
+  f8f20dc0 fffffff5 d062e000 d062ff30 f8f15aa3 d062ff7c c10f596c 73663266
+ Call Trace:
+  [<c13a83a0>] dump_stack+0x5f/0x8f
+  [<c1198ac7>] kmem_cache_destroy+0x1e7/0x1f0
+  [<f8f15aa3>] exit_f2fs_fs+0x4b/0x5a8 [f2fs]
+  [<c10f596c>] SyS_delete_module+0x16c/0x1d0
+  [<c1001b10>] ? do_fast_syscall_32+0x30/0x1c0
+  [<c13c59bf>] ? __this_cpu_preempt_check+0xf/0x20
+  [<c10afa7d>] ? trace_hardirqs_on_caller+0xdd/0x210
+  [<c10ad50b>] ? trace_hardirqs_off+0xb/0x10
+  [<c1001b81>] do_fast_syscall_32+0xa1/0x1c0
+  [<c176d888>] sysenter_past_esp+0x45/0x74
+
+The reason is: in recovery flow, we use delayed iput mechanism for directory
+which has recovered dentry block. It means the reference of inode will be
+held until last dirty dentry page being writebacked.
+
+But when we mount f2fs with inline_dentry option, during recovery, dirent
+may only be recovered into dir inode page rather than dentry page, so there
+are no chance for us to release inode reference in ->writepage when
+writebacking last dentry page.
+
+We can call paired iget/iput explicityly for inline_dentry case, but for
+non-inline_dentry case, iput will call writeback_single_inode to write all
+data pages synchronously, but during recovery, ->writepages of f2fs skips
+writing all pages, result in losing dirent.
+
+This patch fixes this issue by obsoleting old mechanism, and introduce a
+new dir_list to hold all directory inodes which has recovered datas until
+finishing recovery.
+
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4:
+ - Deleted add_dirty_dir_inode() function is different
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c |   24 ---------------------
+ fs/f2fs/f2fs.h       |    2 -
+ fs/f2fs/recovery.c   |   56 ++++++++++++++++++++++++++++-----------------------
+ 3 files changed, 31 insertions(+), 51 deletions(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -771,24 +771,6 @@ out:
+       f2fs_trace_pid(page);
+ }
+-void add_dirty_dir_inode(struct inode *inode)
+-{
+-      struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+-      struct inode_entry *new =
+-                      f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
+-      int ret = 0;
+-
+-      new->inode = inode;
+-      INIT_LIST_HEAD(&new->list);
+-
+-      spin_lock(&sbi->dir_inode_lock);
+-      ret = __add_dirty_inode(inode, new);
+-      spin_unlock(&sbi->dir_inode_lock);
+-
+-      if (ret)
+-              kmem_cache_free(inode_entry_slab, new);
+-}
+-
+ void remove_dirty_dir_inode(struct inode *inode)
+ {
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+@@ -811,12 +793,6 @@ void remove_dirty_dir_inode(struct inode
+       stat_dec_dirty_dir(sbi);
+       spin_unlock(&sbi->dir_inode_lock);
+       kmem_cache_free(inode_entry_slab, entry);
+-
+-      /* Only from the recovery routine */
+-      if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) {
+-              clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT);
+-              iput(inode);
+-      }
+ }
+ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -1402,7 +1402,6 @@ enum {
+       FI_NO_ALLOC,            /* should not allocate any blocks */
+       FI_FREE_NID,            /* free allocated nide */
+       FI_UPDATE_DIR,          /* should update inode block for consistency */
+-      FI_DELAY_IPUT,          /* used for the recovery */
+       FI_NO_EXTENT,           /* not to use the extent cache */
+       FI_INLINE_XATTR,        /* used for inline xattr */
+       FI_INLINE_DATA,         /* used for inline data*/
+@@ -1828,7 +1827,6 @@ void remove_orphan_inode(struct f2fs_sb_
+ int recover_orphan_inodes(struct f2fs_sb_info *);
+ int get_valid_checkpoint(struct f2fs_sb_info *);
+ void update_dirty_page(struct inode *, struct page *);
+-void add_dirty_dir_inode(struct inode *);
+ void remove_dirty_dir_inode(struct inode *);
+ void sync_dirty_dir_inodes(struct f2fs_sb_info *);
+ void write_checkpoint(struct f2fs_sb_info *, struct cp_control *);
+--- a/fs/f2fs/recovery.c
++++ b/fs/f2fs/recovery.c
+@@ -89,7 +89,8 @@ static void del_fsync_inode(struct fsync
+       kmem_cache_free(fsync_entry_slab, entry);
+ }
+-static int recover_dentry(struct inode *inode, struct page *ipage)
++static int recover_dentry(struct inode *inode, struct page *ipage,
++                                              struct list_head *dir_list)
+ {
+       struct f2fs_inode *raw_inode = F2FS_INODE(ipage);
+       nid_t pino = le32_to_cpu(raw_inode->i_pino);
+@@ -97,18 +98,29 @@ static int recover_dentry(struct inode *
+       struct qstr name;
+       struct page *page;
+       struct inode *dir, *einode;
++      struct fsync_inode_entry *entry;
+       int err = 0;
+-      dir = f2fs_iget(inode->i_sb, pino);
+-      if (IS_ERR(dir)) {
+-              err = PTR_ERR(dir);
+-              goto out;
++      entry = get_fsync_inode(dir_list, pino);
++      if (!entry) {
++              dir = f2fs_iget(inode->i_sb, pino);
++              if (IS_ERR(dir)) {
++                      err = PTR_ERR(dir);
++                      goto out;
++              }
++
++              entry = add_fsync_inode(dir_list, dir);
++              if (!entry) {
++                      err = -ENOMEM;
++                      iput(dir);
++                      goto out;
++              }
+       }
+-      if (file_enc_name(inode)) {
+-              iput(dir);
++      dir = entry->inode;
++
++      if (file_enc_name(inode))
+               return 0;
+-      }
+       name.len = le32_to_cpu(raw_inode->i_namelen);
+       name.name = raw_inode->i_name;
+@@ -116,7 +128,7 @@ static int recover_dentry(struct inode *
+       if (unlikely(name.len > F2FS_NAME_LEN)) {
+               WARN_ON(1);
+               err = -ENAMETOOLONG;
+-              goto out_err;
++              goto out;
+       }
+ retry:
+       de = f2fs_find_entry(dir, &name, &page);
+@@ -142,23 +154,12 @@ retry:
+               goto retry;
+       }
+       err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode);
+-      if (err)
+-              goto out_err;
+-
+-      if (is_inode_flag_set(F2FS_I(dir), FI_DELAY_IPUT)) {
+-              iput(dir);
+-      } else {
+-              add_dirty_dir_inode(dir);
+-              set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT);
+-      }
+       goto out;
+ out_unmap_put:
+       f2fs_dentry_kunmap(dir, page);
+       f2fs_put_page(page, 0);
+-out_err:
+-      iput(dir);
+ out:
+       f2fs_msg(inode->i_sb, KERN_NOTICE,
+                       "%s: ino = %x, name = %s, dir = %lx, err = %d",
+@@ -479,7 +480,8 @@ out:
+       return err;
+ }
+-static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head)
++static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
++                                              struct list_head *dir_list)
+ {
+       unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
+       struct curseg_info *curseg;
+@@ -506,7 +508,7 @@ static int recover_data(struct f2fs_sb_i
+                       break;
+               }
+-              entry = get_fsync_inode(head, ino_of_node(page));
++              entry = get_fsync_inode(inode_list, ino_of_node(page));
+               if (!entry)
+                       goto next;
+               /*
+@@ -517,7 +519,7 @@ static int recover_data(struct f2fs_sb_i
+               if (entry->last_inode == blkaddr)
+                       recover_inode(entry->inode, page);
+               if (entry->last_dentry == blkaddr) {
+-                      err = recover_dentry(entry->inode, page);
++                      err = recover_dentry(entry->inode, page, dir_list);
+                       if (err) {
+                               f2fs_put_page(page, 1);
+                               break;
+@@ -545,6 +547,7 @@ int recover_fsync_data(struct f2fs_sb_in
+ {
+       struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
+       struct list_head inode_list;
++      struct list_head dir_list;
+       block_t blkaddr;
+       int err;
+       int ret = 0;
+@@ -556,6 +559,7 @@ int recover_fsync_data(struct f2fs_sb_in
+               return -ENOMEM;
+       INIT_LIST_HEAD(&inode_list);
++      INIT_LIST_HEAD(&dir_list);
+       /* prevent checkpoint */
+       mutex_lock(&sbi->cp_mutex);
+@@ -575,12 +579,11 @@ int recover_fsync_data(struct f2fs_sb_in
+       need_writecp = true;
+       /* step #2: recover data */
+-      err = recover_data(sbi, &inode_list);
++      err = recover_data(sbi, &inode_list, &dir_list);
+       if (!err)
+               f2fs_bug_on(sbi, !list_empty(&inode_list));
+ out:
+       destroy_fsync_dnodes(&inode_list);
+-      kmem_cache_destroy(fsync_entry_slab);
+       /* truncate meta pages to be used by the recovery */
+       truncate_inode_pages_range(META_MAPPING(sbi),
+@@ -618,5 +621,8 @@ out:
+       } else {
+               mutex_unlock(&sbi->cp_mutex);
+       }
++
++      destroy_fsync_dnodes(&dir_list);
++      kmem_cache_destroy(fsync_entry_slab);
+       return ret ? ret: err;
+ }
diff --git a/queue-4.4/f2fs-fix-invalid-memory-access.patch b/queue-4.4/f2fs-fix-invalid-memory-access.patch
new file mode 100644 (file)
index 0000000..6fb04b4
--- /dev/null
@@ -0,0 +1,165 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Thu, 2 Aug 2018 22:59:12 +0800
+Subject: f2fs: fix invalid memory access
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit d3f07c049dab1a3f1740f476afd3d5e5b738c21c upstream.
+
+syzbot found the following crash on:
+
+HEAD commit:    d9bd94c0bcaa Add linux-next specific files for 20180801
+git tree:       linux-next
+console output: https://syzkaller.appspot.com/x/log.txt?x=1001189c400000
+kernel config:  https://syzkaller.appspot.com/x/.config?x=cc8964ea4d04518c
+dashboard link: https://syzkaller.appspot.com/bug?extid=c966a82db0b14aa37e81
+compiler:       gcc (GCC) 8.0.1 20180413 (experimental)
+
+Unfortunately, I don't have any reproducer for this crash yet.
+
+IMPORTANT: if you fix the bug, please add the following tag to the commit:
+Reported-by: syzbot+c966a82db0b14aa37e81@syzkaller.appspotmail.com
+
+loop7: rw=12288, want=8200, limit=20
+netlink: 65342 bytes leftover after parsing attributes in process `syz-executor4'.
+openvswitch: netlink: Message has 8 unknown bytes.
+kasan: CONFIG_KASAN_INLINE enabled
+kasan: GPF could be caused by NULL-ptr deref or user memory access
+general protection fault: 0000 [#1] SMP KASAN
+CPU: 1 PID: 7615 Comm: syz-executor7 Not tainted 4.18.0-rc7-next-20180801+ #29
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
+RIP: 0010:__read_once_size include/linux/compiler.h:188 [inline]
+RIP: 0010:compound_head include/linux/page-flags.h:142 [inline]
+RIP: 0010:PageLocked include/linux/page-flags.h:272 [inline]
+RIP: 0010:f2fs_put_page fs/f2fs/f2fs.h:2011 [inline]
+RIP: 0010:validate_checkpoint+0x66d/0xec0 fs/f2fs/checkpoint.c:835
+Code: e8 58 05 7f fe 4c 8d 6b 80 4d 8d 74 24 08 48 b8 00 00 00 00 00 fc ff df 4c 89 ea 48 c1 ea 03 c6 04 02 00 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 f4 06 00 00 4c 89 ea 4d 8b 7c 24 08 48 b8 00 00
+RSP: 0018:ffff8801937cebe8 EFLAGS: 00010246
+RAX: dffffc0000000000 RBX: ffff8801937cef30 RCX: ffffc90006035000
+RDX: 0000000000000000 RSI: ffffffff82fd9658 RDI: 0000000000000005
+RBP: ffff8801937cef58 R08: ffff8801ab254700 R09: fffff94000d9e026
+R10: fffff94000d9e026 R11: ffffea0006cf0137 R12: fffffffffffffffb
+R13: ffff8801937ceeb0 R14: 0000000000000003 R15: ffff880193419b40
+FS:  00007f36a61d5700(0000) GS:ffff8801db100000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 00007fc04ff93000 CR3: 00000001d0562000 CR4: 00000000001426e0
+DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+Call Trace:
+ f2fs_get_valid_checkpoint+0x436/0x1ec0 fs/f2fs/checkpoint.c:860
+ f2fs_fill_super+0x2d42/0x8110 fs/f2fs/super.c:2883
+ mount_bdev+0x314/0x3e0 fs/super.c:1344
+ f2fs_mount+0x3c/0x50 fs/f2fs/super.c:3133
+ legacy_get_tree+0x131/0x460 fs/fs_context.c:729
+ vfs_get_tree+0x1cb/0x5c0 fs/super.c:1743
+ do_new_mount fs/namespace.c:2603 [inline]
+ do_mount+0x6f2/0x1e20 fs/namespace.c:2927
+ ksys_mount+0x12d/0x140 fs/namespace.c:3143
+ __do_sys_mount fs/namespace.c:3157 [inline]
+ __se_sys_mount fs/namespace.c:3154 [inline]
+ __x64_sys_mount+0xbe/0x150 fs/namespace.c:3154
+ do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290
+ entry_SYSCALL_64_after_hwframe+0x49/0xbe
+RIP: 0033:0x45943a
+Code: b8 a6 00 00 00 0f 05 48 3d 01 f0 ff ff 0f 83 bd 8a fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 49 89 ca b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 0f 83 9a 8a fb ff c3 66 0f 1f 84 00 00 00 00 00
+RSP: 002b:00007f36a61d4a88 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5
+RAX: ffffffffffffffda RBX: 00007f36a61d4b30 RCX: 000000000045943a
+RDX: 00007f36a61d4ad0 RSI: 0000000020000100 RDI: 00007f36a61d4af0
+RBP: 0000000020000100 R08: 00007f36a61d4b30 R09: 00007f36a61d4ad0
+R10: 0000000000000000 R11: 0000000000000206 R12: 0000000000000013
+R13: 0000000000000000 R14: 00000000004c8ea0 R15: 0000000000000000
+Modules linked in:
+Dumping ftrace buffer:
+   (ftrace buffer empty)
+---[ end trace bd8550c129352286 ]---
+RIP: 0010:__read_once_size include/linux/compiler.h:188 [inline]
+RIP: 0010:compound_head include/linux/page-flags.h:142 [inline]
+RIP: 0010:PageLocked include/linux/page-flags.h:272 [inline]
+RIP: 0010:f2fs_put_page fs/f2fs/f2fs.h:2011 [inline]
+RIP: 0010:validate_checkpoint+0x66d/0xec0 fs/f2fs/checkpoint.c:835
+Code: e8 58 05 7f fe 4c 8d 6b 80 4d 8d 74 24 08 48 b8 00 00 00 00 00 fc ff df 4c 89 ea 48 c1 ea 03 c6 04 02 00 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 f4 06 00 00 4c 89 ea 4d 8b 7c 24 08 48 b8 00 00
+RSP: 0018:ffff8801937cebe8 EFLAGS: 00010246
+RAX: dffffc0000000000 RBX: ffff8801937cef30 RCX: ffffc90006035000
+RDX: 0000000000000000 RSI: ffffffff82fd9658 RDI: 0000000000000005
+netlink: 65342 bytes leftover after parsing attributes in process `syz-executor4'.
+RBP: ffff8801937cef58 R08: ffff8801ab254700 R09: fffff94000d9e026
+openvswitch: netlink: Message has 8 unknown bytes.
+R10: fffff94000d9e026 R11: ffffea0006cf0137 R12: fffffffffffffffb
+R13: ffff8801937ceeb0 R14: 0000000000000003 R15: ffff880193419b40
+FS:  00007f36a61d5700(0000) GS:ffff8801db100000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 00007fc04ff93000 CR3: 00000001d0562000 CR4: 00000000001426e0
+DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+
+In validate_checkpoint(), if we failed to call get_checkpoint_version(), we
+will pass returned invalid page pointer into f2fs_put_page, cause accessing
+invalid memory, this patch tries to handle error path correctly to fix this
+issue.
+
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c |   11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -631,6 +631,7 @@ static int get_checkpoint_version(struct
+       crc_offset = le32_to_cpu((*cp_block)->checksum_offset);
+       if (crc_offset >= blk_size) {
++              f2fs_put_page(*cp_page, 1);
+               f2fs_msg(sbi->sb, KERN_WARNING,
+                       "invalid crc_offset: %zu", crc_offset);
+               return -EINVAL;
+@@ -639,6 +640,7 @@ static int get_checkpoint_version(struct
+       crc = le32_to_cpu(*((__le32 *)((unsigned char *)*cp_block
+                                                       + crc_offset)));
+       if (!f2fs_crc_valid(crc, *cp_block, crc_offset)) {
++              f2fs_put_page(*cp_page, 1);
+               f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
+               return -EINVAL;
+       }
+@@ -658,14 +660,14 @@ static struct page *validate_checkpoint(
+       err = get_checkpoint_version(sbi, cp_addr, &cp_block,
+                                       &cp_page_1, version);
+       if (err)
+-              goto invalid_cp1;
++              return NULL;
+       if (le32_to_cpu(cp_block->cp_pack_total_block_count) >
+                                       sbi->blocks_per_seg) {
+               f2fs_msg(sbi->sb, KERN_WARNING,
+                       "invalid cp_pack_total_block_count:%u",
+                       le32_to_cpu(cp_block->cp_pack_total_block_count));
+-              goto invalid_cp1;
++              goto invalid_cp;
+       }
+       pre_version = *version;
+@@ -673,7 +675,7 @@ static struct page *validate_checkpoint(
+       err = get_checkpoint_version(sbi, cp_addr, &cp_block,
+                                       &cp_page_2, version);
+       if (err)
+-              goto invalid_cp2;
++              goto invalid_cp;
+       cur_version = *version;
+       if (cur_version == pre_version) {
+@@ -681,9 +683,8 @@ static struct page *validate_checkpoint(
+               f2fs_put_page(cp_page_2, 1);
+               return cp_page_1;
+       }
+-invalid_cp2:
+       f2fs_put_page(cp_page_2, 1);
+-invalid_cp1:
++invalid_cp:
+       f2fs_put_page(cp_page_1, 1);
+       return NULL;
+ }
diff --git a/queue-4.4/f2fs-fix-missing-up_read.patch b/queue-4.4/f2fs-fix-missing-up_read.patch
new file mode 100644 (file)
index 0000000..2be64dd
--- /dev/null
@@ -0,0 +1,34 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Thu, 27 Sep 2018 22:15:31 -0700
+Subject: f2fs: fix missing up_read
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit 89d13c38501df730cbb2e02c4499da1b5187119d upstream.
+
+This patch fixes missing up_read call.
+
+Fixes: c9b60788fc76 ("f2fs: fix to do sanity check with block address in main area")
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/node.c |    4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/fs/f2fs/node.c
++++ b/fs/f2fs/node.c
+@@ -1342,8 +1342,10 @@ static int f2fs_write_node_page(struct p
+       }
+       if (__is_valid_data_blkaddr(ni.blk_addr) &&
+-              !f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC))
++              !f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) {
++              up_read(&sbi->node_write);
+               goto redirty_out;
++      }
+       set_page_writeback(page);
+       fio.blk_addr = ni.blk_addr;
diff --git a/queue-4.4/f2fs-fix-race-condition-in-between-free-nid-allocator-initializer.patch b/queue-4.4/f2fs-fix-race-condition-in-between-free-nid-allocator-initializer.patch
new file mode 100644 (file)
index 0000000..6ab86e5
--- /dev/null
@@ -0,0 +1,137 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Wed, 22 Mar 2017 14:45:05 +0800
+Subject: f2fs: fix race condition in between free nid allocator/initializer
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit 30a61ddf8117c26ac5b295e1233eaa9629a94ca3 upstream.
+
+In below concurrent case, allocated nid can be loaded into free nid cache
+and be allocated again.
+
+Thread A                               Thread B
+- f2fs_create
+ - f2fs_new_inode
+  - alloc_nid
+   - __insert_nid_to_list(ALLOC_NID_LIST)
+                                       - f2fs_balance_fs_bg
+                                        - build_free_nids
+                                         - __build_free_nids
+                                          - scan_nat_page
+                                           - add_free_nid
+                                            - __lookup_nat_cache
+ - f2fs_add_link
+  - init_inode_metadata
+   - new_inode_page
+    - new_node_page
+     - set_node_addr
+ - alloc_nid_done
+  - __remove_nid_from_list(ALLOC_NID_LIST)
+                                            - __insert_nid_to_list(FREE_NID_LIST)
+
+This patch makes nat cache lookup and free nid list operation being atomical
+to avoid this race condition.
+
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4:
+ - add_free_nid() returns 0 in case of any error (except low memory)
+ - Tree/list addition has not been moved into __insert_nid_to_list()]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/node.c |   62 +++++++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 43 insertions(+), 19 deletions(-)
+
+--- a/fs/f2fs/node.c
++++ b/fs/f2fs/node.c
+@@ -1428,8 +1428,9 @@ static void __del_from_free_nid_list(str
+ static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
+ {
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+-      struct free_nid *i;
++      struct free_nid *i, *e;
+       struct nat_entry *ne;
++      int err = -EINVAL;
+       if (!available_free_memory(sbi, FREE_NIDS))
+               return -1;
+@@ -1438,35 +1439,58 @@ static int add_free_nid(struct f2fs_sb_i
+       if (unlikely(nid == 0))
+               return 0;
+-      if (build) {
+-              /* do not add allocated nids */
+-              ne = __lookup_nat_cache(nm_i, nid);
+-              if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
+-                              nat_get_blkaddr(ne) != NULL_ADDR))
+-                      return 0;
+-      }
+-
+       i = f2fs_kmem_cache_alloc(free_nid_slab, GFP_NOFS);
+       i->nid = nid;
+       i->state = NID_NEW;
+-      if (radix_tree_preload(GFP_NOFS)) {
+-              kmem_cache_free(free_nid_slab, i);
+-              return 0;
+-      }
++      if (radix_tree_preload(GFP_NOFS))
++              goto err;
+       spin_lock(&nm_i->free_nid_list_lock);
+-      if (radix_tree_insert(&nm_i->free_nid_root, i->nid, i)) {
+-              spin_unlock(&nm_i->free_nid_list_lock);
+-              radix_tree_preload_end();
+-              kmem_cache_free(free_nid_slab, i);
+-              return 0;
++
++      if (build) {
++              /*
++               *   Thread A             Thread B
++               *  - f2fs_create
++               *   - f2fs_new_inode
++               *    - alloc_nid
++               *     - __insert_nid_to_list(ALLOC_NID_LIST)
++               *                     - f2fs_balance_fs_bg
++               *                      - build_free_nids
++               *                       - __build_free_nids
++               *                        - scan_nat_page
++               *                         - add_free_nid
++               *                          - __lookup_nat_cache
++               *  - f2fs_add_link
++               *   - init_inode_metadata
++               *    - new_inode_page
++               *     - new_node_page
++               *      - set_node_addr
++               *  - alloc_nid_done
++               *   - __remove_nid_from_list(ALLOC_NID_LIST)
++               *                         - __insert_nid_to_list(FREE_NID_LIST)
++               */
++              ne = __lookup_nat_cache(nm_i, nid);
++              if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
++                              nat_get_blkaddr(ne) != NULL_ADDR))
++                      goto err_out;
++
++              e = __lookup_free_nid_list(nm_i, nid);
++              if (e)
++                      goto err_out;
+       }
++      if (radix_tree_insert(&nm_i->free_nid_root, i->nid, i))
++              goto err_out;
++      err = 0;
+       list_add_tail(&i->list, &nm_i->free_nid_list);
+       nm_i->fcnt++;
++err_out:
+       spin_unlock(&nm_i->free_nid_list_lock);
+       radix_tree_preload_end();
+-      return 1;
++err:
++      if (err)
++              kmem_cache_free(free_nid_slab, i);
++      return !err;
+ }
+ static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid)
diff --git a/queue-4.4/f2fs-fix-to-avoid-reading-out-encrypted-data-in-page-cache.patch b/queue-4.4/f2fs-fix-to-avoid-reading-out-encrypted-data-in-page-cache.patch
new file mode 100644 (file)
index 0000000..b813ae2
--- /dev/null
@@ -0,0 +1,173 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Sun, 3 Jul 2016 22:05:11 +0800
+Subject: f2fs: fix to avoid reading out encrypted data in page cache
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit 78682f79447998369a85f12b6437fa8fdbbdca50 upstream.
+
+For encrypted inode, if user overwrites data of the inode, f2fs will read
+encrypted data into page cache, and then do the decryption.
+
+However reader can race with overwriter, and it will see encrypted data
+which has not been decrypted by overwriter yet. Fix it by moving decrypting
+work to background and keep page non-uptodated until data is decrypted.
+
+Thread A                               Thread B
+- f2fs_file_write_iter
+ - __generic_file_write_iter
+  - generic_perform_write
+   - f2fs_write_begin
+    - f2fs_submit_page_bio
+                                       - generic_file_read_iter
+                                        - do_generic_file_read
+                                         - lock_page_killable
+                                         - unlock_page
+                                         - copy_page_to_iter
+                                         hit the encrypted data in updated page
+    - lock_page
+    - fscrypt_decrypt_page
+
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4:
+ - Keep using f2fs_crypto functions instead of generic fscrypt API
+ - Use PAGE_CACHE_SIZE instead of PAGE_SIZE
+ - Use submit_bio() instead of __submit_bio()
+ - In f2fs_write_begin(), use dn.data_blkaddr instead of blkaddr
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/data.c |   89 ++++++++++++++++++++++++++++++---------------------------
+ 1 file changed, 47 insertions(+), 42 deletions(-)
+
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -866,6 +866,37 @@ out:
+       return ret;
+ }
++struct bio *f2fs_grab_bio(struct inode *inode, block_t blkaddr,
++                                                      unsigned nr_pages)
++{
++      struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
++      struct f2fs_crypto_ctx *ctx = NULL;
++      struct block_device *bdev = sbi->sb->s_bdev;
++      struct bio *bio;
++
++      if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
++              ctx = f2fs_get_crypto_ctx(inode);
++              if (IS_ERR(ctx))
++                      return ERR_CAST(ctx);
++
++              /* wait the page to be moved by cleaning */
++              f2fs_wait_on_encrypted_page_writeback(sbi, blkaddr);
++      }
++
++      bio = bio_alloc(GFP_KERNEL, min_t(int, nr_pages, BIO_MAX_PAGES));
++      if (!bio) {
++              if (ctx)
++                      f2fs_release_crypto_ctx(ctx);
++              return ERR_PTR(-ENOMEM);
++      }
++      bio->bi_bdev = bdev;
++      bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(blkaddr);
++      bio->bi_end_io = f2fs_read_end_io;
++      bio->bi_private = ctx;
++
++      return bio;
++}
++
+ /*
+  * This function was originally taken from fs/mpage.c, and customized for f2fs.
+  * Major change was from block_size == page_size in f2fs by default.
+@@ -884,7 +915,6 @@ static int f2fs_mpage_readpages(struct a
+       sector_t last_block;
+       sector_t last_block_in_file;
+       sector_t block_nr;
+-      struct block_device *bdev = inode->i_sb->s_bdev;
+       struct f2fs_map_blocks map;
+       map.m_pblk = 0;
+@@ -958,31 +988,9 @@ submit_and_realloc:
+                       bio = NULL;
+               }
+               if (bio == NULL) {
+-                      struct f2fs_crypto_ctx *ctx = NULL;
+-
+-                      if (f2fs_encrypted_inode(inode) &&
+-                                      S_ISREG(inode->i_mode)) {
+-
+-                              ctx = f2fs_get_crypto_ctx(inode);
+-                              if (IS_ERR(ctx))
+-                                      goto set_error_page;
+-
+-                              /* wait the page to be moved by cleaning */
+-                              f2fs_wait_on_encrypted_page_writeback(
+-                                              F2FS_I_SB(inode), block_nr);
+-                      }
+-
+-                      bio = bio_alloc(GFP_KERNEL,
+-                              min_t(int, nr_pages, BIO_MAX_PAGES));
+-                      if (!bio) {
+-                              if (ctx)
+-                                      f2fs_release_crypto_ctx(ctx);
++                      bio = f2fs_grab_bio(inode, block_nr, nr_pages);
++                      if (IS_ERR(bio))
+                               goto set_error_page;
+-                      }
+-                      bio->bi_bdev = bdev;
+-                      bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(block_nr);
+-                      bio->bi_end_io = f2fs_read_end_io;
+-                      bio->bi_private = ctx;
+               }
+               if (bio_add_page(bio, page, blocksize, 0) < blocksize)
+@@ -1482,17 +1490,21 @@ put_next:
+       if (dn.data_blkaddr == NEW_ADDR) {
+               zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+       } else {
+-              struct f2fs_io_info fio = {
+-                      .sbi = sbi,
+-                      .type = DATA,
+-                      .rw = READ_SYNC,
+-                      .blk_addr = dn.data_blkaddr,
+-                      .page = page,
+-                      .encrypted_page = NULL,
+-              };
+-              err = f2fs_submit_page_bio(&fio);
+-              if (err)
++              struct bio *bio;
++
++              bio = f2fs_grab_bio(inode, dn.data_blkaddr, 1);
++              if (IS_ERR(bio)) {
++                      err = PTR_ERR(bio);
++                      goto fail;
++              }
++
++              if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) {
++                      bio_put(bio);
++                      err = -EFAULT;
+                       goto fail;
++              }
++
++              submit_bio(READ_SYNC, bio);
+               lock_page(page);
+               if (unlikely(!PageUptodate(page))) {
+@@ -1503,13 +1515,6 @@ put_next:
+                       f2fs_put_page(page, 1);
+                       goto repeat;
+               }
+-
+-              /* avoid symlink page */
+-              if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
+-                      err = f2fs_decrypt_one(inode, page);
+-                      if (err)
+-                              goto fail;
+-              }
+       }
+ out_update:
+       SetPageUptodate(page);
diff --git a/queue-4.4/f2fs-fix-to-convert-inline-directory-correctly.patch b/queue-4.4/f2fs-fix-to-convert-inline-directory-correctly.patch
new file mode 100644 (file)
index 0000000..2fce29f
--- /dev/null
@@ -0,0 +1,370 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <chao2.yu@samsung.com>
+Date: Mon, 22 Feb 2016 18:29:18 +0800
+Subject: f2fs: fix to convert inline directory correctly
+
+From: Chao Yu <chao2.yu@samsung.com>
+
+With below serials, we will lose parts of dirents:
+
+1) mount f2fs with inline_dentry option
+2) echo 1 > /sys/fs/f2fs/sdX/dir_level
+3) mkdir dir
+4) touch 180 files named [1-180] in dir
+5) touch 181 in dir
+6) echo 3 > /proc/sys/vm/drop_caches
+7) ll dir
+
+ls: cannot access 2: No such file or directory
+ls: cannot access 4: No such file or directory
+ls: cannot access 5: No such file or directory
+ls: cannot access 6: No such file or directory
+ls: cannot access 8: No such file or directory
+ls: cannot access 9: No such file or directory
+...
+total 360
+drwxr-xr-x 2 root root 4096 Feb 19 15:12 ./
+drwxr-xr-x 3 root root 4096 Feb 19 15:11 ../
+-rw-r--r-- 1 root root    0 Feb 19 15:12 1
+-rw-r--r-- 1 root root    0 Feb 19 15:12 10
+-rw-r--r-- 1 root root    0 Feb 19 15:12 100
+-????????? ? ?    ?       ?            ? 101
+-????????? ? ?    ?       ?            ? 102
+-????????? ? ?    ?       ?            ? 103
+...
+
+The reason is: when doing the inline dir conversion, we didn't consider
+that directory has hierarchical hash structure which can be configured
+through sysfs interface 'dir_level'.
+
+By default, dir_level of directory inode is 0, it means we have one bucket
+in hash table located in first level, all dirents will be hashed in this
+bucket, so it has no problem for us to do the duplication simply between
+inline dentry page and converted normal dentry page.
+
+However, if we configured dir_level with the value N (greater than 0), it
+will expand the bucket number of first level hash table by 2^N - 1, it
+hashs dirents into different buckets according their hash value, if we
+still move all dirents to first bucket, it makes incorrent locating for
+inline dirents, the result is, although we can iterate all dirents through
+->readdir, we can't stat some of them in ->lookup which based on hash
+table searching.
+
+This patch fixes this issue by rehashing dirents into correct position
+when converting inline directory.
+
+Signed-off-by: Chao Yu <chao2.yu@samsung.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4:
+ - Keep using f2fs_crypto functions instead of generic fscrypt API
+ - Use remove_dirty_dir_inode() instead of remove_dirty_inode()
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/dir.c           |   87 +++++++++++++++++++++++---------------------
+ fs/f2fs/f2fs.h          |    4 +-
+ fs/f2fs/inline.c        |   94 +++++++++++++++++++++++++++++++++++++++++++++++-
+ include/linux/f2fs_fs.h |    2 +
+ 4 files changed, 144 insertions(+), 43 deletions(-)
+
+--- a/fs/f2fs/dir.c
++++ b/fs/f2fs/dir.c
+@@ -48,7 +48,6 @@ unsigned char f2fs_filetype_table[F2FS_F
+       [F2FS_FT_SYMLINK]       = DT_LNK,
+ };
+-#define S_SHIFT 12
+ static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = {
+       [S_IFREG >> S_SHIFT]    = F2FS_FT_REG_FILE,
+       [S_IFDIR >> S_SHIFT]    = F2FS_FT_DIR,
+@@ -64,6 +63,13 @@ void set_de_type(struct f2fs_dir_entry *
+       de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
+ }
++unsigned char get_de_type(struct f2fs_dir_entry *de)
++{
++      if (de->file_type < F2FS_FT_MAX)
++              return f2fs_filetype_table[de->file_type];
++      return DT_UNKNOWN;
++}
++
+ static unsigned long dir_block_index(unsigned int level,
+                               int dir_level, unsigned int idx)
+ {
+@@ -519,11 +525,7 @@ void f2fs_update_dentry(nid_t ino, umode
+               test_and_set_bit_le(bit_pos + i, (void *)d->bitmap);
+ }
+-/*
+- * Caller should grab and release a rwsem by calling f2fs_lock_op() and
+- * f2fs_unlock_op().
+- */
+-int __f2fs_add_link(struct inode *dir, const struct qstr *name,
++int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
+                               struct inode *inode, nid_t ino, umode_t mode)
+ {
+       unsigned int bit_pos;
+@@ -536,28 +538,11 @@ int __f2fs_add_link(struct inode *dir, c
+       struct f2fs_dentry_block *dentry_blk = NULL;
+       struct f2fs_dentry_ptr d;
+       struct page *page = NULL;
+-      struct f2fs_filename fname;
+-      struct qstr new_name;
+-      int slots, err;
+-
+-      err = f2fs_fname_setup_filename(dir, name, 0, &fname);
+-      if (err)
+-              return err;
+-
+-      new_name.name = fname_name(&fname);
+-      new_name.len = fname_len(&fname);
+-
+-      if (f2fs_has_inline_dentry(dir)) {
+-              err = f2fs_add_inline_entry(dir, &new_name, inode, ino, mode);
+-              if (!err || err != -EAGAIN)
+-                      goto out;
+-              else
+-                      err = 0;
+-      }
++      int slots, err = 0;
+       level = 0;
+-      slots = GET_DENTRY_SLOTS(new_name.len);
+-      dentry_hash = f2fs_dentry_hash(&new_name, NULL);
++      slots = GET_DENTRY_SLOTS(new_name->len);
++      dentry_hash = f2fs_dentry_hash(new_name, NULL);
+       current_depth = F2FS_I(dir)->i_current_depth;
+       if (F2FS_I(dir)->chash == dentry_hash) {
+@@ -566,10 +551,8 @@ int __f2fs_add_link(struct inode *dir, c
+       }
+ start:
+-      if (unlikely(current_depth == MAX_DIR_HASH_DEPTH)) {
+-              err = -ENOSPC;
+-              goto out;
+-      }
++      if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))
++              return -ENOSPC;
+       /* Increase the depth, if required */
+       if (level == current_depth)
+@@ -583,10 +566,8 @@ start:
+       for (block = bidx; block <= (bidx + nblock - 1); block++) {
+               dentry_page = get_new_data_page(dir, NULL, block, true);
+-              if (IS_ERR(dentry_page)) {
+-                      err = PTR_ERR(dentry_page);
+-                      goto out;
+-              }
++              if (IS_ERR(dentry_page))
++                      return PTR_ERR(dentry_page);
+               dentry_blk = kmap(dentry_page);
+               bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
+@@ -606,7 +587,7 @@ add_dentry:
+       if (inode) {
+               down_write(&F2FS_I(inode)->i_sem);
+-              page = init_inode_metadata(inode, dir, &new_name, NULL);
++              page = init_inode_metadata(inode, dir, new_name, NULL);
+               if (IS_ERR(page)) {
+                       err = PTR_ERR(page);
+                       goto fail;
+@@ -616,7 +597,7 @@ add_dentry:
+       }
+       make_dentry_ptr(NULL, &d, (void *)dentry_blk, 1);
+-      f2fs_update_dentry(ino, mode, &d, &new_name, dentry_hash, bit_pos);
++      f2fs_update_dentry(ino, mode, &d, new_name, dentry_hash, bit_pos);
+       set_page_dirty(dentry_page);
+@@ -638,7 +619,34 @@ fail:
+       }
+       kunmap(dentry_page);
+       f2fs_put_page(dentry_page, 1);
+-out:
++
++      return err;
++}
++
++/*
++ * Caller should grab and release a rwsem by calling f2fs_lock_op() and
++ * f2fs_unlock_op().
++ */
++int __f2fs_add_link(struct inode *dir, const struct qstr *name,
++                              struct inode *inode, nid_t ino, umode_t mode)
++{
++      struct f2fs_filename fname;
++      struct qstr new_name;
++      int err;
++
++      err = f2fs_fname_setup_filename(dir, name, 0, &fname);
++      if (err)
++              return err;
++
++      new_name.name = fname_name(&fname);
++      new_name.len = fname_len(&fname);
++
++      err = -EAGAIN;
++      if (f2fs_has_inline_dentry(dir))
++              err = f2fs_add_inline_entry(dir, &new_name, inode, ino, mode);
++      if (err == -EAGAIN)
++              err = f2fs_add_regular_entry(dir, &new_name, inode, ino, mode);
++
+       f2fs_fname_free_filename(&fname);
+       return err;
+ }
+@@ -792,10 +800,7 @@ bool f2fs_fill_dentries(struct dir_conte
+                       break;
+               de = &d->dentry[bit_pos];
+-              if (de->file_type < F2FS_FT_MAX)
+-                      d_type = f2fs_filetype_table[de->file_type];
+-              else
+-                      d_type = DT_UNKNOWN;
++              d_type = get_de_type(de);
+               de_name.name = d->filename[bit_pos];
+               de_name.len = le16_to_cpu(de->name_len);
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -1677,7 +1677,7 @@ struct dentry *f2fs_get_parent(struct de
+  */
+ extern unsigned char f2fs_filetype_table[F2FS_FT_MAX];
+ void set_de_type(struct f2fs_dir_entry *, umode_t);
+-
++unsigned char get_de_type(struct f2fs_dir_entry *);
+ struct f2fs_dir_entry *find_target_dentry(struct f2fs_filename *,
+                       f2fs_hash_t, int *, struct f2fs_dentry_ptr *);
+ bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *,
+@@ -1698,6 +1698,8 @@ void f2fs_set_link(struct inode *, struc
+ int update_dent_inode(struct inode *, struct inode *, const struct qstr *);
+ void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *,
+                       const struct qstr *, f2fs_hash_t , unsigned int);
++int f2fs_add_regular_entry(struct inode *, const struct qstr *,
++                                              struct inode *, nid_t, umode_t);
+ int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *, nid_t,
+                       umode_t);
+ void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *,
+--- a/fs/f2fs/inline.c
++++ b/fs/f2fs/inline.c
+@@ -367,7 +367,7 @@ int make_empty_inline_dir(struct inode *
+  * NOTE: ipage is grabbed by caller, but if any error occurs, we should
+  * release ipage in this function.
+  */
+-static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
++static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
+                               struct f2fs_inline_dentry *inline_dentry)
+ {
+       struct page *page;
+@@ -428,6 +428,98 @@ out:
+       return err;
+ }
++static int f2fs_add_inline_entries(struct inode *dir,
++                      struct f2fs_inline_dentry *inline_dentry)
++{
++      struct f2fs_dentry_ptr d;
++      unsigned long bit_pos = 0;
++      int err = 0;
++
++      make_dentry_ptr(NULL, &d, (void *)inline_dentry, 2);
++
++      while (bit_pos < d.max) {
++              struct f2fs_dir_entry *de;
++              struct qstr new_name;
++              nid_t ino;
++              umode_t fake_mode;
++
++              if (!test_bit_le(bit_pos, d.bitmap)) {
++                      bit_pos++;
++                      continue;
++              }
++
++              de = &d.dentry[bit_pos];
++              new_name.name = d.filename[bit_pos];
++              new_name.len = de->name_len;
++
++              ino = le32_to_cpu(de->ino);
++              fake_mode = get_de_type(de) << S_SHIFT;
++
++              err = f2fs_add_regular_entry(dir, &new_name, NULL,
++                                                      ino, fake_mode);
++              if (err)
++                      goto punch_dentry_pages;
++
++              if (unlikely(!de->name_len))
++                      d.max = -1;
++
++              bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
++      }
++      return 0;
++punch_dentry_pages:
++      truncate_inode_pages(&dir->i_data, 0);
++      truncate_blocks(dir, 0, false);
++      remove_dirty_dir_inode(dir);
++      return err;
++}
++
++static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage,
++                              struct f2fs_inline_dentry *inline_dentry)
++{
++      struct f2fs_inline_dentry *backup_dentry;
++      int err;
++
++      backup_dentry = kmalloc(sizeof(struct f2fs_inline_dentry),
++                                                      GFP_F2FS_ZERO);
++      if (!backup_dentry)
++              return -ENOMEM;
++
++      memcpy(backup_dentry, inline_dentry, MAX_INLINE_DATA);
++      truncate_inline_inode(ipage, 0);
++
++      unlock_page(ipage);
++
++      err = f2fs_add_inline_entries(dir, backup_dentry);
++      if (err)
++              goto recover;
++
++      lock_page(ipage);
++
++      stat_dec_inline_dir(dir);
++      clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY);
++      update_inode(dir, ipage);
++      kfree(backup_dentry);
++      return 0;
++recover:
++      lock_page(ipage);
++      memcpy(inline_dentry, backup_dentry, MAX_INLINE_DATA);
++      i_size_write(dir, MAX_INLINE_DATA);
++      update_inode(dir, ipage);
++      f2fs_put_page(ipage, 1);
++
++      kfree(backup_dentry);
++      return err;
++}
++
++static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
++                              struct f2fs_inline_dentry *inline_dentry)
++{
++      if (!F2FS_I(dir)->i_dir_level)
++              return f2fs_move_inline_dirents(dir, ipage, inline_dentry);
++      else
++              return f2fs_move_rehashed_dirents(dir, ipage, inline_dentry);
++}
++
+ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
+                       struct inode *inode, nid_t ino, umode_t mode)
+ {
+--- a/include/linux/f2fs_fs.h
++++ b/include/linux/f2fs_fs.h
+@@ -497,4 +497,6 @@ enum {
+       F2FS_FT_MAX
+ };
++#define S_SHIFT 12
++
+ #endif  /* _LINUX_F2FS_FS_H */
diff --git a/queue-4.4/f2fs-fix-to-determine-start_cp_addr-by-sbi-cur_cp_pack.patch b/queue-4.4/f2fs-fix-to-determine-start_cp_addr-by-sbi-cur_cp_pack.patch
new file mode 100644 (file)
index 0000000..e907d96
--- /dev/null
@@ -0,0 +1,100 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Thu, 24 Nov 2016 12:45:15 -0800
+Subject: f2fs: fix to determine start_cp_addr by sbi->cur_cp_pack
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit 8508e44ae98622f841f5ef29d0bf3d5db4e0c1cc upstream.
+
+We don't guarantee cp_addr is fixed by cp_version.
+This is to sync with f2fs-tools.
+
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c |    8 +++++++-
+ fs/f2fs/f2fs.h       |   26 ++++++++++++++++----------
+ 2 files changed, 23 insertions(+), 11 deletions(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -710,6 +710,11 @@ int get_valid_checkpoint(struct f2fs_sb_
+       if (sanity_check_ckpt(sbi))
+               goto fail_no_cp;
++      if (cur_page == cp1)
++              sbi->cur_cp_pack = 1;
++      else
++              sbi->cur_cp_pack = 2;
++
+       if (cp_blks <= 1)
+               goto done;
+@@ -1008,7 +1013,7 @@ static void do_checkpoint(struct f2fs_sb
+                               le32_to_cpu(ckpt->checksum_offset)))
+                               = cpu_to_le32(crc32);
+-      start_blk = __start_cp_addr(sbi);
++      start_blk = __start_cp_next_addr(sbi);
+       /* need to wait for end_io results */
+       wait_on_all_pages_writeback(sbi);
+@@ -1063,6 +1068,7 @@ static void do_checkpoint(struct f2fs_sb
+       clear_prefree_segments(sbi, cpc);
+       clear_sbi_flag(sbi, SBI_IS_DIRTY);
++      __set_cp_next_pack(sbi);
+ }
+ /*
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -731,6 +731,7 @@ struct f2fs_sb_info {
+       /* for checkpoint */
+       struct f2fs_checkpoint *ckpt;           /* raw checkpoint pointer */
++      int cur_cp_pack;                        /* remain current cp pack */
+       struct inode *meta_inode;               /* cache meta blocks */
+       struct mutex cp_mutex;                  /* checkpoint procedure lock */
+       struct rw_semaphore cp_rwsem;           /* blocking FS operations */
+@@ -1140,22 +1141,27 @@ static inline void *__bitmap_ptr(struct
+ static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi)
+ {
+-      block_t start_addr;
+-      struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+-      unsigned long long ckpt_version = cur_cp_version(ckpt);
+-
+-      start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
++      block_t start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
+-      /*
+-       * odd numbered checkpoint should at cp segment 0
+-       * and even segment must be at cp segment 1
+-       */
+-      if (!(ckpt_version & 1))
++      if (sbi->cur_cp_pack == 2)
+               start_addr += sbi->blocks_per_seg;
++      return start_addr;
++}
++static inline block_t __start_cp_next_addr(struct f2fs_sb_info *sbi)
++{
++      block_t start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
++
++      if (sbi->cur_cp_pack == 1)
++              start_addr += sbi->blocks_per_seg;
+       return start_addr;
+ }
++static inline void __set_cp_next_pack(struct f2fs_sb_info *sbi)
++{
++      sbi->cur_cp_pack = (sbi->cur_cp_pack == 1) ? 2 : 1;
++}
++
+ static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi)
+ {
+       return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum);
diff --git a/queue-4.4/f2fs-fix-to-do-sanity-check-with-block-address-in-main-area-v2.patch b/queue-4.4/f2fs-fix-to-do-sanity-check-with-block-address-in-main-area-v2.patch
new file mode 100644 (file)
index 0000000..2078ff3
--- /dev/null
@@ -0,0 +1,365 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Tue, 10 Jul 2018 23:01:45 +0800
+Subject: f2fs: fix to do sanity check with block address in main area v2
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit 91291e9998d208370eb8156c760691b873bd7522 upstream.
+
+This patch adds f2fs_is_valid_blkaddr() in below functions to do sanity
+check with block address to avoid pentential panic:
+- f2fs_grab_read_bio()
+- __written_first_block()
+
+https://bugzilla.kernel.org/show_bug.cgi?id=200465
+
+- Reproduce
+
+- POC (poc.c)
+    #define _GNU_SOURCE
+    #include <sys/types.h>
+    #include <sys/mount.h>
+    #include <sys/mman.h>
+    #include <sys/stat.h>
+    #include <sys/xattr.h>
+
+    #include <dirent.h>
+    #include <errno.h>
+    #include <error.h>
+    #include <fcntl.h>
+    #include <stdio.h>
+    #include <stdlib.h>
+    #include <string.h>
+    #include <unistd.h>
+
+    #include <linux/falloc.h>
+    #include <linux/loop.h>
+
+    static void activity(char *mpoint) {
+
+      char *xattr;
+      int err;
+
+      err = asprintf(&xattr, "%s/foo/bar/xattr", mpoint);
+
+      char buf2[113];
+      memset(buf2, 0, sizeof(buf2));
+      listxattr(xattr, buf2, sizeof(buf2));
+
+    }
+
+    int main(int argc, char *argv[]) {
+      activity(argv[1]);
+      return 0;
+    }
+
+- kernel message
+[  844.718738] F2FS-fs (loop0): Mounted with checkpoint version = 2
+[  846.430929] F2FS-fs (loop0): access invalid blkaddr:1024
+[  846.431058] WARNING: CPU: 1 PID: 1249 at fs/f2fs/checkpoint.c:154 f2fs_is_valid_blkaddr+0x10f/0x160
+[  846.431059] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_timer snd input_leds joydev soundcore serio_raw i2c_piix4 mac_hid ib_iser rdma_cm iw_cm ib_cm ib_core configfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi autofs4 raid10 raid456 libcrc32c async_raid6_recov async_memcpy async_pq async_xor xor async_tx raid6_pq raid1 raid0 multipath linear qxl ttm crct10dif_pclmul crc32_pclmul drm_kms_helper ghash_clmulni_intel syscopyarea sysfillrect sysimgblt fb_sys_fops pcbc drm 8139too aesni_intel 8139cp floppy psmouse mii aes_x86_64 crypto_simd pata_acpi cryptd glue_helper
+[  846.431310] CPU: 1 PID: 1249 Comm: a.out Not tainted 4.18.0-rc3+ #1
+[  846.431312] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  846.431315] RIP: 0010:f2fs_is_valid_blkaddr+0x10f/0x160
+[  846.431316] Code: 00 eb ed 31 c0 83 fa 05 75 ae 48 83 ec 08 48 8b 3f 89 f1 48 c7 c2 fc 0b 0f 8b 48 c7 c6 8b d7 09 8b 88 44 24 07 e8 61 8b ff ff <0f> 0b 0f b6 44 24 07 48 83 c4 08 eb 81 4c 8b 47 10 8b 8f 38 04 00
+[  846.431347] RSP: 0018:ffff961c414a7bc0 EFLAGS: 00010282
+[  846.431349] RAX: 0000000000000000 RBX: ffffc5f787b8ea80 RCX: 0000000000000000
+[  846.431350] RDX: 0000000000000000 RSI: ffff89dfffd165d8 RDI: ffff89dfffd165d8
+[  846.431351] RBP: ffff961c414a7c20 R08: 0000000000000001 R09: 0000000000000248
+[  846.431353] R10: 0000000000000000 R11: 0000000000000248 R12: 0000000000000007
+[  846.431369] R13: ffff89dff5492800 R14: ffff89dfae3aa000 R15: ffff89dff4ff88d0
+[  846.431372] FS:  00007f882e2fb700(0000) GS:ffff89dfffd00000(0000) knlGS:0000000000000000
+[  846.431373] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  846.431374] CR2: 0000000001a88008 CR3: 00000001eb572000 CR4: 00000000000006e0
+[  846.431384] Call Trace:
+[  846.431426]  f2fs_iget+0x6f4/0xe70
+[  846.431430]  ? f2fs_find_entry+0x71/0x90
+[  846.431432]  f2fs_lookup+0x1aa/0x390
+[  846.431452]  __lookup_slow+0x97/0x150
+[  846.431459]  lookup_slow+0x35/0x50
+[  846.431462]  walk_component+0x1c6/0x470
+[  846.431479]  ? memcg_kmem_charge_memcg+0x70/0x90
+[  846.431488]  ? page_add_file_rmap+0x13/0x200
+[  846.431491]  path_lookupat+0x76/0x230
+[  846.431501]  ? __alloc_pages_nodemask+0xfc/0x280
+[  846.431504]  filename_lookup+0xb8/0x1a0
+[  846.431534]  ? _cond_resched+0x16/0x40
+[  846.431541]  ? kmem_cache_alloc+0x160/0x1d0
+[  846.431549]  ? path_listxattr+0x41/0xa0
+[  846.431551]  path_listxattr+0x41/0xa0
+[  846.431570]  do_syscall_64+0x55/0x100
+[  846.431583]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[  846.431607] RIP: 0033:0x7f882de1c0d7
+[  846.431607] Code: f0 ff ff 73 01 c3 48 8b 0d be dd 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 b8 c2 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 91 dd 2b 00 f7 d8 64 89 01 48
+[  846.431639] RSP: 002b:00007ffe8e66c238 EFLAGS: 00000202 ORIG_RAX: 00000000000000c2
+[  846.431641] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f882de1c0d7
+[  846.431642] RDX: 0000000000000071 RSI: 00007ffe8e66c280 RDI: 0000000001a880c0
+[  846.431643] RBP: 00007ffe8e66c300 R08: 0000000001a88010 R09: 0000000000000000
+[  846.431645] R10: 00000000000001ab R11: 0000000000000202 R12: 0000000000400550
+[  846.431646] R13: 00007ffe8e66c400 R14: 0000000000000000 R15: 0000000000000000
+[  846.431648] ---[ end trace abca54df39d14f5c ]---
+[  846.431651] F2FS-fs (loop0): invalid blkaddr: 1024, type: 5, run fsck to fix.
+[  846.431762] WARNING: CPU: 1 PID: 1249 at fs/f2fs/f2fs.h:2697 f2fs_iget+0xd17/0xe70
+[  846.431763] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_timer snd input_leds joydev soundcore serio_raw i2c_piix4 mac_hid ib_iser rdma_cm iw_cm ib_cm ib_core configfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi autofs4 raid10 raid456 libcrc32c async_raid6_recov async_memcpy async_pq async_xor xor async_tx raid6_pq raid1 raid0 multipath linear qxl ttm crct10dif_pclmul crc32_pclmul drm_kms_helper ghash_clmulni_intel syscopyarea sysfillrect sysimgblt fb_sys_fops pcbc drm 8139too aesni_intel 8139cp floppy psmouse mii aes_x86_64 crypto_simd pata_acpi cryptd glue_helper
+[  846.431797] CPU: 1 PID: 1249 Comm: a.out Tainted: G        W         4.18.0-rc3+ #1
+[  846.431798] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  846.431800] RIP: 0010:f2fs_iget+0xd17/0xe70
+[  846.431801] Code: ff ff 48 63 d8 e9 e1 f6 ff ff 48 8b 45 c8 41 b8 05 00 00 00 48 c7 c2 d8 e8 0e 8b 48 c7 c6 1d b0 0a 8b 48 8b 38 e8 f9 b4 00 00 <0f> 0b 48 8b 45 c8 f0 80 48 48 04 e9 d8 f9 ff ff 0f 0b 48 8b 43 18
+[  846.431832] RSP: 0018:ffff961c414a7bd0 EFLAGS: 00010282
+[  846.431834] RAX: 0000000000000000 RBX: ffffc5f787b8ea80 RCX: 0000000000000006
+[  846.431835] RDX: 0000000000000000 RSI: 0000000000000096 RDI: ffff89dfffd165d0
+[  846.431836] RBP: ffff961c414a7c20 R08: 0000000000000000 R09: 0000000000000273
+[  846.431837] R10: 0000000000000000 R11: ffff89dfad50ca60 R12: 0000000000000007
+[  846.431838] R13: ffff89dff5492800 R14: ffff89dfae3aa000 R15: ffff89dff4ff88d0
+[  846.431840] FS:  00007f882e2fb700(0000) GS:ffff89dfffd00000(0000) knlGS:0000000000000000
+[  846.431841] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  846.431842] CR2: 0000000001a88008 CR3: 00000001eb572000 CR4: 00000000000006e0
+[  846.431846] Call Trace:
+[  846.431850]  ? f2fs_find_entry+0x71/0x90
+[  846.431853]  f2fs_lookup+0x1aa/0x390
+[  846.431856]  __lookup_slow+0x97/0x150
+[  846.431858]  lookup_slow+0x35/0x50
+[  846.431874]  walk_component+0x1c6/0x470
+[  846.431878]  ? memcg_kmem_charge_memcg+0x70/0x90
+[  846.431880]  ? page_add_file_rmap+0x13/0x200
+[  846.431882]  path_lookupat+0x76/0x230
+[  846.431884]  ? __alloc_pages_nodemask+0xfc/0x280
+[  846.431886]  filename_lookup+0xb8/0x1a0
+[  846.431890]  ? _cond_resched+0x16/0x40
+[  846.431891]  ? kmem_cache_alloc+0x160/0x1d0
+[  846.431894]  ? path_listxattr+0x41/0xa0
+[  846.431896]  path_listxattr+0x41/0xa0
+[  846.431898]  do_syscall_64+0x55/0x100
+[  846.431901]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[  846.431902] RIP: 0033:0x7f882de1c0d7
+[  846.431903] Code: f0 ff ff 73 01 c3 48 8b 0d be dd 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 b8 c2 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 91 dd 2b 00 f7 d8 64 89 01 48
+[  846.431934] RSP: 002b:00007ffe8e66c238 EFLAGS: 00000202 ORIG_RAX: 00000000000000c2
+[  846.431936] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f882de1c0d7
+[  846.431937] RDX: 0000000000000071 RSI: 00007ffe8e66c280 RDI: 0000000001a880c0
+[  846.431939] RBP: 00007ffe8e66c300 R08: 0000000001a88010 R09: 0000000000000000
+[  846.431940] R10: 00000000000001ab R11: 0000000000000202 R12: 0000000000400550
+[  846.431941] R13: 00007ffe8e66c400 R14: 0000000000000000 R15: 0000000000000000
+[  846.431943] ---[ end trace abca54df39d14f5d ]---
+[  846.432033] F2FS-fs (loop0): access invalid blkaddr:1024
+[  846.432051] WARNING: CPU: 1 PID: 1249 at fs/f2fs/checkpoint.c:154 f2fs_is_valid_blkaddr+0x10f/0x160
+[  846.432051] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_timer snd input_leds joydev soundcore serio_raw i2c_piix4 mac_hid ib_iser rdma_cm iw_cm ib_cm ib_core configfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi autofs4 raid10 raid456 libcrc32c async_raid6_recov async_memcpy async_pq async_xor xor async_tx raid6_pq raid1 raid0 multipath linear qxl ttm crct10dif_pclmul crc32_pclmul drm_kms_helper ghash_clmulni_intel syscopyarea sysfillrect sysimgblt fb_sys_fops pcbc drm 8139too aesni_intel 8139cp floppy psmouse mii aes_x86_64 crypto_simd pata_acpi cryptd glue_helper
+[  846.432085] CPU: 1 PID: 1249 Comm: a.out Tainted: G        W         4.18.0-rc3+ #1
+[  846.432086] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  846.432089] RIP: 0010:f2fs_is_valid_blkaddr+0x10f/0x160
+[  846.432089] Code: 00 eb ed 31 c0 83 fa 05 75 ae 48 83 ec 08 48 8b 3f 89 f1 48 c7 c2 fc 0b 0f 8b 48 c7 c6 8b d7 09 8b 88 44 24 07 e8 61 8b ff ff <0f> 0b 0f b6 44 24 07 48 83 c4 08 eb 81 4c 8b 47 10 8b 8f 38 04 00
+[  846.432120] RSP: 0018:ffff961c414a7900 EFLAGS: 00010286
+[  846.432122] RAX: 0000000000000000 RBX: 0000000000000400 RCX: 0000000000000006
+[  846.432123] RDX: 0000000000000000 RSI: 0000000000000096 RDI: ffff89dfffd165d0
+[  846.432124] RBP: ffff89dff5492800 R08: 0000000000000001 R09: 000000000000029d
+[  846.432125] R10: ffff961c414a7820 R11: 000000000000029d R12: 0000000000000400
+[  846.432126] R13: 0000000000000000 R14: ffff89dff4ff88d0 R15: 0000000000000000
+[  846.432128] FS:  00007f882e2fb700(0000) GS:ffff89dfffd00000(0000) knlGS:0000000000000000
+[  846.432130] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  846.432131] CR2: 0000000001a88008 CR3: 00000001eb572000 CR4: 00000000000006e0
+[  846.432135] Call Trace:
+[  846.432151]  f2fs_wait_on_block_writeback+0x20/0x110
+[  846.432158]  f2fs_grab_read_bio+0xbc/0xe0
+[  846.432161]  f2fs_submit_page_read+0x21/0x280
+[  846.432163]  f2fs_get_read_data_page+0xb7/0x3c0
+[  846.432165]  f2fs_get_lock_data_page+0x29/0x1e0
+[  846.432167]  f2fs_get_new_data_page+0x148/0x550
+[  846.432170]  f2fs_add_regular_entry+0x1d2/0x550
+[  846.432178]  ? __switch_to+0x12f/0x460
+[  846.432181]  f2fs_add_dentry+0x6a/0xd0
+[  846.432184]  f2fs_do_add_link+0xe9/0x140
+[  846.432186]  __recover_dot_dentries+0x260/0x280
+[  846.432189]  f2fs_lookup+0x343/0x390
+[  846.432193]  __lookup_slow+0x97/0x150
+[  846.432195]  lookup_slow+0x35/0x50
+[  846.432208]  walk_component+0x1c6/0x470
+[  846.432212]  ? memcg_kmem_charge_memcg+0x70/0x90
+[  846.432215]  ? page_add_file_rmap+0x13/0x200
+[  846.432217]  path_lookupat+0x76/0x230
+[  846.432219]  ? __alloc_pages_nodemask+0xfc/0x280
+[  846.432221]  filename_lookup+0xb8/0x1a0
+[  846.432224]  ? _cond_resched+0x16/0x40
+[  846.432226]  ? kmem_cache_alloc+0x160/0x1d0
+[  846.432228]  ? path_listxattr+0x41/0xa0
+[  846.432230]  path_listxattr+0x41/0xa0
+[  846.432233]  do_syscall_64+0x55/0x100
+[  846.432235]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[  846.432237] RIP: 0033:0x7f882de1c0d7
+[  846.432237] Code: f0 ff ff 73 01 c3 48 8b 0d be dd 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 b8 c2 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 91 dd 2b 00 f7 d8 64 89 01 48
+[  846.432269] RSP: 002b:00007ffe8e66c238 EFLAGS: 00000202 ORIG_RAX: 00000000000000c2
+[  846.432271] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f882de1c0d7
+[  846.432272] RDX: 0000000000000071 RSI: 00007ffe8e66c280 RDI: 0000000001a880c0
+[  846.432273] RBP: 00007ffe8e66c300 R08: 0000000001a88010 R09: 0000000000000000
+[  846.432274] R10: 00000000000001ab R11: 0000000000000202 R12: 0000000000400550
+[  846.432275] R13: 00007ffe8e66c400 R14: 0000000000000000 R15: 0000000000000000
+[  846.432277] ---[ end trace abca54df39d14f5e ]---
+[  846.432279] F2FS-fs (loop0): invalid blkaddr: 1024, type: 5, run fsck to fix.
+[  846.432376] WARNING: CPU: 1 PID: 1249 at fs/f2fs/f2fs.h:2697 f2fs_wait_on_block_writeback+0xb1/0x110
+[  846.432376] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_timer snd input_leds joydev soundcore serio_raw i2c_piix4 mac_hid ib_iser rdma_cm iw_cm ib_cm ib_core configfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi autofs4 raid10 raid456 libcrc32c async_raid6_recov async_memcpy async_pq async_xor xor async_tx raid6_pq raid1 raid0 multipath linear qxl ttm crct10dif_pclmul crc32_pclmul drm_kms_helper ghash_clmulni_intel syscopyarea sysfillrect sysimgblt fb_sys_fops pcbc drm 8139too aesni_intel 8139cp floppy psmouse mii aes_x86_64 crypto_simd pata_acpi cryptd glue_helper
+[  846.432410] CPU: 1 PID: 1249 Comm: a.out Tainted: G        W         4.18.0-rc3+ #1
+[  846.432411] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  846.432413] RIP: 0010:f2fs_wait_on_block_writeback+0xb1/0x110
+[  846.432414] Code: 66 90 f0 ff 4b 34 74 59 5b 5d c3 48 8b 7d 00 41 b8 05 00 00 00 89 d9 48 c7 c2 d8 e8 0e 8b 48 c7 c6 1d b0 0a 8b e8 df bc fd ff <0f> 0b f0 80 4d 48 04 e9 67 ff ff ff 48 8b 03 48 c1 e8 37 83 e0 07
+[  846.432445] RSP: 0018:ffff961c414a7910 EFLAGS: 00010286
+[  846.432447] RAX: 0000000000000000 RBX: 0000000000000400 RCX: 0000000000000006
+[  846.432448] RDX: 0000000000000000 RSI: 0000000000000092 RDI: ffff89dfffd165d0
+[  846.432449] RBP: ffff89dff5492800 R08: 0000000000000000 R09: 00000000000002d1
+[  846.432450] R10: ffff961c414a7820 R11: ffff89dfad50cf80 R12: 0000000000000400
+[  846.432451] R13: 0000000000000000 R14: ffff89dff4ff88d0 R15: 0000000000000000
+[  846.432453] FS:  00007f882e2fb700(0000) GS:ffff89dfffd00000(0000) knlGS:0000000000000000
+[  846.432454] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  846.432455] CR2: 0000000001a88008 CR3: 00000001eb572000 CR4: 00000000000006e0
+[  846.432459] Call Trace:
+[  846.432463]  f2fs_grab_read_bio+0xbc/0xe0
+[  846.432464]  f2fs_submit_page_read+0x21/0x280
+[  846.432466]  f2fs_get_read_data_page+0xb7/0x3c0
+[  846.432468]  f2fs_get_lock_data_page+0x29/0x1e0
+[  846.432470]  f2fs_get_new_data_page+0x148/0x550
+[  846.432473]  f2fs_add_regular_entry+0x1d2/0x550
+[  846.432475]  ? __switch_to+0x12f/0x460
+[  846.432477]  f2fs_add_dentry+0x6a/0xd0
+[  846.432480]  f2fs_do_add_link+0xe9/0x140
+[  846.432483]  __recover_dot_dentries+0x260/0x280
+[  846.432485]  f2fs_lookup+0x343/0x390
+[  846.432488]  __lookup_slow+0x97/0x150
+[  846.432490]  lookup_slow+0x35/0x50
+[  846.432505]  walk_component+0x1c6/0x470
+[  846.432509]  ? memcg_kmem_charge_memcg+0x70/0x90
+[  846.432511]  ? page_add_file_rmap+0x13/0x200
+[  846.432513]  path_lookupat+0x76/0x230
+[  846.432515]  ? __alloc_pages_nodemask+0xfc/0x280
+[  846.432517]  filename_lookup+0xb8/0x1a0
+[  846.432520]  ? _cond_resched+0x16/0x40
+[  846.432522]  ? kmem_cache_alloc+0x160/0x1d0
+[  846.432525]  ? path_listxattr+0x41/0xa0
+[  846.432526]  path_listxattr+0x41/0xa0
+[  846.432529]  do_syscall_64+0x55/0x100
+[  846.432531]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[  846.432533] RIP: 0033:0x7f882de1c0d7
+[  846.432533] Code: f0 ff ff 73 01 c3 48 8b 0d be dd 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 b8 c2 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 91 dd 2b 00 f7 d8 64 89 01 48
+[  846.432565] RSP: 002b:00007ffe8e66c238 EFLAGS: 00000202 ORIG_RAX: 00000000000000c2
+[  846.432567] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f882de1c0d7
+[  846.432568] RDX: 0000000000000071 RSI: 00007ffe8e66c280 RDI: 0000000001a880c0
+[  846.432569] RBP: 00007ffe8e66c300 R08: 0000000001a88010 R09: 0000000000000000
+[  846.432570] R10: 00000000000001ab R11: 0000000000000202 R12: 0000000000400550
+[  846.432571] R13: 00007ffe8e66c400 R14: 0000000000000000 R15: 0000000000000000
+[  846.432573] ---[ end trace abca54df39d14f5f ]---
+[  846.434280] BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
+[  846.434424] PGD 80000001ebd3a067 P4D 80000001ebd3a067 PUD 1eb1ae067 PMD 0
+[  846.434551] Oops: 0000 [#1] SMP PTI
+[  846.434697] CPU: 0 PID: 44 Comm: kworker/u5:0 Tainted: G        W         4.18.0-rc3+ #1
+[  846.434805] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  846.435000] Workqueue: fscrypt_read_queue decrypt_work
+[  846.435174] RIP: 0010:fscrypt_do_page_crypto+0x6e/0x2d0
+[  846.435351] Code: 00 65 48 8b 04 25 28 00 00 00 48 89 84 24 88 00 00 00 31 c0 e8 43 c2 e0 ff 49 8b 86 48 02 00 00 85 ed c7 44 24 70 00 00 00 00 <48> 8b 58 08 0f 84 14 02 00 00 48 8b 78 10 48 8b 0c 24 48 c7 84 24
+[  846.435696] RSP: 0018:ffff961c40f9bd60 EFLAGS: 00010206
+[  846.435870] RAX: 0000000000000000 RBX: ffffc5f787719b80 RCX: ffffc5f787719b80
+[  846.436051] RDX: ffffffff8b9f4b88 RSI: ffffffff8b0ae622 RDI: ffff961c40f9bdb8
+[  846.436261] RBP: 0000000000001000 R08: ffffc5f787719b80 R09: 0000000000001000
+[  846.436433] R10: 0000000000000018 R11: fefefefefefefeff R12: ffffc5f787719b80
+[  846.436562] R13: ffffc5f787719b80 R14: ffff89dff4ff88d0 R15: 0ffff89dfaddee60
+[  846.436658] FS:  0000000000000000(0000) GS:ffff89dfffc00000(0000) knlGS:0000000000000000
+[  846.436758] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  846.436898] CR2: 0000000000000008 CR3: 00000001eddd0000 CR4: 00000000000006f0
+[  846.437001] Call Trace:
+[  846.437181]  ? check_preempt_wakeup+0xf2/0x230
+[  846.437276]  ? check_preempt_curr+0x7c/0x90
+[  846.437370]  fscrypt_decrypt_page+0x48/0x4d
+[  846.437466]  __fscrypt_decrypt_bio+0x5b/0x90
+[  846.437542]  decrypt_work+0x12/0x20
+[  846.437651]  process_one_work+0x15e/0x3d0
+[  846.437740]  worker_thread+0x4c/0x440
+[  846.437848]  kthread+0xf8/0x130
+[  846.437938]  ? rescuer_thread+0x350/0x350
+[  846.438022]  ? kthread_associate_blkcg+0x90/0x90
+[  846.438117]  ret_from_fork+0x35/0x40
+[  846.438201] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_timer snd input_leds joydev soundcore serio_raw i2c_piix4 mac_hid ib_iser rdma_cm iw_cm ib_cm ib_core configfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi autofs4 raid10 raid456 libcrc32c async_raid6_recov async_memcpy async_pq async_xor xor async_tx raid6_pq raid1 raid0 multipath linear qxl ttm crct10dif_pclmul crc32_pclmul drm_kms_helper ghash_clmulni_intel syscopyarea sysfillrect sysimgblt fb_sys_fops pcbc drm 8139too aesni_intel 8139cp floppy psmouse mii aes_x86_64 crypto_simd pata_acpi cryptd glue_helper
+[  846.438653] CR2: 0000000000000008
+[  846.438713] ---[ end trace abca54df39d14f60 ]---
+[  846.438796] RIP: 0010:fscrypt_do_page_crypto+0x6e/0x2d0
+[  846.438844] Code: 00 65 48 8b 04 25 28 00 00 00 48 89 84 24 88 00 00 00 31 c0 e8 43 c2 e0 ff 49 8b 86 48 02 00 00 85 ed c7 44 24 70 00 00 00 00 <48> 8b 58 08 0f 84 14 02 00 00 48 8b 78 10 48 8b 0c 24 48 c7 84 24
+[  846.439084] RSP: 0018:ffff961c40f9bd60 EFLAGS: 00010206
+[  846.439176] RAX: 0000000000000000 RBX: ffffc5f787719b80 RCX: ffffc5f787719b80
+[  846.440927] RDX: ffffffff8b9f4b88 RSI: ffffffff8b0ae622 RDI: ffff961c40f9bdb8
+[  846.442083] RBP: 0000000000001000 R08: ffffc5f787719b80 R09: 0000000000001000
+[  846.443284] R10: 0000000000000018 R11: fefefefefefefeff R12: ffffc5f787719b80
+[  846.444448] R13: ffffc5f787719b80 R14: ffff89dff4ff88d0 R15: 0ffff89dfaddee60
+[  846.445558] FS:  0000000000000000(0000) GS:ffff89dfffc00000(0000) knlGS:0000000000000000
+[  846.446687] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  846.447796] CR2: 0000000000000008 CR3: 00000001eddd0000 CR4: 00000000000006f0
+
+- Location
+https://elixir.bootlin.com/linux/v4.18-rc4/source/fs/crypto/crypto.c#L149
+       struct crypto_skcipher *tfm = ci->ci_ctfm;
+Here ci can be NULL
+
+Note that this issue maybe require CONFIG_F2FS_FS_ENCRYPTION=y to reproduce.
+
+Reported-by Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/data.c  |    3 +++
+ fs/f2fs/inode.c |   18 +++++++++++++-----
+ 2 files changed, 16 insertions(+), 5 deletions(-)
+
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -884,6 +884,9 @@ struct bio *f2fs_grab_bio(struct inode *
+       struct block_device *bdev = sbi->sb->s_bdev;
+       struct bio *bio;
++      if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
++              return ERR_PTR(-EFAULT);
++
+       if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
+               ctx = f2fs_get_crypto_ctx(inode);
+               if (IS_ERR(ctx))
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -50,14 +50,16 @@ static void __get_inode_rdev(struct inod
+       }
+ }
+-static bool __written_first_block(struct f2fs_sb_info *sbi,
++static int __written_first_block(struct f2fs_sb_info *sbi,
+                                       struct f2fs_inode *ri)
+ {
+       block_t addr = le32_to_cpu(ri->i_addr[0]);
+-      if (is_valid_data_blkaddr(sbi, addr))
+-              return true;
+-      return false;
++      if (!__is_valid_data_blkaddr(addr))
++              return 1;
++      if (!f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC))
++              return -EFAULT;
++      return 0;
+ }
+ static void __set_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
+@@ -145,6 +147,7 @@ static int do_read_inode(struct inode *i
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       struct page *node_page;
+       struct f2fs_inode *ri;
++      int err;
+       /* Check if ino is within scope */
+       if (check_nid_range(sbi, inode->i_ino)) {
+@@ -199,7 +202,12 @@ static int do_read_inode(struct inode *i
+       /* get rdev by using inline_info */
+       __get_inode_rdev(inode, ri);
+-      if (__written_first_block(sbi, ri))
++      err = __written_first_block(sbi, ri);
++      if (err < 0) {
++              f2fs_put_page(node_page, 1);
++              return err;
++      }
++      if (!err)
+               set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN);
+       f2fs_put_page(node_page, 1);
diff --git a/queue-4.4/f2fs-fix-to-do-sanity-check-with-block-address-in-main-area.patch b/queue-4.4/f2fs-fix-to-do-sanity-check-with-block-address-in-main-area.patch
new file mode 100644 (file)
index 0000000..cf6994f
--- /dev/null
@@ -0,0 +1,492 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Wed, 1 Aug 2018 19:13:44 +0800
+Subject: f2fs: fix to do sanity check with block address in main area
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit c9b60788fc760d136211853f10ce73dc152d1f4a upstream.
+
+This patch add to do sanity check with below field:
+- cp_pack_total_block_count
+- blkaddr of data/node
+- extent info
+
+- Overview
+BUG() in verify_block_addr() when writing to a corrupted f2fs image
+
+- Reproduce (4.18 upstream kernel)
+
+- POC (poc.c)
+
+static void activity(char *mpoint) {
+
+  char *foo_bar_baz;
+  int err;
+
+  static int buf[8192];
+  memset(buf, 0, sizeof(buf));
+
+  err = asprintf(&foo_bar_baz, "%s/foo/bar/baz", mpoint);
+
+  int fd = open(foo_bar_baz, O_RDWR | O_TRUNC, 0777);
+  if (fd >= 0) {
+    write(fd, (char *)buf, sizeof(buf));
+    fdatasync(fd);
+    close(fd);
+  }
+}
+
+int main(int argc, char *argv[]) {
+  activity(argv[1]);
+  return 0;
+}
+
+- Kernel message
+[  689.349473] F2FS-fs (loop0): Mounted with checkpoint version = 3
+[  699.728662] WARNING: CPU: 0 PID: 1309 at fs/f2fs/segment.c:2860 f2fs_inplace_write_data+0x232/0x240
+[  699.728670] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
+[  699.729056] CPU: 0 PID: 1309 Comm: a.out Not tainted 4.18.0-rc1+ #4
+[  699.729064] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  699.729074] RIP: 0010:f2fs_inplace_write_data+0x232/0x240
+[  699.729076] Code: ff e9 cf fe ff ff 49 8d 7d 10 e8 39 45 ad ff 4d 8b 7d 10 be 04 00 00 00 49 8d 7f 48 e8 07 49 ad ff 45 8b 7f 48 e9 fb fe ff ff <0f> 0b f0 41 80 4d 48 04 e9 65 fe ff ff 90 66 66 66 66 90 55 48 8d
+[  699.729130] RSP: 0018:ffff8801f43af568 EFLAGS: 00010202
+[  699.729139] RAX: 000000000000003f RBX: ffff8801f43af7b8 RCX: ffffffffb88c9113
+[  699.729142] RDX: 0000000000000003 RSI: dffffc0000000000 RDI: ffff8802024e5540
+[  699.729144] RBP: ffff8801f43af590 R08: 0000000000000009 R09: ffffffffffffffe8
+[  699.729147] R10: 0000000000000001 R11: ffffed0039b0596a R12: ffff8802024e5540
+[  699.729149] R13: ffff8801f0335500 R14: ffff8801e3e7a700 R15: ffff8801e1ee4450
+[  699.729154] FS:  00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[  699.729156] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  699.729159] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
+[  699.729171] Call Trace:
+[  699.729192]  f2fs_do_write_data_page+0x2e2/0xe00
+[  699.729203]  ? f2fs_should_update_outplace+0xd0/0xd0
+[  699.729238]  ? memcg_drain_all_list_lrus+0x280/0x280
+[  699.729269]  ? __radix_tree_replace+0xa3/0x120
+[  699.729276]  __write_data_page+0x5c7/0xe30
+[  699.729291]  ? kasan_check_read+0x11/0x20
+[  699.729310]  ? page_mapped+0x8a/0x110
+[  699.729321]  ? page_mkclean+0xe9/0x160
+[  699.729327]  ? f2fs_do_write_data_page+0xe00/0xe00
+[  699.729331]  ? invalid_page_referenced_vma+0x130/0x130
+[  699.729345]  ? clear_page_dirty_for_io+0x332/0x450
+[  699.729351]  f2fs_write_cache_pages+0x4ca/0x860
+[  699.729358]  ? __write_data_page+0xe30/0xe30
+[  699.729374]  ? percpu_counter_add_batch+0x22/0xa0
+[  699.729380]  ? kasan_check_write+0x14/0x20
+[  699.729391]  ? _raw_spin_lock+0x17/0x40
+[  699.729403]  ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
+[  699.729413]  ? iov_iter_advance+0x113/0x640
+[  699.729418]  ? f2fs_write_end+0x133/0x2e0
+[  699.729423]  ? balance_dirty_pages_ratelimited+0x239/0x640
+[  699.729428]  f2fs_write_data_pages+0x329/0x520
+[  699.729433]  ? generic_perform_write+0x250/0x320
+[  699.729438]  ? f2fs_write_cache_pages+0x860/0x860
+[  699.729454]  ? current_time+0x110/0x110
+[  699.729459]  ? f2fs_preallocate_blocks+0x1ef/0x370
+[  699.729464]  do_writepages+0x37/0xb0
+[  699.729468]  ? f2fs_write_cache_pages+0x860/0x860
+[  699.729472]  ? do_writepages+0x37/0xb0
+[  699.729478]  __filemap_fdatawrite_range+0x19a/0x1f0
+[  699.729483]  ? delete_from_page_cache_batch+0x4e0/0x4e0
+[  699.729496]  ? __vfs_write+0x2b2/0x410
+[  699.729501]  file_write_and_wait_range+0x66/0xb0
+[  699.729506]  f2fs_do_sync_file+0x1f9/0xd90
+[  699.729511]  ? truncate_partial_data_page+0x290/0x290
+[  699.729521]  ? __sb_end_write+0x30/0x50
+[  699.729526]  ? vfs_write+0x20f/0x260
+[  699.729530]  f2fs_sync_file+0x9a/0xb0
+[  699.729534]  ? f2fs_do_sync_file+0xd90/0xd90
+[  699.729548]  vfs_fsync_range+0x68/0x100
+[  699.729554]  ? __fget_light+0xc9/0xe0
+[  699.729558]  do_fsync+0x3d/0x70
+[  699.729562]  __x64_sys_fdatasync+0x24/0x30
+[  699.729585]  do_syscall_64+0x78/0x170
+[  699.729595]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[  699.729613] RIP: 0033:0x7f9bf930d800
+[  699.729615] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 83 3d 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
+[  699.729668] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
+[  699.729673] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
+[  699.729675] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
+[  699.729678] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
+[  699.729680] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
+[  699.729683] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
+[  699.729687] ---[ end trace 4ce02f25ff7d3df5 ]---
+[  699.729782] ------------[ cut here ]------------
+[  699.729785] kernel BUG at fs/f2fs/segment.h:654!
+[  699.731055] invalid opcode: 0000 [#1] SMP KASAN PTI
+[  699.732104] CPU: 0 PID: 1309 Comm: a.out Tainted: G        W         4.18.0-rc1+ #4
+[  699.733684] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  699.735611] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
+[  699.736649] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
+[  699.740524] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
+[  699.741573] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
+[  699.743006] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
+[  699.744426] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
+[  699.745833] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
+[  699.747256] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
+[  699.748683] FS:  00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[  699.750293] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  699.751462] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
+[  699.752874] Call Trace:
+[  699.753386]  ? f2fs_inplace_write_data+0x93/0x240
+[  699.754341]  f2fs_inplace_write_data+0xd2/0x240
+[  699.755271]  f2fs_do_write_data_page+0x2e2/0xe00
+[  699.756214]  ? f2fs_should_update_outplace+0xd0/0xd0
+[  699.757215]  ? memcg_drain_all_list_lrus+0x280/0x280
+[  699.758209]  ? __radix_tree_replace+0xa3/0x120
+[  699.759164]  __write_data_page+0x5c7/0xe30
+[  699.760002]  ? kasan_check_read+0x11/0x20
+[  699.760823]  ? page_mapped+0x8a/0x110
+[  699.761573]  ? page_mkclean+0xe9/0x160
+[  699.762345]  ? f2fs_do_write_data_page+0xe00/0xe00
+[  699.763332]  ? invalid_page_referenced_vma+0x130/0x130
+[  699.764374]  ? clear_page_dirty_for_io+0x332/0x450
+[  699.765347]  f2fs_write_cache_pages+0x4ca/0x860
+[  699.766276]  ? __write_data_page+0xe30/0xe30
+[  699.767161]  ? percpu_counter_add_batch+0x22/0xa0
+[  699.768112]  ? kasan_check_write+0x14/0x20
+[  699.768951]  ? _raw_spin_lock+0x17/0x40
+[  699.769739]  ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
+[  699.770885]  ? iov_iter_advance+0x113/0x640
+[  699.771743]  ? f2fs_write_end+0x133/0x2e0
+[  699.772569]  ? balance_dirty_pages_ratelimited+0x239/0x640
+[  699.773680]  f2fs_write_data_pages+0x329/0x520
+[  699.774603]  ? generic_perform_write+0x250/0x320
+[  699.775544]  ? f2fs_write_cache_pages+0x860/0x860
+[  699.776510]  ? current_time+0x110/0x110
+[  699.777299]  ? f2fs_preallocate_blocks+0x1ef/0x370
+[  699.778279]  do_writepages+0x37/0xb0
+[  699.779026]  ? f2fs_write_cache_pages+0x860/0x860
+[  699.779978]  ? do_writepages+0x37/0xb0
+[  699.780755]  __filemap_fdatawrite_range+0x19a/0x1f0
+[  699.781746]  ? delete_from_page_cache_batch+0x4e0/0x4e0
+[  699.782820]  ? __vfs_write+0x2b2/0x410
+[  699.783597]  file_write_and_wait_range+0x66/0xb0
+[  699.784540]  f2fs_do_sync_file+0x1f9/0xd90
+[  699.785381]  ? truncate_partial_data_page+0x290/0x290
+[  699.786415]  ? __sb_end_write+0x30/0x50
+[  699.787204]  ? vfs_write+0x20f/0x260
+[  699.787941]  f2fs_sync_file+0x9a/0xb0
+[  699.788694]  ? f2fs_do_sync_file+0xd90/0xd90
+[  699.789572]  vfs_fsync_range+0x68/0x100
+[  699.790360]  ? __fget_light+0xc9/0xe0
+[  699.791128]  do_fsync+0x3d/0x70
+[  699.791779]  __x64_sys_fdatasync+0x24/0x30
+[  699.792614]  do_syscall_64+0x78/0x170
+[  699.793371]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[  699.794406] RIP: 0033:0x7f9bf930d800
+[  699.795134] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 83 3d 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
+[  699.798960] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
+[  699.800483] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
+[  699.801923] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
+[  699.803373] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
+[  699.804798] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
+[  699.806233] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
+[  699.807667] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
+[  699.817079] ---[ end trace 4ce02f25ff7d3df6 ]---
+[  699.818068] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
+[  699.819114] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
+[  699.822919] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
+[  699.823977] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
+[  699.825436] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
+[  699.826881] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
+[  699.828292] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
+[  699.829750] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
+[  699.831192] FS:  00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[  699.832793] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  699.833981] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
+[  699.835556] ==================================================================
+[  699.837029] BUG: KASAN: stack-out-of-bounds in update_stack_state+0x38c/0x3e0
+[  699.838462] Read of size 8 at addr ffff8801f43af970 by task a.out/1309
+
+[  699.840086] CPU: 0 PID: 1309 Comm: a.out Tainted: G      D W         4.18.0-rc1+ #4
+[  699.841603] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  699.843475] Call Trace:
+[  699.843982]  dump_stack+0x7b/0xb5
+[  699.844661]  print_address_description+0x70/0x290
+[  699.845607]  kasan_report+0x291/0x390
+[  699.846351]  ? update_stack_state+0x38c/0x3e0
+[  699.853831]  __asan_load8+0x54/0x90
+[  699.854569]  update_stack_state+0x38c/0x3e0
+[  699.855428]  ? __read_once_size_nocheck.constprop.7+0x20/0x20
+[  699.856601]  ? __save_stack_trace+0x5e/0x100
+[  699.857476]  unwind_next_frame.part.5+0x18e/0x490
+[  699.858448]  ? unwind_dump+0x290/0x290
+[  699.859217]  ? clear_page_dirty_for_io+0x332/0x450
+[  699.860185]  __unwind_start+0x106/0x190
+[  699.860974]  __save_stack_trace+0x5e/0x100
+[  699.861808]  ? __save_stack_trace+0x5e/0x100
+[  699.862691]  ? unlink_anon_vmas+0xba/0x2c0
+[  699.863525]  save_stack_trace+0x1f/0x30
+[  699.864312]  save_stack+0x46/0xd0
+[  699.864993]  ? __alloc_pages_slowpath+0x1420/0x1420
+[  699.865990]  ? flush_tlb_mm_range+0x15e/0x220
+[  699.866889]  ? kasan_check_write+0x14/0x20
+[  699.867724]  ? __dec_node_state+0x92/0xb0
+[  699.868543]  ? lock_page_memcg+0x85/0xf0
+[  699.869350]  ? unlock_page_memcg+0x16/0x80
+[  699.870185]  ? page_remove_rmap+0x198/0x520
+[  699.871048]  ? mark_page_accessed+0x133/0x200
+[  699.871930]  ? _cond_resched+0x1a/0x50
+[  699.872700]  ? unmap_page_range+0xcd4/0xe50
+[  699.873551]  ? rb_next+0x58/0x80
+[  699.874217]  ? rb_next+0x58/0x80
+[  699.874895]  __kasan_slab_free+0x13c/0x1a0
+[  699.875734]  ? unlink_anon_vmas+0xba/0x2c0
+[  699.876563]  kasan_slab_free+0xe/0x10
+[  699.877315]  kmem_cache_free+0x89/0x1e0
+[  699.878095]  unlink_anon_vmas+0xba/0x2c0
+[  699.878913]  free_pgtables+0x101/0x1b0
+[  699.879677]  exit_mmap+0x146/0x2a0
+[  699.880378]  ? __ia32_sys_munmap+0x50/0x50
+[  699.881214]  ? kasan_check_read+0x11/0x20
+[  699.882052]  ? mm_update_next_owner+0x322/0x380
+[  699.882985]  mmput+0x8b/0x1d0
+[  699.883602]  do_exit+0x43a/0x1390
+[  699.884288]  ? mm_update_next_owner+0x380/0x380
+[  699.885212]  ? f2fs_sync_file+0x9a/0xb0
+[  699.885995]  ? f2fs_do_sync_file+0xd90/0xd90
+[  699.886877]  ? vfs_fsync_range+0x68/0x100
+[  699.887694]  ? __fget_light+0xc9/0xe0
+[  699.888442]  ? do_fsync+0x3d/0x70
+[  699.889118]  ? __x64_sys_fdatasync+0x24/0x30
+[  699.889996]  rewind_stack_do_exit+0x17/0x20
+[  699.890860] RIP: 0033:0x7f9bf930d800
+[  699.891585] Code: Bad RIP value.
+[  699.892268] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
+[  699.893781] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
+[  699.895220] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
+[  699.896643] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
+[  699.898069] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
+[  699.899505] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
+
+[  699.901241] The buggy address belongs to the page:
+[  699.902215] page:ffffea0007d0ebc0 count:0 mapcount:0 mapping:0000000000000000 index:0x0
+[  699.903811] flags: 0x2ffff0000000000()
+[  699.904585] raw: 02ffff0000000000 0000000000000000 ffffffff07d00101 0000000000000000
+[  699.906125] raw: 0000000000000000 0000000000240000 00000000ffffffff 0000000000000000
+[  699.907673] page dumped because: kasan: bad access detected
+
+[  699.909108] Memory state around the buggy address:
+[  699.910077]  ffff8801f43af800: 00 f1 f1 f1 f1 00 f4 f4 f4 f3 f3 f3 f3 00 00 00
+[  699.911528]  ffff8801f43af880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[  699.912953] >ffff8801f43af900: 00 00 00 00 00 00 00 00 f1 01 f4 f4 f4 f2 f2 f2
+[  699.914392]                                                              ^
+[  699.915758]  ffff8801f43af980: f2 00 f4 f4 00 00 00 00 f2 00 00 00 00 00 00 00
+[  699.917193]  ffff8801f43afa00: 00 00 00 00 00 00 00 00 00 f3 f3 f3 00 00 00 00
+[  699.918634] ==================================================================
+
+- Location
+https://elixir.bootlin.com/linux/v4.18-rc1/source/fs/f2fs/segment.h#L644
+
+Reported-by Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4:
+ - CoW is not implemented so check f2fs_io_info::blk_addr instead of
+   f2fs_io_info::{old,new}_blkaddr
+ - Operation code is f2fs_io_info::rw instead of f2fs_io_info::op
+ - f2fs_stop_checkpoint() only takes one argument
+ - In f2fs_map_blocks(), validate dn.data_blkaddr instead of blkaddr
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c |   22 +++++++++++++++++++---
+ fs/f2fs/data.c       |   21 ++++++++++++++++++++-
+ fs/f2fs/f2fs.h       |    3 +++
+ fs/f2fs/file.c       |   12 ++++++++++++
+ fs/f2fs/inode.c      |   16 ++++++++++++++++
+ fs/f2fs/node.c       |    4 ++++
+ fs/f2fs/segment.h    |    3 +--
+ 7 files changed, 75 insertions(+), 6 deletions(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -75,8 +75,10 @@ repeat:
+       fio.page = page;
+       if (f2fs_submit_page_bio(&fio)) {
+-              f2fs_put_page(page, 1);
+-              goto repeat;
++              memset(page_address(page), 0, PAGE_SIZE);
++              f2fs_stop_checkpoint(sbi);
++              f2fs_bug_on(sbi, 1);
++              return page;
+       }
+       lock_page(page);
+@@ -130,8 +132,14 @@ bool f2fs_is_valid_blkaddr(struct f2fs_s
+       case META_POR:
+       case DATA_GENERIC:
+               if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
+-                      blkaddr < MAIN_BLKADDR(sbi)))
++                      blkaddr < MAIN_BLKADDR(sbi))) {
++                      if (type == DATA_GENERIC) {
++                              f2fs_msg(sbi->sb, KERN_WARNING,
++                                      "access invalid blkaddr:%u", blkaddr);
++                              WARN_ON(1);
++                      }
+                       return false;
++              }
+               break;
+       case META_GENERIC:
+               if (unlikely(blkaddr < SEG0_BLKADDR(sbi) ||
+@@ -651,6 +659,14 @@ static struct page *validate_checkpoint(
+                                       &cp_page_1, version);
+       if (err)
+               goto invalid_cp1;
++
++      if (le32_to_cpu(cp_block->cp_pack_total_block_count) >
++                                      sbi->blocks_per_seg) {
++              f2fs_msg(sbi->sb, KERN_WARNING,
++                      "invalid cp_pack_total_block_count:%u",
++                      le32_to_cpu(cp_block->cp_pack_total_block_count));
++              goto invalid_cp1;
++      }
+       pre_version = *version;
+       cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -147,7 +147,10 @@ int f2fs_submit_page_bio(struct f2fs_io_
+       struct bio *bio;
+       struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page;
+-      verify_block_addr(fio, fio->blk_addr);
++      if (!f2fs_is_valid_blkaddr(fio->sbi, fio->blk_addr,
++                      __is_meta_io(fio) ? META_GENERIC : DATA_GENERIC))
++              return -EFAULT;
++
+       trace_f2fs_submit_page_bio(page, fio);
+       f2fs_trace_ios(fio, 0);
+@@ -604,6 +607,12 @@ static int f2fs_map_blocks(struct inode
+               goto unlock_out;
+       }
++      if (__is_valid_data_blkaddr(dn.data_blkaddr) &&
++              !f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr, DATA_GENERIC)) {
++              err = -EFAULT;
++              goto sync_out;
++      }
++
+       if (!is_valid_data_blkaddr(sbi, dn.data_blkaddr)) {
+               if (create) {
+                       if (unlikely(f2fs_cp_error(sbi))) {
+@@ -972,6 +981,10 @@ got_it:
+                               SetPageUptodate(page);
+                               goto confused;
+                       }
++
++                      if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr,
++                                                              DATA_GENERIC))
++                              goto set_error_page;
+               } else {
+                       zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+                       SetPageUptodate(page);
+@@ -1086,6 +1099,12 @@ int do_write_data_page(struct f2fs_io_in
+       set_page_writeback(page);
++      if (__is_valid_data_blkaddr(fio->blk_addr) &&
++              !f2fs_is_valid_blkaddr(fio->sbi, fio->blk_addr,
++                                                      DATA_GENERIC)) {
++              err = -EFAULT;
++              goto out_writepage;
++      }
+       /*
+        * If current allocation needs SSR,
+        * it had better in-place writes for updated data.
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -1649,6 +1649,9 @@ static inline void *f2fs_kvzalloc(size_t
+       (pgofs - ADDRS_PER_INODE(fi) + ADDRS_PER_BLOCK) /       \
+       ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi))
++#define __is_meta_io(fio) (PAGE_TYPE_OF_BIO(fio->type) == META &&     \
++                              (!is_read_io(fio->rw) || fio->is_meta))
++
+ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
+                                       block_t blkaddr, int type);
+ void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
+--- a/fs/f2fs/file.c
++++ b/fs/f2fs/file.c
+@@ -374,6 +374,13 @@ static loff_t f2fs_seek_block(struct fil
+                       block_t blkaddr;
+                       blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
++                      if (__is_valid_data_blkaddr(blkaddr) &&
++                              !f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
++                                              blkaddr, DATA_GENERIC)) {
++                              f2fs_put_dnode(&dn);
++                              goto fail;
++                      }
++
+                       if (__found_offset(F2FS_I_SB(inode), blkaddr, dirty,
+                                                       pgofs, whence)) {
+                               f2fs_put_dnode(&dn);
+@@ -467,6 +474,11 @@ int truncate_data_blocks_range(struct dn
+               dn->data_blkaddr = NULL_ADDR;
+               set_data_blkaddr(dn);
++
++              if (__is_valid_data_blkaddr(blkaddr) &&
++                      !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
++                      continue;
++
+               invalidate_blocks(sbi, blkaddr);
+               if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page))
+                       clear_inode_flag(F2FS_I(dn->inode),
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -120,6 +120,22 @@ static bool sanity_check_inode(struct in
+               return false;
+       }
++      if (F2FS_I(inode)->extent_tree) {
++              struct extent_info *ei = &F2FS_I(inode)->extent_tree->largest;
++
++              if (ei->len &&
++                      (!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC) ||
++                      !f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1,
++                                                      DATA_GENERIC))) {
++                      set_sbi_flag(sbi, SBI_NEED_FSCK);
++                      f2fs_msg(sbi->sb, KERN_WARNING,
++                              "%s: inode (ino=%lx) extent info [%u, %u, %u] "
++                              "is incorrect, run fsck to fix",
++                              __func__, inode->i_ino,
++                              ei->blk, ei->fofs, ei->len);
++                      return false;
++              }
++      }
+       return true;
+ }
+--- a/fs/f2fs/node.c
++++ b/fs/f2fs/node.c
+@@ -1341,6 +1341,10 @@ static int f2fs_write_node_page(struct p
+               return 0;
+       }
++      if (__is_valid_data_blkaddr(ni.blk_addr) &&
++              !f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC))
++              goto redirty_out;
++
+       set_page_writeback(page);
+       fio.blk_addr = ni.blk_addr;
+       write_node_page(nid, &fio);
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -586,8 +586,7 @@ static inline void verify_block_addr(str
+ {
+       struct f2fs_sb_info *sbi = fio->sbi;
+-      if (PAGE_TYPE_OF_BIO(fio->type) == META &&
+-                              (!is_read_io(fio->rw) || fio->is_meta))
++      if (__is_meta_io(fio))
+               verify_blkaddr(sbi, blk_addr, META_GENERIC);
+       else
+               verify_blkaddr(sbi, blk_addr, DATA_GENERIC);
diff --git a/queue-4.4/f2fs-fix-to-do-sanity-check-with-cp_pack_start_sum.patch b/queue-4.4/f2fs-fix-to-do-sanity-check-with-cp_pack_start_sum.patch
new file mode 100644 (file)
index 0000000..5fcc4d0
--- /dev/null
@@ -0,0 +1,349 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Wed, 1 Aug 2018 19:16:11 +0800
+Subject: f2fs: fix to do sanity check with cp_pack_start_sum
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit e494c2f995d6181d6e29c4927d68e0f295ecf75b upstream.
+
+After fuzzing, cp_pack_start_sum could be corrupted, so current log's
+summary info should be wrong due to loading incorrect summary block.
+Then, if segment's type in current log is exceeded NR_CURSEG_TYPE, it
+can lead accessing invalid dirty_i->dirty_segmap bitmap finally.
+
+Add sanity check for cp_pack_start_sum to fix this issue.
+
+https://bugzilla.kernel.org/show_bug.cgi?id=200419
+
+- Reproduce
+
+- Kernel message (f2fs-dev w/ KASAN)
+[ 3117.578432] F2FS-fs (loop0): Invalid log blocks per segment (8)
+
+[ 3117.578445] F2FS-fs (loop0): Can't find valid F2FS filesystem in 2th superblock
+[ 3117.581364] F2FS-fs (loop0): invalid crc_offset: 30716
+[ 3117.583564] WARNING: CPU: 1 PID: 1225 at fs/f2fs/checkpoint.c:90 __get_meta_page+0x448/0x4b0
+[ 3117.583570] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_timer joydev input_leds serio_raw snd soundcore mac_hid i2c_piix4 ib_iser rdma_cm iw_cm ib_cm ib_core configfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi btrfs zstd_decompress zstd_compress xxhash raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear 8139too qxl ttm drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops drm crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcbc aesni_intel psmouse aes_x86_64 8139cp crypto_simd cryptd mii glue_helper pata_acpi floppy
+[ 3117.584014] CPU: 1 PID: 1225 Comm: mount Not tainted 4.17.0+ #1
+[ 3117.584017] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 3117.584022] RIP: 0010:__get_meta_page+0x448/0x4b0
+[ 3117.584023] Code: 00 49 8d bc 24 84 00 00 00 e8 74 54 da ff 41 83 8c 24 84 00 00 00 08 4c 89 f6 4c 89 ef e8 c0 d9 95 00 48 89 ef e8 18 e3 00 00 <0f> 0b f0 80 4d 48 04 e9 0f fe ff ff 0f 0b 48 89 c7 48 89 04 24 e8
+[ 3117.584072] RSP: 0018:ffff88018eb678c0 EFLAGS: 00010286
+[ 3117.584082] RAX: ffff88018f0a6a78 RBX: ffffea0007a46600 RCX: ffffffff9314d1b2
+[ 3117.584085] RDX: ffffffff00000001 RSI: 0000000000000000 RDI: ffff88018f0a6a98
+[ 3117.584087] RBP: ffff88018ebe9980 R08: 0000000000000002 R09: 0000000000000001
+[ 3117.584090] R10: 0000000000000001 R11: ffffed00326e4450 R12: ffff880193722200
+[ 3117.584092] R13: ffff88018ebe9afc R14: 0000000000000206 R15: ffff88018eb67900
+[ 3117.584096] FS:  00007f5694636840(0000) GS:ffff8801f3b00000(0000) knlGS:0000000000000000
+[ 3117.584098] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 3117.584101] CR2: 00000000016f21b8 CR3: 0000000191c22000 CR4: 00000000000006e0
+[ 3117.584112] Call Trace:
+[ 3117.584121]  ? f2fs_set_meta_page_dirty+0x150/0x150
+[ 3117.584127]  ? f2fs_build_segment_manager+0xbf9/0x3190
+[ 3117.584133]  ? f2fs_npages_for_summary_flush+0x75/0x120
+[ 3117.584145]  f2fs_build_segment_manager+0xda8/0x3190
+[ 3117.584151]  ? f2fs_get_valid_checkpoint+0x298/0xa00
+[ 3117.584156]  ? f2fs_flush_sit_entries+0x10e0/0x10e0
+[ 3117.584184]  ? map_id_range_down+0x17c/0x1b0
+[ 3117.584188]  ? __put_user_ns+0x30/0x30
+[ 3117.584206]  ? find_next_bit+0x53/0x90
+[ 3117.584237]  ? cpumask_next+0x16/0x20
+[ 3117.584249]  f2fs_fill_super+0x1948/0x2b40
+[ 3117.584258]  ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.584279]  ? sget_userns+0x65e/0x690
+[ 3117.584296]  ? set_blocksize+0x88/0x130
+[ 3117.584302]  ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.584305]  mount_bdev+0x1c0/0x200
+[ 3117.584310]  mount_fs+0x5c/0x190
+[ 3117.584320]  vfs_kern_mount+0x64/0x190
+[ 3117.584330]  do_mount+0x2e4/0x1450
+[ 3117.584343]  ? lockref_put_return+0x130/0x130
+[ 3117.584347]  ? copy_mount_string+0x20/0x20
+[ 3117.584357]  ? kasan_unpoison_shadow+0x31/0x40
+[ 3117.584362]  ? kasan_kmalloc+0xa6/0xd0
+[ 3117.584373]  ? memcg_kmem_put_cache+0x16/0x90
+[ 3117.584377]  ? __kmalloc_track_caller+0x196/0x210
+[ 3117.584383]  ? _copy_from_user+0x61/0x90
+[ 3117.584396]  ? memdup_user+0x3e/0x60
+[ 3117.584401]  ksys_mount+0x7e/0xd0
+[ 3117.584405]  __x64_sys_mount+0x62/0x70
+[ 3117.584427]  do_syscall_64+0x73/0x160
+[ 3117.584440]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 3117.584455] RIP: 0033:0x7f5693f14b9a
+[ 3117.584456] Code: 48 8b 0d 01 c3 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 49 89 ca b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d ce c2 2b 00 f7 d8 64 89 01 48
+[ 3117.584505] RSP: 002b:00007fff27346488 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5
+[ 3117.584510] RAX: ffffffffffffffda RBX: 00000000016e2030 RCX: 00007f5693f14b9a
+[ 3117.584512] RDX: 00000000016e2210 RSI: 00000000016e3f30 RDI: 00000000016ee040
+[ 3117.584514] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000013
+[ 3117.584516] R10: 00000000c0ed0000 R11: 0000000000000206 R12: 00000000016ee040
+[ 3117.584519] R13: 00000000016e2210 R14: 0000000000000000 R15: 0000000000000003
+[ 3117.584523] ---[ end trace a8e0d899985faf31 ]---
+[ 3117.685663] F2FS-fs (loop0): f2fs_check_nid_range: out-of-range nid=2, run fsck to fix.
+[ 3117.685673] F2FS-fs (loop0): recover_data: ino = 2 (i_size: recover) recovered = 1, err = 0
+[ 3117.685707] ==================================================================
+[ 3117.685955] BUG: KASAN: slab-out-of-bounds in __remove_dirty_segment+0xdd/0x1e0
+[ 3117.686175] Read of size 8 at addr ffff88018f0a63d0 by task mount/1225
+
+[ 3117.686477] CPU: 0 PID: 1225 Comm: mount Tainted: G        W         4.17.0+ #1
+[ 3117.686481] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 3117.686483] Call Trace:
+[ 3117.686494]  dump_stack+0x71/0xab
+[ 3117.686512]  print_address_description+0x6b/0x290
+[ 3117.686517]  kasan_report+0x28e/0x390
+[ 3117.686522]  ? __remove_dirty_segment+0xdd/0x1e0
+[ 3117.686527]  __remove_dirty_segment+0xdd/0x1e0
+[ 3117.686532]  locate_dirty_segment+0x189/0x190
+[ 3117.686538]  f2fs_allocate_new_segments+0xa9/0xe0
+[ 3117.686543]  recover_data+0x703/0x2c20
+[ 3117.686547]  ? f2fs_recover_fsync_data+0x48f/0xd50
+[ 3117.686553]  ? ksys_mount+0x7e/0xd0
+[ 3117.686564]  ? policy_nodemask+0x1a/0x90
+[ 3117.686567]  ? policy_node+0x56/0x70
+[ 3117.686571]  ? add_fsync_inode+0xf0/0xf0
+[ 3117.686592]  ? blk_finish_plug+0x44/0x60
+[ 3117.686597]  ? f2fs_ra_meta_pages+0x38b/0x5e0
+[ 3117.686602]  ? find_inode_fast+0xac/0xc0
+[ 3117.686606]  ? f2fs_is_valid_blkaddr+0x320/0x320
+[ 3117.686618]  ? __radix_tree_lookup+0x150/0x150
+[ 3117.686633]  ? dqget+0x670/0x670
+[ 3117.686648]  ? pagecache_get_page+0x29/0x410
+[ 3117.686656]  ? kmem_cache_alloc+0x176/0x1e0
+[ 3117.686660]  ? f2fs_is_valid_blkaddr+0x11d/0x320
+[ 3117.686664]  f2fs_recover_fsync_data+0xc23/0xd50
+[ 3117.686670]  ? f2fs_space_for_roll_forward+0x60/0x60
+[ 3117.686674]  ? rb_insert_color+0x323/0x3d0
+[ 3117.686678]  ? f2fs_recover_orphan_inodes+0xa5/0x700
+[ 3117.686683]  ? proc_register+0x153/0x1d0
+[ 3117.686686]  ? f2fs_remove_orphan_inode+0x10/0x10
+[ 3117.686695]  ? f2fs_attr_store+0x50/0x50
+[ 3117.686700]  ? proc_create_single_data+0x52/0x60
+[ 3117.686707]  f2fs_fill_super+0x1d06/0x2b40
+[ 3117.686728]  ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.686735]  ? sget_userns+0x65e/0x690
+[ 3117.686740]  ? set_blocksize+0x88/0x130
+[ 3117.686745]  ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.686748]  mount_bdev+0x1c0/0x200
+[ 3117.686753]  mount_fs+0x5c/0x190
+[ 3117.686758]  vfs_kern_mount+0x64/0x190
+[ 3117.686762]  do_mount+0x2e4/0x1450
+[ 3117.686769]  ? lockref_put_return+0x130/0x130
+[ 3117.686773]  ? copy_mount_string+0x20/0x20
+[ 3117.686777]  ? kasan_unpoison_shadow+0x31/0x40
+[ 3117.686780]  ? kasan_kmalloc+0xa6/0xd0
+[ 3117.686786]  ? memcg_kmem_put_cache+0x16/0x90
+[ 3117.686790]  ? __kmalloc_track_caller+0x196/0x210
+[ 3117.686795]  ? _copy_from_user+0x61/0x90
+[ 3117.686801]  ? memdup_user+0x3e/0x60
+[ 3117.686804]  ksys_mount+0x7e/0xd0
+[ 3117.686809]  __x64_sys_mount+0x62/0x70
+[ 3117.686816]  do_syscall_64+0x73/0x160
+[ 3117.686824]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 3117.686829] RIP: 0033:0x7f5693f14b9a
+[ 3117.686830] Code: 48 8b 0d 01 c3 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 49 89 ca b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d ce c2 2b 00 f7 d8 64 89 01 48
+[ 3117.686887] RSP: 002b:00007fff27346488 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5
+[ 3117.686892] RAX: ffffffffffffffda RBX: 00000000016e2030 RCX: 00007f5693f14b9a
+[ 3117.686894] RDX: 00000000016e2210 RSI: 00000000016e3f30 RDI: 00000000016ee040
+[ 3117.686896] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000013
+[ 3117.686899] R10: 00000000c0ed0000 R11: 0000000000000206 R12: 00000000016ee040
+[ 3117.686901] R13: 00000000016e2210 R14: 0000000000000000 R15: 0000000000000003
+
+[ 3117.687005] Allocated by task 1225:
+[ 3117.687152]  kasan_kmalloc+0xa6/0xd0
+[ 3117.687157]  kmem_cache_alloc_trace+0xfd/0x200
+[ 3117.687161]  f2fs_build_segment_manager+0x2d09/0x3190
+[ 3117.687165]  f2fs_fill_super+0x1948/0x2b40
+[ 3117.687168]  mount_bdev+0x1c0/0x200
+[ 3117.687171]  mount_fs+0x5c/0x190
+[ 3117.687174]  vfs_kern_mount+0x64/0x190
+[ 3117.687177]  do_mount+0x2e4/0x1450
+[ 3117.687180]  ksys_mount+0x7e/0xd0
+[ 3117.687182]  __x64_sys_mount+0x62/0x70
+[ 3117.687186]  do_syscall_64+0x73/0x160
+[ 3117.687190]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+[ 3117.687285] Freed by task 19:
+[ 3117.687412]  __kasan_slab_free+0x137/0x190
+[ 3117.687416]  kfree+0x8b/0x1b0
+[ 3117.687460]  ttm_bo_man_put_node+0x61/0x80 [ttm]
+[ 3117.687476]  ttm_bo_cleanup_refs+0x15f/0x250 [ttm]
+[ 3117.687492]  ttm_bo_delayed_delete+0x2f0/0x300 [ttm]
+[ 3117.687507]  ttm_bo_delayed_workqueue+0x17/0x50 [ttm]
+[ 3117.687528]  process_one_work+0x2f9/0x740
+[ 3117.687531]  worker_thread+0x78/0x6b0
+[ 3117.687541]  kthread+0x177/0x1c0
+[ 3117.687545]  ret_from_fork+0x35/0x40
+
+[ 3117.687638] The buggy address belongs to the object at ffff88018f0a6300
+                which belongs to the cache kmalloc-192 of size 192
+[ 3117.688014] The buggy address is located 16 bytes to the right of
+                192-byte region [ffff88018f0a6300, ffff88018f0a63c0)
+[ 3117.688382] The buggy address belongs to the page:
+[ 3117.688554] page:ffffea00063c2980 count:1 mapcount:0 mapping:ffff8801f3403180 index:0x0
+[ 3117.688788] flags: 0x17fff8000000100(slab)
+[ 3117.688944] raw: 017fff8000000100 ffffea00063c2840 0000000e0000000e ffff8801f3403180
+[ 3117.689166] raw: 0000000000000000 0000000080100010 00000001ffffffff 0000000000000000
+[ 3117.689386] page dumped because: kasan: bad access detected
+
+[ 3117.689653] Memory state around the buggy address:
+[ 3117.689816]  ffff88018f0a6280: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
+[ 3117.690027]  ffff88018f0a6300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[ 3117.690239] >ffff88018f0a6380: 00 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+[ 3117.690448]                                                  ^
+[ 3117.690644]  ffff88018f0a6400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[ 3117.690868]  ffff88018f0a6480: 00 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc
+[ 3117.691077] ==================================================================
+[ 3117.691290] Disabling lock debugging due to kernel taint
+[ 3117.693893] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
+[ 3117.694120] PGD 80000001f01bc067 P4D 80000001f01bc067 PUD 1d9638067 PMD 0
+[ 3117.694338] Oops: 0002 [#1] SMP KASAN PTI
+[ 3117.694490] CPU: 1 PID: 1225 Comm: mount Tainted: G    B   W         4.17.0+ #1
+[ 3117.694703] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 3117.695073] RIP: 0010:__remove_dirty_segment+0xe2/0x1e0
+[ 3117.695246] Code: c4 48 89 c7 e8 cf bb d7 ff 45 0f b6 24 24 41 83 e4 3f 44 88 64 24 07 41 83 e4 3f 4a 8d 7c e3 08 e8 b3 bc d7 ff 4a 8b 4c e3 08 <f0> 4c 0f b3 29 0f 82 94 00 00 00 48 8d bd 20 04 00 00 e8 97 bb d7
+[ 3117.695793] RSP: 0018:ffff88018eb67638 EFLAGS: 00010292
+[ 3117.695969] RAX: 0000000000000000 RBX: ffff88018f0a6300 RCX: 0000000000000000
+[ 3117.696182] RDX: 0000000000000000 RSI: 0000000000000297 RDI: 0000000000000297
+[ 3117.696391] RBP: ffff88018ebe9980 R08: ffffed003e743ebb R09: ffffed003e743ebb
+[ 3117.696604] R10: 0000000000000001 R11: ffffed003e743eba R12: 0000000000000019
+[ 3117.696813] R13: 0000000000000014 R14: 0000000000000320 R15: ffff88018ebe99e0
+[ 3117.697032] FS:  00007f5694636840(0000) GS:ffff8801f3b00000(0000) knlGS:0000000000000000
+[ 3117.697280] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 3117.702357] CR2: 00007fe89bb1a000 CR3: 0000000191c22000 CR4: 00000000000006e0
+[ 3117.707235] Call Trace:
+[ 3117.712077]  locate_dirty_segment+0x189/0x190
+[ 3117.716891]  f2fs_allocate_new_segments+0xa9/0xe0
+[ 3117.721617]  recover_data+0x703/0x2c20
+[ 3117.726316]  ? f2fs_recover_fsync_data+0x48f/0xd50
+[ 3117.730957]  ? ksys_mount+0x7e/0xd0
+[ 3117.735573]  ? policy_nodemask+0x1a/0x90
+[ 3117.740198]  ? policy_node+0x56/0x70
+[ 3117.744829]  ? add_fsync_inode+0xf0/0xf0
+[ 3117.749487]  ? blk_finish_plug+0x44/0x60
+[ 3117.754152]  ? f2fs_ra_meta_pages+0x38b/0x5e0
+[ 3117.758831]  ? find_inode_fast+0xac/0xc0
+[ 3117.763448]  ? f2fs_is_valid_blkaddr+0x320/0x320
+[ 3117.768046]  ? __radix_tree_lookup+0x150/0x150
+[ 3117.772603]  ? dqget+0x670/0x670
+[ 3117.777159]  ? pagecache_get_page+0x29/0x410
+[ 3117.781648]  ? kmem_cache_alloc+0x176/0x1e0
+[ 3117.786067]  ? f2fs_is_valid_blkaddr+0x11d/0x320
+[ 3117.790476]  f2fs_recover_fsync_data+0xc23/0xd50
+[ 3117.794790]  ? f2fs_space_for_roll_forward+0x60/0x60
+[ 3117.799086]  ? rb_insert_color+0x323/0x3d0
+[ 3117.803304]  ? f2fs_recover_orphan_inodes+0xa5/0x700
+[ 3117.807563]  ? proc_register+0x153/0x1d0
+[ 3117.811766]  ? f2fs_remove_orphan_inode+0x10/0x10
+[ 3117.815947]  ? f2fs_attr_store+0x50/0x50
+[ 3117.820087]  ? proc_create_single_data+0x52/0x60
+[ 3117.824262]  f2fs_fill_super+0x1d06/0x2b40
+[ 3117.828367]  ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.832432]  ? sget_userns+0x65e/0x690
+[ 3117.836500]  ? set_blocksize+0x88/0x130
+[ 3117.840501]  ? f2fs_commit_super+0x1a0/0x1a0
+[ 3117.844420]  mount_bdev+0x1c0/0x200
+[ 3117.848275]  mount_fs+0x5c/0x190
+[ 3117.852053]  vfs_kern_mount+0x64/0x190
+[ 3117.855810]  do_mount+0x2e4/0x1450
+[ 3117.859441]  ? lockref_put_return+0x130/0x130
+[ 3117.862996]  ? copy_mount_string+0x20/0x20
+[ 3117.866417]  ? kasan_unpoison_shadow+0x31/0x40
+[ 3117.869719]  ? kasan_kmalloc+0xa6/0xd0
+[ 3117.872948]  ? memcg_kmem_put_cache+0x16/0x90
+[ 3117.876121]  ? __kmalloc_track_caller+0x196/0x210
+[ 3117.879333]  ? _copy_from_user+0x61/0x90
+[ 3117.882467]  ? memdup_user+0x3e/0x60
+[ 3117.885604]  ksys_mount+0x7e/0xd0
+[ 3117.888700]  __x64_sys_mount+0x62/0x70
+[ 3117.891742]  do_syscall_64+0x73/0x160
+[ 3117.894692]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 3117.897669] RIP: 0033:0x7f5693f14b9a
+[ 3117.900563] Code: 48 8b 0d 01 c3 2b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 49 89 ca b8 a5 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d ce c2 2b 00 f7 d8 64 89 01 48
+[ 3117.906922] RSP: 002b:00007fff27346488 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5
+[ 3117.910159] RAX: ffffffffffffffda RBX: 00000000016e2030 RCX: 00007f5693f14b9a
+[ 3117.913469] RDX: 00000000016e2210 RSI: 00000000016e3f30 RDI: 00000000016ee040
+[ 3117.916764] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000013
+[ 3117.920071] R10: 00000000c0ed0000 R11: 0000000000000206 R12: 00000000016ee040
+[ 3117.923393] R13: 00000000016e2210 R14: 0000000000000000 R15: 0000000000000003
+[ 3117.926680] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_timer joydev input_leds serio_raw snd soundcore mac_hid i2c_piix4 ib_iser rdma_cm iw_cm ib_cm ib_core configfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi btrfs zstd_decompress zstd_compress xxhash raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear 8139too qxl ttm drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops drm crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcbc aesni_intel psmouse aes_x86_64 8139cp crypto_simd cryptd mii glue_helper pata_acpi floppy
+[ 3117.949979] CR2: 0000000000000000
+[ 3117.954283] ---[ end trace a8e0d899985faf32 ]---
+[ 3117.958575] RIP: 0010:__remove_dirty_segment+0xe2/0x1e0
+[ 3117.962810] Code: c4 48 89 c7 e8 cf bb d7 ff 45 0f b6 24 24 41 83 e4 3f 44 88 64 24 07 41 83 e4 3f 4a 8d 7c e3 08 e8 b3 bc d7 ff 4a 8b 4c e3 08 <f0> 4c 0f b3 29 0f 82 94 00 00 00 48 8d bd 20 04 00 00 e8 97 bb d7
+[ 3117.971789] RSP: 0018:ffff88018eb67638 EFLAGS: 00010292
+[ 3117.976333] RAX: 0000000000000000 RBX: ffff88018f0a6300 RCX: 0000000000000000
+[ 3117.980926] RDX: 0000000000000000 RSI: 0000000000000297 RDI: 0000000000000297
+[ 3117.985497] RBP: ffff88018ebe9980 R08: ffffed003e743ebb R09: ffffed003e743ebb
+[ 3117.990098] R10: 0000000000000001 R11: ffffed003e743eba R12: 0000000000000019
+[ 3117.994761] R13: 0000000000000014 R14: 0000000000000320 R15: ffff88018ebe99e0
+[ 3117.999392] FS:  00007f5694636840(0000) GS:ffff8801f3b00000(0000) knlGS:0000000000000000
+[ 3118.004096] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[ 3118.008816] CR2: 00007fe89bb1a000 CR3: 0000000191c22000 CR4: 00000000000006e0
+
+- Location
+https://elixir.bootlin.com/linux/v4.18-rc3/source/fs/f2fs/segment.c#L775
+               if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
+                       dirty_i->nr_dirty[t]--;
+Here dirty_i->dirty_segmap[t] can be NULL which leads to crash in test_and_clear_bit()
+
+Reported-by Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4: The function is called sanity_check_ckpt()]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c |    8 ++++----
+ fs/f2fs/super.c      |   12 ++++++++++++
+ 2 files changed, 16 insertions(+), 4 deletions(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -731,15 +731,15 @@ int get_valid_checkpoint(struct f2fs_sb_
+       cp_block = (struct f2fs_checkpoint *)page_address(cur_page);
+       memcpy(sbi->ckpt, cp_block, blk_size);
+-      /* Sanity checking of checkpoint */
+-      if (sanity_check_ckpt(sbi))
+-              goto free_fail_no_cp;
+-
+       if (cur_page == cp1)
+               sbi->cur_cp_pack = 1;
+       else
+               sbi->cur_cp_pack = 2;
++      /* Sanity checking of checkpoint */
++      if (sanity_check_ckpt(sbi))
++              goto free_fail_no_cp;
++
+       if (cp_blks <= 1)
+               goto done;
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1141,6 +1141,7 @@ int sanity_check_ckpt(struct f2fs_sb_inf
+       unsigned int sit_bitmap_size, nat_bitmap_size;
+       unsigned int log_blocks_per_seg;
+       unsigned int segment_count_main;
++      unsigned int cp_pack_start_sum, cp_payload;
+       block_t user_block_count;
+       int i;
+@@ -1201,6 +1202,17 @@ int sanity_check_ckpt(struct f2fs_sb_inf
+               return 1;
+       }
++      cp_pack_start_sum = __start_sum_addr(sbi);
++      cp_payload = __cp_payload(sbi);
++      if (cp_pack_start_sum < cp_payload + 1 ||
++              cp_pack_start_sum > blocks_per_seg - 1 -
++                      NR_CURSEG_TYPE) {
++              f2fs_msg(sbi->sb, KERN_ERR,
++                      "Wrong cp_pack_start_sum: %u",
++                      cp_pack_start_sum);
++              return 1;
++      }
++
+       if (unlikely(f2fs_cp_error(sbi))) {
+               f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck");
+               return 1;
diff --git a/queue-4.4/f2fs-fix-to-do-sanity-check-with-node-footer-and-iblocks.patch b/queue-4.4/f2fs-fix-to-do-sanity-check-with-node-footer-and-iblocks.patch
new file mode 100644 (file)
index 0000000..44d87b5
--- /dev/null
@@ -0,0 +1,240 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Fri, 29 Jun 2018 13:55:22 +0800
+Subject: f2fs: fix to do sanity check with node footer and iblocks
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit e34438c903b653daca2b2a7de95aed46226f8ed3 upstream.
+
+This patch adds to do sanity check with below fields of inode to
+avoid reported panic.
+- node footer
+- iblocks
+
+https://bugzilla.kernel.org/show_bug.cgi?id=200223
+
+- Overview
+BUG() triggered in f2fs_truncate_inode_blocks() when un-mounting a mounted f2fs image after writing to it
+
+- Reproduce
+
+- POC (poc.c)
+
+static void activity(char *mpoint) {
+
+  char *foo_bar_baz;
+  int err;
+
+  static int buf[8192];
+  memset(buf, 0, sizeof(buf));
+
+  err = asprintf(&foo_bar_baz, "%s/foo/bar/baz", mpoint);
+
+  // open / write / read
+  int fd = open(foo_bar_baz, O_RDWR | O_TRUNC, 0777);
+  if (fd >= 0) {
+    write(fd, (char *)buf, 517);
+    write(fd, (char *)buf, sizeof(buf));
+    close(fd);
+  }
+
+}
+
+int main(int argc, char *argv[]) {
+  activity(argv[1]);
+  return 0;
+}
+
+- Kernel meesage
+[  552.479723] F2FS-fs (loop0): Mounted with checkpoint version = 2
+[  556.451891] ------------[ cut here ]------------
+[  556.451899] kernel BUG at fs/f2fs/node.c:987!
+[  556.452920] invalid opcode: 0000 [#1] SMP KASAN PTI
+[  556.453936] CPU: 1 PID: 1310 Comm: umount Not tainted 4.18.0-rc1+ #4
+[  556.455213] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  556.457140] RIP: 0010:f2fs_truncate_inode_blocks+0x4a7/0x6f0
+[  556.458280] Code: e8 ae ea ff ff 41 89 c7 c1 e8 1f 84 c0 74 0a 41 83 ff fe 0f 85 35 ff ff ff 81 85 b0 fe ff ff fb 03 00 00 e9 f7 fd ff ff 0f 0b <0f> 0b e8 62 b7 9a 00 48 8b bd a0 fe ff ff e8 56 54 ae ff 48 8b b5
+[  556.462015] RSP: 0018:ffff8801f292f808 EFLAGS: 00010286
+[  556.463068] RAX: ffffed003e73242d RBX: ffff8801f292f958 RCX: ffffffffb88b81bc
+[  556.464479] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffff8801f3992164
+[  556.465901] RBP: ffff8801f292f980 R08: ffffed003e73242d R09: ffffed003e73242d
+[  556.467311] R10: 0000000000000001 R11: ffffed003e73242c R12: 00000000fffffc64
+[  556.468706] R13: ffff8801f3992000 R14: 0000000000000058 R15: 00000000ffff8801
+[  556.470117] FS:  00007f8029297840(0000) GS:ffff8801f6f00000(0000) knlGS:0000000000000000
+[  556.471702] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  556.472838] CR2: 000055f5f57305d8 CR3: 00000001f18b0000 CR4: 00000000000006e0
+[  556.474265] Call Trace:
+[  556.474782]  ? f2fs_alloc_nid_failed+0xf0/0xf0
+[  556.475686]  ? truncate_nodes+0x980/0x980
+[  556.476516]  ? pagecache_get_page+0x21f/0x2f0
+[  556.477412]  ? __asan_loadN+0xf/0x20
+[  556.478153]  ? __get_node_page+0x331/0x5b0
+[  556.478992]  ? reweight_entity+0x1e6/0x3b0
+[  556.479826]  f2fs_truncate_blocks+0x55e/0x740
+[  556.480709]  ? f2fs_truncate_data_blocks+0x20/0x20
+[  556.481689]  ? __radix_tree_lookup+0x34/0x160
+[  556.482630]  ? radix_tree_lookup+0xd/0x10
+[  556.483445]  f2fs_truncate+0xd4/0x1a0
+[  556.484206]  f2fs_evict_inode+0x5ce/0x630
+[  556.485032]  evict+0x16f/0x290
+[  556.485664]  iput+0x280/0x300
+[  556.486300]  dentry_unlink_inode+0x165/0x1e0
+[  556.487169]  __dentry_kill+0x16a/0x260
+[  556.487936]  dentry_kill+0x70/0x250
+[  556.488651]  shrink_dentry_list+0x125/0x260
+[  556.489504]  shrink_dcache_parent+0xc1/0x110
+[  556.490379]  ? shrink_dcache_sb+0x200/0x200
+[  556.491231]  ? bit_wait_timeout+0xc0/0xc0
+[  556.492047]  do_one_tree+0x12/0x40
+[  556.492743]  shrink_dcache_for_umount+0x3f/0xa0
+[  556.493656]  generic_shutdown_super+0x43/0x1c0
+[  556.494561]  kill_block_super+0x52/0x80
+[  556.495341]  kill_f2fs_super+0x62/0x70
+[  556.496105]  deactivate_locked_super+0x6f/0xa0
+[  556.497004]  deactivate_super+0x5e/0x80
+[  556.497785]  cleanup_mnt+0x61/0xa0
+[  556.498492]  __cleanup_mnt+0x12/0x20
+[  556.499218]  task_work_run+0xc8/0xf0
+[  556.499949]  exit_to_usermode_loop+0x125/0x130
+[  556.500846]  do_syscall_64+0x138/0x170
+[  556.501609]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[  556.502659] RIP: 0033:0x7f8028b77487
+[  556.503384] Code: 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 31 f6 e9 09 00 00 00 66 0f 1f 84 00 00 00 00 00 b8 a6 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d e1 c9 2b 00 f7 d8 64 89 01 48
+[  556.507137] RSP: 002b:00007fff9f2e3598 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
+[  556.508637] RAX: 0000000000000000 RBX: 0000000000ebd030 RCX: 00007f8028b77487
+[  556.510069] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000000000ec41e0
+[  556.511481] RBP: 0000000000ec41e0 R08: 0000000000000000 R09: 0000000000000014
+[  556.512892] R10: 00000000000006b2 R11: 0000000000000246 R12: 00007f802908083c
+[  556.514320] R13: 0000000000000000 R14: 0000000000ebd210 R15: 00007fff9f2e3820
+[  556.515745] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
+[  556.529276] ---[ end trace 4ce02f25ff7d3df5 ]---
+[  556.530340] RIP: 0010:f2fs_truncate_inode_blocks+0x4a7/0x6f0
+[  556.531513] Code: e8 ae ea ff ff 41 89 c7 c1 e8 1f 84 c0 74 0a 41 83 ff fe 0f 85 35 ff ff ff 81 85 b0 fe ff ff fb 03 00 00 e9 f7 fd ff ff 0f 0b <0f> 0b e8 62 b7 9a 00 48 8b bd a0 fe ff ff e8 56 54 ae ff 48 8b b5
+[  556.535330] RSP: 0018:ffff8801f292f808 EFLAGS: 00010286
+[  556.536395] RAX: ffffed003e73242d RBX: ffff8801f292f958 RCX: ffffffffb88b81bc
+[  556.537824] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffff8801f3992164
+[  556.539290] RBP: ffff8801f292f980 R08: ffffed003e73242d R09: ffffed003e73242d
+[  556.540709] R10: 0000000000000001 R11: ffffed003e73242c R12: 00000000fffffc64
+[  556.542131] R13: ffff8801f3992000 R14: 0000000000000058 R15: 00000000ffff8801
+[  556.543579] FS:  00007f8029297840(0000) GS:ffff8801f6f00000(0000) knlGS:0000000000000000
+[  556.545180] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  556.546338] CR2: 000055f5f57305d8 CR3: 00000001f18b0000 CR4: 00000000000006e0
+[  556.547809] ==================================================================
+[  556.549248] BUG: KASAN: stack-out-of-bounds in arch_tlb_gather_mmu+0x52/0x170
+[  556.550672] Write of size 8 at addr ffff8801f292fd10 by task umount/1310
+
+[  556.552338] CPU: 1 PID: 1310 Comm: umount Tainted: G      D           4.18.0-rc1+ #4
+[  556.553886] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  556.555756] Call Trace:
+[  556.556264]  dump_stack+0x7b/0xb5
+[  556.556944]  print_address_description+0x70/0x290
+[  556.557903]  kasan_report+0x291/0x390
+[  556.558649]  ? arch_tlb_gather_mmu+0x52/0x170
+[  556.559537]  __asan_store8+0x57/0x90
+[  556.560268]  arch_tlb_gather_mmu+0x52/0x170
+[  556.561110]  tlb_gather_mmu+0x12/0x40
+[  556.561862]  exit_mmap+0x123/0x2a0
+[  556.562555]  ? __ia32_sys_munmap+0x50/0x50
+[  556.563384]  ? exit_aio+0x98/0x230
+[  556.564079]  ? __x32_compat_sys_io_submit+0x260/0x260
+[  556.565099]  ? taskstats_exit+0x1f4/0x640
+[  556.565925]  ? kasan_check_read+0x11/0x20
+[  556.566739]  ? mm_update_next_owner+0x322/0x380
+[  556.567652]  mmput+0x8b/0x1d0
+[  556.568260]  do_exit+0x43a/0x1390
+[  556.568937]  ? mm_update_next_owner+0x380/0x380
+[  556.569855]  ? deactivate_super+0x5e/0x80
+[  556.570668]  ? cleanup_mnt+0x61/0xa0
+[  556.571395]  ? __cleanup_mnt+0x12/0x20
+[  556.572156]  ? task_work_run+0xc8/0xf0
+[  556.572917]  ? exit_to_usermode_loop+0x125/0x130
+[  556.573861]  rewind_stack_do_exit+0x17/0x20
+[  556.574707] RIP: 0033:0x7f8028b77487
+[  556.575428] Code: Bad RIP value.
+[  556.576106] RSP: 002b:00007fff9f2e3598 EFLAGS: 00000246 ORIG_RAX: 00000000000000a6
+[  556.577599] RAX: 0000000000000000 RBX: 0000000000ebd030 RCX: 00007f8028b77487
+[  556.579020] RDX: 0000000000000001 RSI: 0000000000000000 RDI: 0000000000ec41e0
+[  556.580422] RBP: 0000000000ec41e0 R08: 0000000000000000 R09: 0000000000000014
+[  556.581833] R10: 00000000000006b2 R11: 0000000000000246 R12: 00007f802908083c
+[  556.583252] R13: 0000000000000000 R14: 0000000000ebd210 R15: 00007fff9f2e3820
+
+[  556.584983] The buggy address belongs to the page:
+[  556.585961] page:ffffea0007ca4bc0 count:0 mapcount:0 mapping:0000000000000000 index:0x0
+[  556.587540] flags: 0x2ffff0000000000()
+[  556.588296] raw: 02ffff0000000000 0000000000000000 dead000000000200 0000000000000000
+[  556.589822] raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
+[  556.591359] page dumped because: kasan: bad access detected
+
+[  556.592786] Memory state around the buggy address:
+[  556.593753]  ffff8801f292fc00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[  556.595191]  ffff8801f292fc80: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 00 00
+[  556.596613] >ffff8801f292fd00: 00 00 f3 00 00 00 00 f3 f3 00 00 00 00 f4 f4 f4
+[  556.598044]                          ^
+[  556.598797]  ffff8801f292fd80: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
+[  556.600225]  ffff8801f292fe00: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 f4 f4 f4
+[  556.601647] ==================================================================
+
+- Location
+https://elixir.bootlin.com/linux/v4.18-rc1/source/fs/f2fs/node.c#L987
+               case NODE_DIND_BLOCK:
+                       err = truncate_nodes(&dn, nofs, offset[1], 3);
+                       cont = 0;
+                       break;
+
+               default:
+                       BUG(); <---
+               }
+
+Reported-by Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/inode.c |   25 +++++++++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -95,9 +95,30 @@ static void __recover_inline_status(stru
+       return;
+ }
+-static bool sanity_check_inode(struct inode *inode)
++static bool sanity_check_inode(struct inode *inode, struct page *node_page)
+ {
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
++      unsigned long long iblocks;
++
++      iblocks = le64_to_cpu(F2FS_INODE(node_page)->i_blocks);
++      if (!iblocks) {
++              set_sbi_flag(sbi, SBI_NEED_FSCK);
++              f2fs_msg(sbi->sb, KERN_WARNING,
++                      "%s: corrupted inode i_blocks i_ino=%lx iblocks=%llu, "
++                      "run fsck to fix.",
++                      __func__, inode->i_ino, iblocks);
++              return false;
++      }
++
++      if (ino_of_node(node_page) != nid_of_node(node_page)) {
++              set_sbi_flag(sbi, SBI_NEED_FSCK);
++              f2fs_msg(sbi->sb, KERN_WARNING,
++                      "%s: corrupted inode footer i_ino=%lx, ino,nid: "
++                      "[%u, %u] run fsck to fix.",
++                      __func__, inode->i_ino,
++                      ino_of_node(node_page), nid_of_node(node_page));
++              return false;
++      }
+       return true;
+ }
+@@ -150,7 +171,7 @@ static int do_read_inode(struct inode *i
+       get_inline_info(fi, ri);
+-      if (!sanity_check_inode(inode)) {
++      if (!sanity_check_inode(inode, node_page)) {
+               f2fs_put_page(node_page, 1);
+               return -EINVAL;
+       }
diff --git a/queue-4.4/f2fs-fix-to-do-sanity-check-with-reserved-blkaddr-of-inline-inode.patch b/queue-4.4/f2fs-fix-to-do-sanity-check-with-reserved-blkaddr-of-inline-inode.patch
new file mode 100644 (file)
index 0000000..37b1c7c
--- /dev/null
@@ -0,0 +1,158 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Sat, 30 Jun 2018 18:13:40 +0800
+Subject: f2fs: fix to do sanity check with reserved blkaddr of inline inode
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit 4dbe38dc386910c668c75ae616b99b823b59f3eb upstream.
+
+As Wen Xu reported in bugzilla, after image was injected with random data
+by fuzzing, inline inode would contain invalid reserved blkaddr, then
+during inline conversion, we will encounter illegal memory accessing
+reported by KASAN, the root cause of this is when writing out converted
+inline page, we will use invalid reserved blkaddr to update sit bitmap,
+result in accessing memory beyond sit bitmap boundary.
+
+In order to fix this issue, let's do sanity check with reserved block
+address of inline inode to avoid above condition.
+
+https://bugzilla.kernel.org/show_bug.cgi?id=200179
+
+[ 1428.846352] BUG: KASAN: use-after-free in update_sit_entry+0x80/0x7f0
+[ 1428.846618] Read of size 4 at addr ffff880194483540 by task a.out/2741
+
+[ 1428.846855] CPU: 0 PID: 2741 Comm: a.out Tainted: G        W         4.17.0+ #1
+[ 1428.846858] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[ 1428.846860] Call Trace:
+[ 1428.846868]  dump_stack+0x71/0xab
+[ 1428.846875]  print_address_description+0x6b/0x290
+[ 1428.846881]  kasan_report+0x28e/0x390
+[ 1428.846888]  ? update_sit_entry+0x80/0x7f0
+[ 1428.846898]  update_sit_entry+0x80/0x7f0
+[ 1428.846906]  f2fs_allocate_data_block+0x6db/0xc70
+[ 1428.846914]  ? f2fs_get_node_info+0x14f/0x590
+[ 1428.846920]  do_write_page+0xc8/0x150
+[ 1428.846928]  f2fs_outplace_write_data+0xfe/0x210
+[ 1428.846935]  ? f2fs_do_write_node_page+0x170/0x170
+[ 1428.846941]  ? radix_tree_tag_clear+0xff/0x130
+[ 1428.846946]  ? __mod_node_page_state+0x22/0xa0
+[ 1428.846951]  ? inc_zone_page_state+0x54/0x100
+[ 1428.846956]  ? __test_set_page_writeback+0x336/0x5d0
+[ 1428.846964]  f2fs_convert_inline_page+0x407/0x6d0
+[ 1428.846971]  ? f2fs_read_inline_data+0x3b0/0x3b0
+[ 1428.846978]  ? __get_node_page+0x335/0x6b0
+[ 1428.846987]  f2fs_convert_inline_inode+0x41b/0x500
+[ 1428.846994]  ? f2fs_convert_inline_page+0x6d0/0x6d0
+[ 1428.847000]  ? kasan_unpoison_shadow+0x31/0x40
+[ 1428.847005]  ? kasan_kmalloc+0xa6/0xd0
+[ 1428.847024]  f2fs_file_mmap+0x79/0xc0
+[ 1428.847029]  mmap_region+0x58b/0x880
+[ 1428.847037]  ? arch_get_unmapped_area+0x370/0x370
+[ 1428.847042]  do_mmap+0x55b/0x7a0
+[ 1428.847048]  vm_mmap_pgoff+0x16f/0x1c0
+[ 1428.847055]  ? vma_is_stack_for_current+0x50/0x50
+[ 1428.847062]  ? __fsnotify_update_child_dentry_flags.part.1+0x160/0x160
+[ 1428.847068]  ? do_sys_open+0x206/0x2a0
+[ 1428.847073]  ? __fget+0xb4/0x100
+[ 1428.847079]  ksys_mmap_pgoff+0x278/0x360
+[ 1428.847085]  ? find_mergeable_anon_vma+0x50/0x50
+[ 1428.847091]  do_syscall_64+0x73/0x160
+[ 1428.847098]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[ 1428.847102] RIP: 0033:0x7fb1430766ba
+[ 1428.847103] Code: 89 f5 41 54 49 89 fc 55 53 74 35 49 63 e8 48 63 da 4d 89 f9 49 89 e8 4d 63 d6 48 89 da 4c 89 ee 4c 89 e7 b8 09 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 56 5b 5d 41 5c 41 5d 41 5e 41 5f c3 0f 1f 00
+[ 1428.847162] RSP: 002b:00007ffc651d9388 EFLAGS: 00000246 ORIG_RAX: 0000000000000009
+[ 1428.847167] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 00007fb1430766ba
+[ 1428.847170] RDX: 0000000000000001 RSI: 0000000000001000 RDI: 0000000000000000
+[ 1428.847173] RBP: 0000000000000003 R08: 0000000000000003 R09: 0000000000000000
+[ 1428.847176] R10: 0000000000008002 R11: 0000000000000246 R12: 0000000000000000
+[ 1428.847179] R13: 0000000000001000 R14: 0000000000008002 R15: 0000000000000000
+
+[ 1428.847252] Allocated by task 2683:
+[ 1428.847372]  kasan_kmalloc+0xa6/0xd0
+[ 1428.847380]  kmem_cache_alloc+0xc8/0x1e0
+[ 1428.847385]  getname_flags+0x73/0x2b0
+[ 1428.847390]  user_path_at_empty+0x1d/0x40
+[ 1428.847395]  vfs_statx+0xc1/0x150
+[ 1428.847401]  __do_sys_newlstat+0x7e/0xd0
+[ 1428.847405]  do_syscall_64+0x73/0x160
+[ 1428.847411]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+[ 1428.847466] Freed by task 2683:
+[ 1428.847566]  __kasan_slab_free+0x137/0x190
+[ 1428.847571]  kmem_cache_free+0x85/0x1e0
+[ 1428.847575]  filename_lookup+0x191/0x280
+[ 1428.847580]  vfs_statx+0xc1/0x150
+[ 1428.847585]  __do_sys_newlstat+0x7e/0xd0
+[ 1428.847590]  do_syscall_64+0x73/0x160
+[ 1428.847596]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+[ 1428.847648] The buggy address belongs to the object at ffff880194483300
+                which belongs to the cache names_cache of size 4096
+[ 1428.847946] The buggy address is located 576 bytes inside of
+                4096-byte region [ffff880194483300, ffff880194484300)
+[ 1428.848234] The buggy address belongs to the page:
+[ 1428.848366] page:ffffea0006512000 count:1 mapcount:0 mapping:ffff8801f3586380 index:0x0 compound_mapcount: 0
+[ 1428.848606] flags: 0x17fff8000008100(slab|head)
+[ 1428.848737] raw: 017fff8000008100 dead000000000100 dead000000000200 ffff8801f3586380
+[ 1428.848931] raw: 0000000000000000 0000000000070007 00000001ffffffff 0000000000000000
+[ 1428.849122] page dumped because: kasan: bad access detected
+
+[ 1428.849305] Memory state around the buggy address:
+[ 1428.849436]  ffff880194483400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+[ 1428.849620]  ffff880194483480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+[ 1428.849804] >ffff880194483500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+[ 1428.849985]                                            ^
+[ 1428.850120]  ffff880194483580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+[ 1428.850303]  ffff880194483600: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
+[ 1428.850498] ==================================================================
+
+Reported-by: Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[bwh: Backported to 4.4: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/inline.c |   21 +++++++++++++++++++++
+ 1 file changed, 21 insertions(+)
+
+--- a/fs/f2fs/inline.c
++++ b/fs/f2fs/inline.c
+@@ -127,6 +127,16 @@ int f2fs_convert_inline_page(struct dnod
+       if (err)
+               return err;
++      if (unlikely(dn->data_blkaddr != NEW_ADDR)) {
++              f2fs_put_dnode(dn);
++              set_sbi_flag(fio.sbi, SBI_NEED_FSCK);
++              f2fs_msg(fio.sbi->sb, KERN_WARNING,
++                      "%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, "
++                      "run fsck to fix.",
++                      __func__, dn->inode->i_ino, dn->data_blkaddr);
++              return -EINVAL;
++      }
++
+       f2fs_wait_on_page_writeback(page, DATA);
+       if (PageUptodate(page))
+@@ -386,6 +396,17 @@ static int f2fs_move_inline_dirents(stru
+       if (err)
+               goto out;
++      if (unlikely(dn.data_blkaddr != NEW_ADDR)) {
++              f2fs_put_dnode(&dn);
++              set_sbi_flag(F2FS_P_SB(page), SBI_NEED_FSCK);
++              f2fs_msg(F2FS_P_SB(page)->sb, KERN_WARNING,
++                      "%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, "
++                      "run fsck to fix.",
++                      __func__, dir->i_ino, dn.data_blkaddr);
++              err = -EINVAL;
++              goto out;
++      }
++
+       f2fs_wait_on_page_writeback(page, DATA);
+       zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE);
diff --git a/queue-4.4/f2fs-fix-to-do-sanity-check-with-secs_per_zone.patch b/queue-4.4/f2fs-fix-to-do-sanity-check-with-secs_per_zone.patch
new file mode 100644 (file)
index 0000000..e08d31d
--- /dev/null
@@ -0,0 +1,98 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Sat, 23 Jun 2018 00:12:36 +0800
+Subject: f2fs: fix to do sanity check with secs_per_zone
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit 42bf546c1fe3f3654bdf914e977acbc2b80a5be5 upstream.
+
+As Wen Xu reported in below link:
+
+https://bugzilla.kernel.org/show_bug.cgi?id=200183
+
+- Overview
+Divide zero in reset_curseg() when mounting a crafted f2fs image
+
+- Reproduce
+
+- Kernel message
+[  588.281510] divide error: 0000 [#1] SMP KASAN PTI
+[  588.282701] CPU: 0 PID: 1293 Comm: mount Not tainted 4.18.0-rc1+ #4
+[  588.284000] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  588.286178] RIP: 0010:reset_curseg+0x94/0x1a0
+[  588.298166] RSP: 0018:ffff8801e88d7940 EFLAGS: 00010246
+[  588.299360] RAX: 0000000000000014 RBX: ffff8801e1d46d00 RCX: ffffffffb88bf60b
+[  588.300809] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffff8801e1d46d64
+[  588.305272] R13: 0000000000000000 R14: 0000000000000014 R15: 0000000000000000
+[  588.306822] FS:  00007fad85008840(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[  588.308456] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  588.309623] CR2: 0000000001705078 CR3: 00000001f30f8000 CR4: 00000000000006f0
+[  588.311085] Call Trace:
+[  588.311637]  f2fs_build_segment_manager+0x103f/0x3410
+[  588.316136]  ? f2fs_commit_super+0x1b0/0x1b0
+[  588.317031]  ? set_blocksize+0x90/0x140
+[  588.319473]  f2fs_mount+0x15/0x20
+[  588.320166]  mount_fs+0x60/0x1a0
+[  588.320847]  ? alloc_vfsmnt+0x309/0x360
+[  588.321647]  vfs_kern_mount+0x6b/0x1a0
+[  588.322432]  do_mount+0x34a/0x18c0
+[  588.323175]  ? strndup_user+0x46/0x70
+[  588.323937]  ? copy_mount_string+0x20/0x20
+[  588.324793]  ? memcg_kmem_put_cache+0x1b/0xa0
+[  588.325702]  ? kasan_check_write+0x14/0x20
+[  588.326562]  ? _copy_from_user+0x6a/0x90
+[  588.327375]  ? memdup_user+0x42/0x60
+[  588.328118]  ksys_mount+0x83/0xd0
+[  588.328808]  __x64_sys_mount+0x67/0x80
+[  588.329607]  do_syscall_64+0x78/0x170
+[  588.330400]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
+[  588.331461] RIP: 0033:0x7fad848e8b9a
+[  588.336022] RSP: 002b:00007ffd7c5b6be8 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5
+[  588.337547] RAX: ffffffffffffffda RBX: 00000000016f8030 RCX: 00007fad848e8b9a
+[  588.338999] RDX: 00000000016f8210 RSI: 00000000016f9f30 RDI: 0000000001700ec0
+[  588.340442] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000013
+[  588.341887] R10: 00000000c0ed0000 R11: 0000000000000206 R12: 0000000001700ec0
+[  588.343341] R13: 00000000016f8210 R14: 0000000000000000 R15: 0000000000000003
+[  588.354891] ---[ end trace 4ce02f25ff7d3df5 ]---
+[  588.355862] RIP: 0010:reset_curseg+0x94/0x1a0
+[  588.360742] RSP: 0018:ffff8801e88d7940 EFLAGS: 00010246
+[  588.361812] RAX: 0000000000000014 RBX: ffff8801e1d46d00 RCX: ffffffffb88bf60b
+[  588.363485] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffff8801e1d46d64
+[  588.365213] RBP: ffff8801e88d7968 R08: ffffed003c32266f R09: ffffed003c32266f
+[  588.366661] R10: 0000000000000001 R11: ffffed003c32266e R12: ffff8801f0337700
+[  588.368110] R13: 0000000000000000 R14: 0000000000000014 R15: 0000000000000000
+[  588.370057] FS:  00007fad85008840(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
+[  588.372099] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  588.373291] CR2: 0000000001705078 CR3: 00000001f30f8000 CR4: 00000000000006f0
+
+- Location
+https://elixir.bootlin.com/linux/latest/source/fs/f2fs/segment.c#L2147
+        curseg->zone = GET_ZONE_FROM_SEG(sbi, curseg->segno);
+
+If secs_per_zone is corrupted due to fuzzing test, it will cause divide
+zero operation when using GET_ZONE_FROM_SEG macro, so we should do more
+sanity check with secs_per_zone during mount to avoid this issue.
+
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/super.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1088,9 +1088,9 @@ static int sanity_check_raw_super(struct
+               return 1;
+       }
+-      if (secs_per_zone > total_sections) {
++      if (secs_per_zone > total_sections || !secs_per_zone) {
+               f2fs_msg(sb, KERN_INFO,
+-                      "Wrong secs_per_zone (%u > %u)",
++                      "Wrong secs_per_zone / total_sections (%u, %u)",
+                       secs_per_zone, total_sections);
+               return 1;
+       }
diff --git a/queue-4.4/f2fs-fix-to-do-sanity-check-with-user_block_count.patch b/queue-4.4/f2fs-fix-to-do-sanity-check-with-user_block_count.patch
new file mode 100644 (file)
index 0000000..65b2a52
--- /dev/null
@@ -0,0 +1,148 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Wed, 27 Jun 2018 18:05:54 +0800
+Subject: f2fs: fix to do sanity check with user_block_count
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit 9dc956b2c8523aed39d1e6508438be9fea28c8fc upstream.
+
+This patch fixs to do sanity check with user_block_count.
+
+- Overview
+Divide zero in utilization when mount() a corrupted f2fs image
+
+- Reproduce (4.18 upstream kernel)
+
+- Kernel message
+[  564.099503] F2FS-fs (loop0): invalid crc value
+[  564.101991] divide error: 0000 [#1] SMP KASAN PTI
+[  564.103103] CPU: 1 PID: 1298 Comm: f2fs_discard-7: Not tainted 4.18.0-rc1+ #4
+[  564.104584] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  564.106624] RIP: 0010:issue_discard_thread+0x248/0x5c0
+[  564.107692] Code: ff ff 48 8b bd e8 fe ff ff 41 8b 9d 4c 04 00 00 e8 cd b8 ad ff 41 8b 85 50 04 00 00 31 d2 48 8d 04 80 48 8d 04 80 48 c1 e0 02 <48> f7 f3 83 f8 50 7e 16 41 c7 86 7c ff ff ff 01 00 00 00 41 c7 86
+[  564.111686] RSP: 0018:ffff8801f3117dc0 EFLAGS: 00010206
+[  564.112775] RAX: 0000000000000384 RBX: 0000000000000000 RCX: ffffffffb88c1e03
+[  564.114250] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffff8801e3aa4850
+[  564.115706] RBP: ffff8801f3117f00 R08: 1ffffffff751a1d0 R09: fffffbfff751a1d0
+[  564.117177] R10: 0000000000000001 R11: fffffbfff751a1d0 R12: 00000000fffffffc
+[  564.118634] R13: ffff8801e3aa4400 R14: ffff8801f3117ed8 R15: ffff8801e2050000
+[  564.120094] FS:  0000000000000000(0000) GS:ffff8801f6f00000(0000) knlGS:0000000000000000
+[  564.121748] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  564.122923] CR2: 000000000202b078 CR3: 00000001f11ac000 CR4: 00000000000006e0
+[  564.124383] Call Trace:
+[  564.124924]  ? __issue_discard_cmd+0x480/0x480
+[  564.125882]  ? __sched_text_start+0x8/0x8
+[  564.126756]  ? __kthread_parkme+0xcb/0x100
+[  564.127620]  ? kthread_blkcg+0x70/0x70
+[  564.128412]  kthread+0x180/0x1d0
+[  564.129105]  ? __issue_discard_cmd+0x480/0x480
+[  564.130029]  ? kthread_associate_blkcg+0x150/0x150
+[  564.131033]  ret_from_fork+0x35/0x40
+[  564.131794] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
+[  564.141798] ---[ end trace 4ce02f25ff7d3df5 ]---
+[  564.142773] RIP: 0010:issue_discard_thread+0x248/0x5c0
+[  564.143885] Code: ff ff 48 8b bd e8 fe ff ff 41 8b 9d 4c 04 00 00 e8 cd b8 ad ff 41 8b 85 50 04 00 00 31 d2 48 8d 04 80 48 8d 04 80 48 c1 e0 02 <48> f7 f3 83 f8 50 7e 16 41 c7 86 7c ff ff ff 01 00 00 00 41 c7 86
+[  564.147776] RSP: 0018:ffff8801f3117dc0 EFLAGS: 00010206
+[  564.148856] RAX: 0000000000000384 RBX: 0000000000000000 RCX: ffffffffb88c1e03
+[  564.150424] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffff8801e3aa4850
+[  564.151906] RBP: ffff8801f3117f00 R08: 1ffffffff751a1d0 R09: fffffbfff751a1d0
+[  564.153463] R10: 0000000000000001 R11: fffffbfff751a1d0 R12: 00000000fffffffc
+[  564.154915] R13: ffff8801e3aa4400 R14: ffff8801f3117ed8 R15: ffff8801e2050000
+[  564.156405] FS:  0000000000000000(0000) GS:ffff8801f6f00000(0000) knlGS:0000000000000000
+[  564.158070] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[  564.159279] CR2: 000000000202b078 CR3: 00000001f11ac000 CR4: 00000000000006e0
+[  564.161043] ==================================================================
+[  564.162587] BUG: KASAN: stack-out-of-bounds in from_kuid_munged+0x1d/0x50
+[  564.163994] Read of size 4 at addr ffff8801f3117c84 by task f2fs_discard-7:/1298
+
+[  564.165852] CPU: 1 PID: 1298 Comm: f2fs_discard-7: Tainted: G      D           4.18.0-rc1+ #4
+[  564.167593] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
+[  564.169522] Call Trace:
+[  564.170057]  dump_stack+0x7b/0xb5
+[  564.170778]  print_address_description+0x70/0x290
+[  564.171765]  kasan_report+0x291/0x390
+[  564.172540]  ? from_kuid_munged+0x1d/0x50
+[  564.173408]  __asan_load4+0x78/0x80
+[  564.174148]  from_kuid_munged+0x1d/0x50
+[  564.174962]  do_notify_parent+0x1f5/0x4f0
+[  564.175808]  ? send_sigqueue+0x390/0x390
+[  564.176639]  ? css_set_move_task+0x152/0x340
+[  564.184197]  do_exit+0x1290/0x1390
+[  564.184950]  ? __issue_discard_cmd+0x480/0x480
+[  564.185884]  ? mm_update_next_owner+0x380/0x380
+[  564.186829]  ? __sched_text_start+0x8/0x8
+[  564.187672]  ? __kthread_parkme+0xcb/0x100
+[  564.188528]  ? kthread_blkcg+0x70/0x70
+[  564.189333]  ? kthread+0x180/0x1d0
+[  564.190052]  ? __issue_discard_cmd+0x480/0x480
+[  564.190983]  rewind_stack_do_exit+0x17/0x20
+
+[  564.192190] The buggy address belongs to the page:
+[  564.193213] page:ffffea0007cc45c0 count:0 mapcount:0 mapping:0000000000000000 index:0x0
+[  564.194856] flags: 0x2ffff0000000000()
+[  564.195644] raw: 02ffff0000000000 0000000000000000 dead000000000200 0000000000000000
+[  564.197247] raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000
+[  564.198826] page dumped because: kasan: bad access detected
+
+[  564.200299] Memory state around the buggy address:
+[  564.201306]  ffff8801f3117b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[  564.202779]  ffff8801f3117c00: 00 00 00 00 00 00 00 00 00 00 00 f3 f3 f3 f3 f3
+[  564.204252] >ffff8801f3117c80: f3 f3 f3 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
+[  564.205742]                    ^
+[  564.206424]  ffff8801f3117d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+[  564.207908]  ffff8801f3117d80: f3 f3 f3 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
+[  564.209389] ==================================================================
+[  564.231795] F2FS-fs (loop0): Mounted with checkpoint version = 2
+
+- Location
+https://elixir.bootlin.com/linux/v4.18-rc1/source/fs/f2fs/segment.h#L586
+       return div_u64((u64)valid_user_blocks(sbi) * 100,
+                                       sbi->user_block_count);
+Missing checks on sbi->user_block_count.
+
+Reported-by: Wen Xu <wen.xu@gatech.edu>
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/super.c |   13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1140,6 +1140,8 @@ int sanity_check_ckpt(struct f2fs_sb_inf
+       unsigned int sit_segs, nat_segs;
+       unsigned int sit_bitmap_size, nat_bitmap_size;
+       unsigned int log_blocks_per_seg;
++      unsigned int segment_count_main;
++      block_t user_block_count;
+       int i;
+       total = le32_to_cpu(raw_super->segment_count);
+@@ -1164,6 +1166,16 @@ int sanity_check_ckpt(struct f2fs_sb_inf
+               return 1;
+       }
++      user_block_count = le64_to_cpu(ckpt->user_block_count);
++      segment_count_main = le32_to_cpu(raw_super->segment_count_main);
++      log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
++      if (!user_block_count || user_block_count >=
++                      segment_count_main << log_blocks_per_seg) {
++              f2fs_msg(sbi->sb, KERN_ERR,
++                      "Wrong user_block_count: %u", user_block_count);
++              return 1;
++      }
++
+       main_segs = le32_to_cpu(raw_super->segment_count_main);
+       blocks_per_seg = sbi->blocks_per_seg;
+@@ -1180,7 +1192,6 @@ int sanity_check_ckpt(struct f2fs_sb_inf
+       sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize);
+       nat_bitmap_size = le32_to_cpu(ckpt->nat_ver_bitmap_bytesize);
+-      log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
+       if (sit_bitmap_size != ((sit_segs / 2) << log_blocks_per_seg) / 8 ||
+               nat_bitmap_size != ((nat_segs / 2) << log_blocks_per_seg) / 8) {
diff --git a/queue-4.4/f2fs-fix-validation-of-the-block-count-in-sanity_check_raw_super.patch b/queue-4.4/f2fs-fix-validation-of-the-block-count-in-sanity_check_raw_super.patch
new file mode 100644 (file)
index 0000000..03c530e
--- /dev/null
@@ -0,0 +1,56 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Sat, 22 Dec 2018 11:22:26 +0100
+Subject: f2fs: fix validation of the block count in sanity_check_raw_super
+
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+
+commit 88960068f25fcc3759455d85460234dcc9d43fef upstream.
+
+Treat "block_count" from struct f2fs_super_block as 64-bit little endian
+value in sanity_check_raw_super() because struct f2fs_super_block
+declares "block_count" as "__le64".
+
+This fixes a bug where the superblock validation fails on big endian
+devices with the following error:
+  F2FS-fs (sda1): Wrong segment_count / block_count (61439 > 0)
+  F2FS-fs (sda1): Can't find valid F2FS filesystem in 1th superblock
+  F2FS-fs (sda1): Wrong segment_count / block_count (61439 > 0)
+  F2FS-fs (sda1): Can't find valid F2FS filesystem in 2th superblock
+As result of this the partition cannot be mounted.
+
+With this patch applied the superblock validation works fine and the
+partition can be mounted again:
+  F2FS-fs (sda1): Mounted with checkpoint version = 7c84
+
+My little endian x86-64 hardware was able to mount the partition without
+this fix.
+To confirm that mounting f2fs filesystems works on big endian machines
+again I tested this on a 32-bit MIPS big endian (lantiq) device.
+
+Fixes: 0cfe75c5b01199 ("f2fs: enhance sanity_check_raw_super() to avoid potential overflows")
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/super.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1081,10 +1081,10 @@ static int sanity_check_raw_super(struct
+               return 1;
+       }
+-      if (segment_count > (le32_to_cpu(raw_super->block_count) >> 9)) {
++      if (segment_count > (le64_to_cpu(raw_super->block_count) >> 9)) {
+               f2fs_msg(sb, KERN_INFO,
+-                      "Wrong segment_count / block_count (%u > %u)",
+-                      segment_count, le32_to_cpu(raw_super->block_count));
++                      "Wrong segment_count / block_count (%u > %llu)",
++                      segment_count, le64_to_cpu(raw_super->block_count));
+               return 1;
+       }
diff --git a/queue-4.4/f2fs-free-meta-pages-if-sanity-check-for-ckpt-is-failed.patch b/queue-4.4/f2fs-free-meta-pages-if-sanity-check-for-ckpt-is-failed.patch
new file mode 100644 (file)
index 0000000..e89fa2b
--- /dev/null
@@ -0,0 +1,40 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Mon, 5 Dec 2016 17:25:32 -0800
+Subject: f2fs: free meta pages if sanity check for ckpt is failed
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit a2125ff7dd1ed3a2a53cdc1f8f9c9cec9cfaa7ab upstream.
+
+This fixes missing freeing meta pages in the error case.
+
+Tested-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -708,7 +708,7 @@ int get_valid_checkpoint(struct f2fs_sb_
+       /* Sanity checking of checkpoint */
+       if (sanity_check_ckpt(sbi))
+-              goto fail_no_cp;
++              goto free_fail_no_cp;
+       if (cur_page == cp1)
+               sbi->cur_cp_pack = 1;
+@@ -736,6 +736,9 @@ done:
+       f2fs_put_page(cp2, 1);
+       return 0;
++free_fail_no_cp:
++      f2fs_put_page(cp1, 1);
++      f2fs_put_page(cp2, 1);
+ fail_no_cp:
+       kfree(sbi->ckpt);
+       return -EINVAL;
diff --git a/queue-4.4/f2fs-give-einval-for-norecovery-and-rw-mount.patch b/queue-4.4/f2fs-give-einval-for-norecovery-and-rw-mount.patch
new file mode 100644 (file)
index 0000000..5e0c9d1
--- /dev/null
@@ -0,0 +1,101 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Wed, 23 Mar 2016 16:12:58 -0700
+Subject: f2fs: give -EINVAL for norecovery and rw mount
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit 6781eabba1bdb133eb9125c4acf6704ccbe4df02 upstream.
+
+Once detecting something to recover, f2fs should stop mounting, given norecovery
+and rw mount options.
+
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/f2fs.h     |    2 +-
+ fs/f2fs/recovery.c |   11 +++++++----
+ fs/f2fs/super.c    |   14 ++++++++++++--
+ 3 files changed, 20 insertions(+), 7 deletions(-)
+
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -1867,7 +1867,7 @@ void build_gc_manager(struct f2fs_sb_inf
+ /*
+  * recovery.c
+  */
+-int recover_fsync_data(struct f2fs_sb_info *);
++int recover_fsync_data(struct f2fs_sb_info *, bool);
+ bool space_for_roll_forward(struct f2fs_sb_info *);
+ /*
+--- a/fs/f2fs/recovery.c
++++ b/fs/f2fs/recovery.c
+@@ -524,12 +524,13 @@ next:
+       return err;
+ }
+-int recover_fsync_data(struct f2fs_sb_info *sbi)
++int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
+ {
+       struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
+       struct list_head inode_list;
+       block_t blkaddr;
+       int err;
++      int ret = 0;
+       bool need_writecp = false;
+       fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
+@@ -546,11 +547,13 @@ int recover_fsync_data(struct f2fs_sb_in
+       /* step #1: find fsynced inode numbers */
+       err = find_fsync_dnodes(sbi, &inode_list);
+-      if (err)
++      if (err || list_empty(&inode_list))
+               goto out;
+-      if (list_empty(&inode_list))
++      if (check_only) {
++              ret = 1;
+               goto out;
++      }
+       need_writecp = true;
+@@ -598,5 +601,5 @@ out:
+       } else {
+               mutex_unlock(&sbi->cp_mutex);
+       }
+-      return err;
++      return ret ? ret: err;
+ }
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1457,14 +1457,24 @@ try_onemore:
+               if (need_fsck)
+                       set_sbi_flag(sbi, SBI_NEED_FSCK);
+-              err = recover_fsync_data(sbi);
+-              if (err) {
++              err = recover_fsync_data(sbi, false);
++              if (err < 0) {
+                       need_fsck = true;
+                       f2fs_msg(sb, KERN_ERR,
+                               "Cannot recover all fsync data errno=%ld", err);
+                       goto free_kobj;
+               }
++      } else {
++              err = recover_fsync_data(sbi, true);
++
++              if (!f2fs_readonly(sb) && err > 0) {
++                      err = -EINVAL;
++                      f2fs_msg(sb, KERN_ERR,
++                              "Need to recover fsync data");
++                      goto free_kobj;
++              }
+       }
++
+       /* recover_fsync_data() cleared this already */
+       clear_sbi_flag(sbi, SBI_POR_DOING);
diff --git a/queue-4.4/f2fs-introduce-and-spread-verify_blkaddr.patch b/queue-4.4/f2fs-introduce-and-spread-verify_blkaddr.patch
new file mode 100644 (file)
index 0000000..b6a23b4
--- /dev/null
@@ -0,0 +1,311 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Chao Yu <yuchao0@huawei.com>
+Date: Tue, 5 Jun 2018 17:44:11 +0800
+Subject: f2fs: introduce and spread verify_blkaddr
+
+From: Chao Yu <yuchao0@huawei.com>
+
+commit e1da7872f6eda977bd812346bf588c35e4495a1e upstream.
+
+This patch introduces verify_blkaddr to check meta/data block address
+with valid range to detect bug earlier.
+
+In addition, once we encounter an invalid blkaddr, notice user to run
+fsck to fix, and let the kernel panic.
+
+Signed-off-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4:
+ - I skipped an earlier renaming of is_valid_meta_blkaddr() to
+   f2fs_is_valid_meta_blkaddr()
+ - Drop inapplicable change to check on f2fs_fio_info::old_blkaddr
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c |   11 +++++++++--
+ fs/f2fs/data.c       |    4 ++--
+ fs/f2fs/f2fs.h       |   32 +++++++++++++++++++++++++++++---
+ fs/f2fs/file.c       |    9 +++++----
+ fs/f2fs/inode.c      |    7 ++++---
+ fs/f2fs/node.c       |    4 ++--
+ fs/f2fs/recovery.c   |    6 +++---
+ fs/f2fs/segment.c    |    4 ++--
+ fs/f2fs/segment.h    |    8 +++-----
+ 9 files changed, 59 insertions(+), 26 deletions(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -107,7 +107,8 @@ struct page *get_tmp_page(struct f2fs_sb
+       return __get_meta_page(sbi, index, false);
+ }
+-bool is_valid_meta_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
++bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
++                                      block_t blkaddr, int type)
+ {
+       switch (type) {
+       case META_NAT:
+@@ -127,10 +128,16 @@ bool is_valid_meta_blkaddr(struct f2fs_s
+                       return false;
+               break;
+       case META_POR:
++      case DATA_GENERIC:
+               if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
+                       blkaddr < MAIN_BLKADDR(sbi)))
+                       return false;
+               break;
++      case META_GENERIC:
++              if (unlikely(blkaddr < SEG0_BLKADDR(sbi) ||
++                      blkaddr >= MAIN_BLKADDR(sbi)))
++                      return false;
++              break;
+       default:
+               BUG();
+       }
+@@ -160,7 +167,7 @@ int ra_meta_pages(struct f2fs_sb_info *s
+       for (; nrpages-- > 0; blkno++) {
+-              if (!is_valid_meta_blkaddr(sbi, blkno, type))
++              if (!f2fs_is_valid_blkaddr(sbi, blkno, type))
+                       goto out;
+               switch (type) {
+--- a/fs/f2fs/data.c
++++ b/fs/f2fs/data.c
+@@ -604,7 +604,7 @@ static int f2fs_map_blocks(struct inode
+               goto unlock_out;
+       }
+-      if (!is_valid_blkaddr(dn.data_blkaddr)) {
++      if (!is_valid_data_blkaddr(sbi, dn.data_blkaddr)) {
+               if (create) {
+                       if (unlikely(f2fs_cp_error(sbi))) {
+                               err = -EIO;
+@@ -1090,7 +1090,7 @@ int do_write_data_page(struct f2fs_io_in
+        * If current allocation needs SSR,
+        * it had better in-place writes for updated data.
+        */
+-      if (unlikely(is_valid_blkaddr(fio->blk_addr) &&
++      if (unlikely(is_valid_data_blkaddr(fio->sbi, fio->blk_addr) &&
+                       !is_cold_data(page) &&
+                       need_inplace_update(inode))) {
+               rewrite_data_page(fio);
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -135,7 +135,7 @@ struct cp_control {
+ };
+ /*
+- * For CP/NAT/SIT/SSA readahead
++ * indicate meta/data type
+  */
+ enum {
+       META_CP,
+@@ -143,6 +143,8 @@ enum {
+       META_SIT,
+       META_SSA,
+       META_POR,
++      DATA_GENERIC,
++      META_GENERIC,
+ };
+ /* for the list of ino */
+@@ -1647,13 +1649,36 @@ static inline void *f2fs_kvzalloc(size_t
+       (pgofs - ADDRS_PER_INODE(fi) + ADDRS_PER_BLOCK) /       \
+       ADDRS_PER_BLOCK * ADDRS_PER_BLOCK + ADDRS_PER_INODE(fi))
+-static inline bool is_valid_blkaddr(block_t blkaddr)
++bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
++                                      block_t blkaddr, int type);
++void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
++static inline void verify_blkaddr(struct f2fs_sb_info *sbi,
++                                      block_t blkaddr, int type)
++{
++      if (!f2fs_is_valid_blkaddr(sbi, blkaddr, type)) {
++              f2fs_msg(sbi->sb, KERN_ERR,
++                      "invalid blkaddr: %u, type: %d, run fsck to fix.",
++                      blkaddr, type);
++              f2fs_bug_on(sbi, 1);
++      }
++}
++
++static inline bool __is_valid_data_blkaddr(block_t blkaddr)
+ {
+       if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
+               return false;
+       return true;
+ }
++static inline bool is_valid_data_blkaddr(struct f2fs_sb_info *sbi,
++                                              block_t blkaddr)
++{
++      if (!__is_valid_data_blkaddr(blkaddr))
++              return false;
++      verify_blkaddr(sbi, blkaddr, DATA_GENERIC);
++      return true;
++}
++
+ /*
+  * file.c
+  */
+@@ -1825,7 +1850,8 @@ void destroy_segment_manager_caches(void
+ struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
+ struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
+ struct page *get_tmp_page(struct f2fs_sb_info *, pgoff_t);
+-bool is_valid_meta_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type);
++bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
++                                      block_t blkaddr, int type);
+ int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int, bool);
+ void ra_meta_pages_cond(struct f2fs_sb_info *, pgoff_t);
+ long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
+--- a/fs/f2fs/file.c
++++ b/fs/f2fs/file.c
+@@ -305,13 +305,13 @@ static pgoff_t __get_first_dirty_index(s
+       return pgofs;
+ }
+-static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs,
+-                                                      int whence)
++static bool __found_offset(struct f2fs_sb_info *sbi, block_t blkaddr,
++                              pgoff_t dirty, pgoff_t pgofs, int whence)
+ {
+       switch (whence) {
+       case SEEK_DATA:
+               if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
+-                      is_valid_blkaddr(blkaddr))
++                      is_valid_data_blkaddr(sbi, blkaddr))
+                       return true;
+               break;
+       case SEEK_HOLE:
+@@ -374,7 +374,8 @@ static loff_t f2fs_seek_block(struct fil
+                       block_t blkaddr;
+                       blkaddr = datablock_addr(dn.node_page, dn.ofs_in_node);
+-                      if (__found_offset(blkaddr, dirty, pgofs, whence)) {
++                      if (__found_offset(F2FS_I_SB(inode), blkaddr, dirty,
++                                                      pgofs, whence)) {
+                               f2fs_put_dnode(&dn);
+                               goto found;
+                       }
+--- a/fs/f2fs/inode.c
++++ b/fs/f2fs/inode.c
+@@ -50,11 +50,12 @@ static void __get_inode_rdev(struct inod
+       }
+ }
+-static bool __written_first_block(struct f2fs_inode *ri)
++static bool __written_first_block(struct f2fs_sb_info *sbi,
++                                      struct f2fs_inode *ri)
+ {
+       block_t addr = le32_to_cpu(ri->i_addr[0]);
+-      if (is_valid_blkaddr(addr))
++      if (is_valid_data_blkaddr(sbi, addr))
+               return true;
+       return false;
+ }
+@@ -149,7 +150,7 @@ static int do_read_inode(struct inode *i
+       /* get rdev by using inline_info */
+       __get_inode_rdev(inode, ri);
+-      if (__written_first_block(ri))
++      if (__written_first_block(sbi, ri))
+               set_inode_flag(F2FS_I(inode), FI_FIRST_BLOCK_WRITTEN);
+       f2fs_put_page(node_page, 1);
+--- a/fs/f2fs/node.c
++++ b/fs/f2fs/node.c
+@@ -296,7 +296,7 @@ static void set_node_addr(struct f2fs_sb
+                       new_blkaddr == NULL_ADDR);
+       f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR &&
+                       new_blkaddr == NEW_ADDR);
+-      f2fs_bug_on(sbi, is_valid_blkaddr(nat_get_blkaddr(e)) &&
++      f2fs_bug_on(sbi, is_valid_data_blkaddr(sbi, nat_get_blkaddr(e)) &&
+                       new_blkaddr == NEW_ADDR);
+       /* increment version no as node is removed */
+@@ -311,7 +311,7 @@ static void set_node_addr(struct f2fs_sb
+       /* change address */
+       nat_set_blkaddr(e, new_blkaddr);
+-      if (!is_valid_blkaddr(new_blkaddr))
++      if (!is_valid_data_blkaddr(sbi, new_blkaddr))
+               set_nat_flag(e, IS_CHECKPOINTED, false);
+       __set_nat_cache_dirty(nm_i, e);
+--- a/fs/f2fs/recovery.c
++++ b/fs/f2fs/recovery.c
+@@ -208,7 +208,7 @@ static int find_fsync_dnodes(struct f2fs
+       while (1) {
+               struct fsync_inode_entry *entry;
+-              if (!is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
++              if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
+                       return 0;
+               page = get_tmp_page(sbi, blkaddr);
+@@ -443,7 +443,7 @@ static int do_recover_data(struct f2fs_s
+               }
+               /* dest is valid block, try to recover from src to dest */
+-              if (is_valid_meta_blkaddr(sbi, dest, META_POR)) {
++              if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
+                       if (src == NULL_ADDR) {
+                               err = reserve_new_block(&dn);
+@@ -494,7 +494,7 @@ static int recover_data(struct f2fs_sb_i
+       while (1) {
+               struct fsync_inode_entry *entry;
+-              if (!is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
++              if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
+                       break;
+               ra_meta_pages_cond(sbi, blkaddr);
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -752,7 +752,7 @@ bool is_checkpointed_data(struct f2fs_sb
+       struct seg_entry *se;
+       bool is_cp = false;
+-      if (!is_valid_blkaddr(blkaddr))
++      if (!is_valid_data_blkaddr(sbi, blkaddr))
+               return true;
+       mutex_lock(&sit_i->sentry_lock);
+@@ -1466,7 +1466,7 @@ void f2fs_wait_on_encrypted_page_writeba
+ {
+       struct page *cpage;
+-      if (!is_valid_blkaddr(blkaddr))
++      if (!is_valid_data_blkaddr(sbi, blkaddr))
+               return;
+       f2fs_bug_on(sbi, blkaddr == NULL_ADDR);
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -80,7 +80,7 @@
+       (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (sbi->blocks_per_seg - 1))
+ #define GET_SEGNO(sbi, blk_addr)                                      \
+-      ((!is_valid_blkaddr(blk_addr)) ?                        \
++      ((!is_valid_data_blkaddr(sbi, blk_addr)) ?                      \
+       NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi),                 \
+               GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
+ #define GET_SECNO(sbi, segno)                                 \
+@@ -588,11 +588,9 @@ static inline void verify_block_addr(str
+       if (PAGE_TYPE_OF_BIO(fio->type) == META &&
+                               (!is_read_io(fio->rw) || fio->is_meta))
+-              BUG_ON(blk_addr < SEG0_BLKADDR(sbi) ||
+-                              blk_addr >= MAIN_BLKADDR(sbi));
++              verify_blkaddr(sbi, blk_addr, META_GENERIC);
+       else
+-              BUG_ON(blk_addr < MAIN_BLKADDR(sbi) ||
+-                              blk_addr >= MAX_BLKADDR(sbi));
++              verify_blkaddr(sbi, blk_addr, DATA_GENERIC);
+ }
+ /*
diff --git a/queue-4.4/f2fs-introduce-get_checkpoint_version-for-cleanup.patch b/queue-4.4/f2fs-introduce-get_checkpoint_version-for-cleanup.patch
new file mode 100644 (file)
index 0000000..40eb3b5
--- /dev/null
@@ -0,0 +1,109 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Tiezhu Yang <kernelpatch@126.com>
+Date: Fri, 30 Sep 2016 08:24:53 +0800
+Subject: f2fs: introduce get_checkpoint_version for cleanup
+
+From: Tiezhu Yang <kernelpatch@126.com>
+
+commit fc0065adb202518e25fb929cda7d5887a456f774 upstream.
+
+There exists almost same codes when get the value of pre_version
+and cur_version in function validate_checkpoint, this patch adds
+get_checkpoint_version to clean up redundant codes.
+
+Signed-off-by: Tiezhu Yang <kernelpatch@126.com>
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4: f2fs_crc_valid() doesn't take an f2fs_sb_info pointer]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c |   66 +++++++++++++++++++++++++++++----------------------
+ 1 file changed, 38 insertions(+), 28 deletions(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -601,45 +601,55 @@ static void write_orphan_inodes(struct f
+       }
+ }
+-static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
+-                              block_t cp_addr, unsigned long long *version)
++static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
++              struct f2fs_checkpoint **cp_block, struct page **cp_page,
++              unsigned long long *version)
+ {
+-      struct page *cp_page_1, *cp_page_2 = NULL;
+       unsigned long blk_size = sbi->blocksize;
+-      struct f2fs_checkpoint *cp_block;
+-      unsigned long long cur_version = 0, pre_version = 0;
+-      size_t crc_offset;
++      size_t crc_offset = 0;
+       __u32 crc = 0;
+-      /* Read the 1st cp block in this CP pack */
+-      cp_page_1 = get_meta_page(sbi, cp_addr);
++      *cp_page = get_meta_page(sbi, cp_addr);
++      *cp_block = (struct f2fs_checkpoint *)page_address(*cp_page);
+-      /* get the version number */
+-      cp_block = (struct f2fs_checkpoint *)page_address(cp_page_1);
+-      crc_offset = le32_to_cpu(cp_block->checksum_offset);
+-      if (crc_offset >= blk_size)
+-              goto invalid_cp1;
++      crc_offset = le32_to_cpu((*cp_block)->checksum_offset);
++      if (crc_offset >= blk_size) {
++              f2fs_msg(sbi->sb, KERN_WARNING,
++                      "invalid crc_offset: %zu", crc_offset);
++              return -EINVAL;
++      }
+-      crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset)));
+-      if (!f2fs_crc_valid(crc, cp_block, crc_offset))
+-              goto invalid_cp1;
++      crc = le32_to_cpu(*((__le32 *)((unsigned char *)*cp_block
++                                                      + crc_offset)));
++      if (!f2fs_crc_valid(crc, *cp_block, crc_offset)) {
++              f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
++              return -EINVAL;
++      }
+-      pre_version = cur_cp_version(cp_block);
++      *version = cur_cp_version(*cp_block);
++      return 0;
++}
+-      /* Read the 2nd cp block in this CP pack */
+-      cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
+-      cp_page_2 = get_meta_page(sbi, cp_addr);
++static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
++                              block_t cp_addr, unsigned long long *version)
++{
++      struct page *cp_page_1 = NULL, *cp_page_2 = NULL;
++      struct f2fs_checkpoint *cp_block = NULL;
++      unsigned long long cur_version = 0, pre_version = 0;
++      int err;
+-      cp_block = (struct f2fs_checkpoint *)page_address(cp_page_2);
+-      crc_offset = le32_to_cpu(cp_block->checksum_offset);
+-      if (crc_offset >= blk_size)
+-              goto invalid_cp2;
++      err = get_checkpoint_version(sbi, cp_addr, &cp_block,
++                                      &cp_page_1, version);
++      if (err)
++              goto invalid_cp1;
++      pre_version = *version;
+-      crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset)));
+-      if (!f2fs_crc_valid(crc, cp_block, crc_offset))
++      cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
++      err = get_checkpoint_version(sbi, cp_addr, &cp_block,
++                                      &cp_page_2, version);
++      if (err)
+               goto invalid_cp2;
+-
+-      cur_version = cur_cp_version(cp_block);
++      cur_version = *version;
+       if (cur_version == pre_version) {
+               *version = cur_version;
diff --git a/queue-4.4/f2fs-move-sanity-checking-of-cp-into-get_valid_checkpoint.patch b/queue-4.4/f2fs-move-sanity-checking-of-cp-into-get_valid_checkpoint.patch
new file mode 100644 (file)
index 0000000..72b9f6c
--- /dev/null
@@ -0,0 +1,85 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Shawn Lin <shawn.lin@rock-chips.com>
+Date: Wed, 17 Feb 2016 11:26:32 +0800
+Subject: f2fs: move sanity checking of cp into get_valid_checkpoint
+
+From: Shawn Lin <shawn.lin@rock-chips.com>
+
+commit 984ec63c5a82a07ad4490ecc69bebacd23f6fa64 upstream.
+
+>From the function name of get_valid_checkpoint, it seems to return
+the valid cp or NULL for caller to check. If no valid one is found,
+f2fs_fill_super will print the err log. But if get_valid_checkpoint
+get one valid(the return value indicate that it's valid, however actually
+it is invalid after sanity checking), then print another similar err
+log. That seems strange. Let's keep sanity checking inside the procedure
+of geting valid cp. Another improvement we gained from this move is
+that even the large volume is supported, we check the cp in advanced
+to skip the following procedure if failing the sanity checking.
+
+Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c |    4 ++++
+ fs/f2fs/f2fs.h       |    1 +
+ fs/f2fs/super.c      |   10 +---------
+ 3 files changed, 6 insertions(+), 9 deletions(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -696,6 +696,10 @@ int get_valid_checkpoint(struct f2fs_sb_
+       cp_block = (struct f2fs_checkpoint *)page_address(cur_page);
+       memcpy(sbi->ckpt, cp_block, blk_size);
++      /* Sanity checking of checkpoint */
++      if (sanity_check_ckpt(sbi))
++              goto fail_no_cp;
++
+       if (cp_blks <= 1)
+               goto done;
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -1718,6 +1718,7 @@ int f2fs_commit_super(struct f2fs_sb_inf
+ int f2fs_sync_fs(struct super_block *, int);
+ extern __printf(3, 4)
+ void f2fs_msg(struct super_block *, const char *, const char *, ...);
++int sanity_check_ckpt(struct f2fs_sb_info *sbi);
+ /*
+  * hash.c
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1073,7 +1073,7 @@ static int sanity_check_raw_super(struct
+       return 0;
+ }
+-static int sanity_check_ckpt(struct f2fs_sb_info *sbi)
++int sanity_check_ckpt(struct f2fs_sb_info *sbi)
+ {
+       unsigned int total, fsmeta;
+       struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
+@@ -1358,13 +1358,6 @@ try_onemore:
+               goto free_meta_inode;
+       }
+-      /* sanity checking of checkpoint */
+-      err = -EINVAL;
+-      if (sanity_check_ckpt(sbi)) {
+-              f2fs_msg(sb, KERN_ERR, "Invalid F2FS checkpoint");
+-              goto free_cp;
+-      }
+-
+       sbi->total_valid_node_count =
+                               le32_to_cpu(sbi->ckpt->valid_node_count);
+       sbi->total_valid_inode_count =
+@@ -1517,7 +1510,6 @@ free_nm:
+       destroy_node_manager(sbi);
+ free_sm:
+       destroy_segment_manager(sbi);
+-free_cp:
+       kfree(sbi->ckpt);
+ free_meta_inode:
+       make_bad_inode(sbi->meta_inode);
diff --git a/queue-4.4/f2fs-not-allow-to-write-illegal-blkaddr.patch b/queue-4.4/f2fs-not-allow-to-write-illegal-blkaddr.patch
new file mode 100644 (file)
index 0000000..1e38020
--- /dev/null
@@ -0,0 +1,53 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Yunlei He <heyunlei@huawei.com>
+Date: Thu, 28 Jul 2016 12:12:38 +0800
+Subject: f2fs: not allow to write illegal blkaddr
+
+From: Yunlei He <heyunlei@huawei.com>
+
+commit bb413d6acd4e1c361daebf8486efc3923f429792 upstream.
+
+we came across an error as below:
+
+[build_nat_area_bitmap:1710] nid[0x    1718] addr[0x         1c18ddc] ino[0x    1718]
+[build_nat_area_bitmap:1710] nid[0x    1719] addr[0x         1c193d5] ino[0x    1719]
+[build_nat_area_bitmap:1710] nid[0x    171a] addr[0x         1c1736e] ino[0x    171a]
+[build_nat_area_bitmap:1710] nid[0x    171b] addr[0x        58b3ee8f] ino[0x815f92ed]
+[build_nat_area_bitmap:1710] nid[0x    171c] addr[0x         fcdc94b] ino[0x49366377]
+[build_nat_area_bitmap:1710] nid[0x    171d] addr[0x        7cd2facf] ino[0xb3c55300]
+[build_nat_area_bitmap:1710] nid[0x    171e] addr[0x        bd4e25d0] ino[0x77c34c09]
+
+... ...
+
+[build_nat_area_bitmap:1710] nid[0x    1718] addr[0x         1c18ddc] ino[0x    1718]
+[build_nat_area_bitmap:1710] nid[0x    1719] addr[0x         1c193d5] ino[0x    1719]
+[build_nat_area_bitmap:1710] nid[0x    171a] addr[0x         1c1736e] ino[0x    171a]
+[build_nat_area_bitmap:1710] nid[0x    171b] addr[0x        58b3ee8f] ino[0x815f92ed]
+[build_nat_area_bitmap:1710] nid[0x    171c] addr[0x         fcdc94b] ino[0x49366377]
+[build_nat_area_bitmap:1710] nid[0x    171d] addr[0x        7cd2facf] ino[0xb3c55300]
+[build_nat_area_bitmap:1710] nid[0x    171e] addr[0x        bd4e25d0] ino[0x77c34c09]
+
+One nat block may be stepped by a data block, so this patch forbid to
+write if the blkaddr is illegal
+
+Signed-off-by: Yunlei He <heyunlei@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/segment.h |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -576,8 +576,8 @@ static inline void check_seg_range(struc
+ static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
+ {
+-      f2fs_bug_on(sbi, blk_addr < SEG0_BLKADDR(sbi)
+-                                      || blk_addr >= MAX_BLKADDR(sbi));
++      BUG_ON(blk_addr < SEG0_BLKADDR(sbi)
++                      || blk_addr >= MAX_BLKADDR(sbi));
+ }
+ /*
diff --git a/queue-4.4/f2fs-put-directory-inodes-before-checkpoint-in-roll-forward-recovery.patch b/queue-4.4/f2fs-put-directory-inodes-before-checkpoint-in-roll-forward-recovery.patch
new file mode 100644 (file)
index 0000000..791cb38
--- /dev/null
@@ -0,0 +1,38 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Mon, 19 Sep 2016 18:13:54 -0700
+Subject: f2fs: put directory inodes before checkpoint in roll-forward recovery
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit 9e1e6df412a28cdbbd2909de5c6189eda4a3383d upstream.
+
+Before checkpoint, we'd be better drop any inodes.
+
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/recovery.c |    4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/fs/f2fs/recovery.c
++++ b/fs/f2fs/recovery.c
+@@ -597,6 +597,9 @@ out:
+               set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
+       mutex_unlock(&sbi->cp_mutex);
++      /* let's drop all the directory inodes for clean checkpoint */
++      destroy_fsync_dnodes(&dir_list);
++
+       if (!err && need_writecp) {
+               struct cp_control cpc = {
+                       .reason = CP_RECOVERY,
+@@ -604,7 +607,6 @@ out:
+               write_checkpoint(sbi, &cpc);
+       }
+-      destroy_fsync_dnodes(&dir_list);
+       kmem_cache_destroy(fsync_entry_slab);
+       return ret ? ret: err;
+ }
diff --git a/queue-4.4/f2fs-remove-an-obsolete-variable.patch b/queue-4.4/f2fs-remove-an-obsolete-variable.patch
new file mode 100644 (file)
index 0000000..88abc2b
--- /dev/null
@@ -0,0 +1,39 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Wed, 4 May 2016 09:58:10 -0700
+Subject: f2fs: remove an obsolete variable
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit fb58ae22067e0595d974e3d856522c1ed6d2d7bf upstream.
+
+This patch removes an obsolete variable used in add_free_nid.
+
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Picked as dependency of commit 30a61ddf8117 "f2fs: fix race condition
+ in between free nid allocator/initializer"]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/node.c |    3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/fs/f2fs/node.c
++++ b/fs/f2fs/node.c
+@@ -1430,7 +1430,6 @@ static int add_free_nid(struct f2fs_sb_i
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct free_nid *i;
+       struct nat_entry *ne;
+-      bool allocated = false;
+       if (!available_free_memory(sbi, FREE_NIDS))
+               return -1;
+@@ -1444,8 +1443,6 @@ static int add_free_nid(struct f2fs_sb_i
+               ne = __lookup_nat_cache(nm_i, nid);
+               if (ne && (!get_nat_flag(ne, IS_CHECKPOINTED) ||
+                               nat_get_blkaddr(ne) != NULL_ADDR))
+-                      allocated = true;
+-              if (allocated)
+                       return 0;
+       }
diff --git a/queue-4.4/f2fs-return-error-during-fill_super.patch b/queue-4.4/f2fs-return-error-during-fill_super.patch
new file mode 100644 (file)
index 0000000..f4d1d6f
--- /dev/null
@@ -0,0 +1,123 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Tue, 19 Dec 2017 19:16:34 -0800
+Subject: f2fs: return error during fill_super
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit c39a1b348c4fe172729eff77c533dabc3c7cdaa7 upstream.
+
+Let's avoid BUG_ON during fill_super, when on-disk was totall corrupted.
+
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Signed-off-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[bwh: Backported to 4.4: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/segment.c |   16 ++++++++++++----
+ fs/f2fs/segment.h |   22 ++++++++++++++++++----
+ 2 files changed, 30 insertions(+), 8 deletions(-)
+
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -2101,7 +2101,7 @@ static int build_curseg(struct f2fs_sb_i
+       return restore_curseg_summaries(sbi);
+ }
+-static void build_sit_entries(struct f2fs_sb_info *sbi)
++static int build_sit_entries(struct f2fs_sb_info *sbi)
+ {
+       struct sit_info *sit_i = SIT_I(sbi);
+       struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
+@@ -2110,6 +2110,7 @@ static void build_sit_entries(struct f2f
+       unsigned int i, start, end;
+       unsigned int readed, start_blk = 0;
+       int nrpages = MAX_BIO_BLOCKS(sbi);
++      int err = 0;
+       do {
+               readed = ra_meta_pages(sbi, start_blk, nrpages, META_SIT, true);
+@@ -2128,7 +2129,9 @@ static void build_sit_entries(struct f2f
+                       sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)];
+                       f2fs_put_page(page, 1);
+-                      check_block_count(sbi, start, &sit);
++                      err = check_block_count(sbi, start, &sit);
++                      if (err)
++                              return err;
+                       seg_info_from_raw_sit(se, &sit);
+                       /* build discard map only one time */
+@@ -2154,7 +2157,9 @@ static void build_sit_entries(struct f2f
+               old_valid_blocks = se->valid_blocks;
+-              check_block_count(sbi, start, &sit);
++              err = check_block_count(sbi, start, &sit);
++              if (err)
++                      break;
+               seg_info_from_raw_sit(se, &sit);
+               memcpy(se->discard_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
+@@ -2165,6 +2170,7 @@ static void build_sit_entries(struct f2f
+                               se->valid_blocks - old_valid_blocks;
+       }
+       mutex_unlock(&curseg->curseg_mutex);
++      return err;
+ }
+ static void init_free_segmap(struct f2fs_sb_info *sbi)
+@@ -2326,7 +2332,9 @@ int build_segment_manager(struct f2fs_sb
+               return err;
+       /* reinit free segmap based on SIT */
+-      build_sit_entries(sbi);
++      err = build_sit_entries(sbi);
++      if (err)
++              return err;
+       init_free_segmap(sbi);
+       err = build_dirty_segmap(sbi);
+--- a/fs/f2fs/segment.h
++++ b/fs/f2fs/segment.h
+@@ -585,7 +585,7 @@ static inline void verify_block_addr(str
+ /*
+  * Summary block is always treated as an invalid block
+  */
+-static inline void check_block_count(struct f2fs_sb_info *sbi,
++static inline int check_block_count(struct f2fs_sb_info *sbi,
+               int segno, struct f2fs_sit_entry *raw_sit)
+ {
+ #ifdef CONFIG_F2FS_CHECK_FS
+@@ -607,11 +607,25 @@ static inline void check_block_count(str
+               cur_pos = next_pos;
+               is_valid = !is_valid;
+       } while (cur_pos < sbi->blocks_per_seg);
+-      BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks);
++
++      if (unlikely(GET_SIT_VBLOCKS(raw_sit) != valid_blocks)) {
++              f2fs_msg(sbi->sb, KERN_ERR,
++                              "Mismatch valid blocks %d vs. %d",
++                                      GET_SIT_VBLOCKS(raw_sit), valid_blocks);
++              set_sbi_flag(sbi, SBI_NEED_FSCK);
++              return -EINVAL;
++      }
+ #endif
+       /* check segment usage, and check boundary of a given segment number */
+-      f2fs_bug_on(sbi, GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
+-                                      || segno > TOTAL_SEGS(sbi) - 1);
++      if (unlikely(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
++                                      || segno > TOTAL_SEGS(sbi) - 1)) {
++              f2fs_msg(sbi->sb, KERN_ERR,
++                              "Wrong valid blocks %d or segno %u",
++                                      GET_SIT_VBLOCKS(raw_sit), segno);
++              set_sbi_flag(sbi, SBI_NEED_FSCK);
++              return -EINVAL;
++      }
++      return 0;
+ }
+ static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi,
diff --git a/queue-4.4/f2fs-sanity-check-on-sit-entry.patch b/queue-4.4/f2fs-sanity-check-on-sit-entry.patch
new file mode 100644 (file)
index 0000000..b285776
--- /dev/null
@@ -0,0 +1,104 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Tue, 24 Apr 2018 15:44:16 -0600
+Subject: f2fs: sanity check on sit entry
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit b2ca374f33bd33fd822eb871876e4888cf79dc97 upstream.
+
+syzbot hit the following crash on upstream commit
+87ef12027b9b1dd0e0b12cf311fbcb19f9d92539 (Wed Apr 18 19:48:17 2018 +0000)
+Merge tag 'ceph-for-4.17-rc2' of git://github.com/ceph/ceph-client
+syzbot dashboard link: https://syzkaller.appspot.com/bug?extid=83699adeb2d13579c31e
+
+C reproducer: https://syzkaller.appspot.com/x/repro.c?id=5805208181407744
+syzkaller reproducer: https://syzkaller.appspot.com/x/repro.syz?id=6005073343676416
+Raw console output: https://syzkaller.appspot.com/x/log.txt?id=6555047731134464
+Kernel config: https://syzkaller.appspot.com/x/.config?id=1808800213120130118
+compiler: gcc (GCC) 8.0.1 20180413 (experimental)
+
+IMPORTANT: if you fix the bug, please add the following tag to the commit:
+Reported-by: syzbot+83699adeb2d13579c31e@syzkaller.appspotmail.com
+It will help syzbot understand when the bug is fixed. See footer for details.
+If you forward the report, please keep this part and the footer.
+
+F2FS-fs (loop0): Magic Mismatch, valid(0xf2f52010) - read(0x0)
+F2FS-fs (loop0): Can't find valid F2FS filesystem in 1th superblock
+F2FS-fs (loop0): invalid crc value
+BUG: unable to handle kernel paging request at ffffed006b2a50c0
+PGD 21ffee067 P4D 21ffee067 PUD 21fbeb067 PMD 0
+Oops: 0000 [#1] SMP KASAN
+Dumping ftrace buffer:
+   (ftrace buffer empty)
+Modules linked in:
+CPU: 0 PID: 4514 Comm: syzkaller989480 Not tainted 4.17.0-rc1+ #8
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
+RIP: 0010:build_sit_entries fs/f2fs/segment.c:3653 [inline]
+RIP: 0010:build_segment_manager+0x7ef7/0xbf70 fs/f2fs/segment.c:3852
+RSP: 0018:ffff8801b102e5b0 EFLAGS: 00010a06
+RAX: 1ffff1006b2a50c0 RBX: 0000000000000004 RCX: 0000000000000001
+RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8801ac74243e
+RBP: ffff8801b102f410 R08: ffff8801acbd46c0 R09: fffffbfff14d9af8
+R10: fffffbfff14d9af8 R11: ffff8801acbd46c0 R12: ffff8801ac742a80
+R13: ffff8801d9519100 R14: dffffc0000000000 R15: ffff880359528600
+FS:  0000000001e04880(0000) GS:ffff8801dae00000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: ffffed006b2a50c0 CR3: 00000001ac6ac000 CR4: 00000000001406f0
+DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+Call Trace:
+ f2fs_fill_super+0x4095/0x7bf0 fs/f2fs/super.c:2803
+ mount_bdev+0x30c/0x3e0 fs/super.c:1165
+ f2fs_mount+0x34/0x40 fs/f2fs/super.c:3020
+ mount_fs+0xae/0x328 fs/super.c:1268
+ vfs_kern_mount.part.34+0xd4/0x4d0 fs/namespace.c:1037
+ vfs_kern_mount fs/namespace.c:1027 [inline]
+ do_new_mount fs/namespace.c:2517 [inline]
+ do_mount+0x564/0x3070 fs/namespace.c:2847
+ ksys_mount+0x12d/0x140 fs/namespace.c:3063
+ __do_sys_mount fs/namespace.c:3077 [inline]
+ __se_sys_mount fs/namespace.c:3074 [inline]
+ __x64_sys_mount+0xbe/0x150 fs/namespace.c:3074
+ do_syscall_64+0x1b1/0x800 arch/x86/entry/common.c:287
+ entry_SYSCALL_64_after_hwframe+0x49/0xbe
+RIP: 0033:0x443d6a
+RSP: 002b:00007ffd312813c8 EFLAGS: 00000297 ORIG_RAX: 00000000000000a5
+RAX: ffffffffffffffda RBX: 0000000020000c00 RCX: 0000000000443d6a
+RDX: 0000000020000000 RSI: 0000000020000100 RDI: 00007ffd312813d0
+RBP: 0000000000000003 R08: 0000000020016a00 R09: 000000000000000a
+R10: 0000000000000000 R11: 0000000000000297 R12: 0000000000000004
+R13: 0000000000402c60 R14: 0000000000000000 R15: 0000000000000000
+RIP: build_sit_entries fs/f2fs/segment.c:3653 [inline] RSP: ffff8801b102e5b0
+RIP: build_segment_manager+0x7ef7/0xbf70 fs/f2fs/segment.c:3852 RSP: ffff8801b102e5b0
+CR2: ffffed006b2a50c0
+---[ end trace a2034989e196ff17 ]---
+
+Reported-and-tested-by: syzbot+83699adeb2d13579c31e@syzkaller.appspotmail.com
+Reviewed-by: Chao Yu <yuchao0@huawei.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/segment.c |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -2152,6 +2152,15 @@ static int build_sit_entries(struct f2fs
+               unsigned int old_valid_blocks;
+               start = le32_to_cpu(segno_in_journal(sum, i));
++              if (start >= MAIN_SEGS(sbi)) {
++                      f2fs_msg(sbi->sb, KERN_ERR,
++                                      "Wrong journal entry on segno %u",
++                                      start);
++                      set_sbi_flag(sbi, SBI_NEED_FSCK);
++                      err = -EINVAL;
++                      break;
++              }
++
+               se = &sit_i->sentries[start];
+               sit = sit_in_journal(sum, i);
diff --git a/queue-4.4/f2fs-use-crc-and-cp-version-to-determine-roll-forward-recovery.patch b/queue-4.4/f2fs-use-crc-and-cp-version-to-determine-roll-forward-recovery.patch
new file mode 100644 (file)
index 0000000..4550d40
--- /dev/null
@@ -0,0 +1,329 @@
+From foo@baz Fri Jan 18 09:16:11 CET 2019
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Mon, 19 Sep 2016 17:55:10 -0700
+Subject: f2fs: use crc and cp version to determine roll-forward recovery
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit a468f0ef516fda9c7d91bb550d458e853d76955e upstream.
+
+Previously, we used cp_version only to detect recoverable dnodes.
+In order to avoid same garbage cp_version, we needed to truncate the next
+dnode during checkpoint, resulting in additional discard or data write.
+If we can distinguish this by using crc in addition to cp_version, we can
+remove this overhead.
+
+There is backward compatibility concern where it changes node_footer layout.
+So, this patch introduces a new checkpoint flag, CP_CRC_RECOVERY_FLAG, to
+detect new layout. New layout will be activated only when this flag is set.
+
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+[bwh: Backported to 4.4:
+ - Deleted code is slightly different
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/f2fs/checkpoint.c    |   21 +------------
+ fs/f2fs/f2fs.h          |    1 
+ fs/f2fs/node.h          |   77 ++++++++++++++++++++++++++++++------------------
+ fs/f2fs/recovery.c      |   30 +++---------------
+ fs/f2fs/segment.c       |   22 -------------
+ fs/f2fs/super.c         |    5 ++-
+ include/linux/f2fs_fs.h |    1 
+ 7 files changed, 63 insertions(+), 94 deletions(-)
+
+--- a/fs/f2fs/checkpoint.c
++++ b/fs/f2fs/checkpoint.c
+@@ -902,7 +902,6 @@ static void wait_on_all_pages_writeback(
+ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+ {
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+-      struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num;
+       nid_t last_nid = nm_i->next_scan_nid;
+@@ -911,15 +910,6 @@ static void do_checkpoint(struct f2fs_sb
+       __u32 crc32 = 0;
+       int i;
+       int cp_payload_blks = __cp_payload(sbi);
+-      block_t discard_blk = NEXT_FREE_BLKADDR(sbi, curseg);
+-      bool invalidate = false;
+-
+-      /*
+-       * This avoids to conduct wrong roll-forward operations and uses
+-       * metapages, so should be called prior to sync_meta_pages below.
+-       */
+-      if (discard_next_dnode(sbi, discard_blk))
+-              invalidate = true;
+       /* Flush all the NAT/SIT pages */
+       while (get_pages(sbi, F2FS_DIRTY_META)) {
+@@ -996,6 +986,9 @@ static void do_checkpoint(struct f2fs_sb
+       if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
+               set_ckpt_flags(ckpt, CP_FSCK_FLAG);
++      /* set this flag to activate crc|cp_ver for recovery */
++      set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG);
++
+       /* update SIT/NAT bitmap */
+       get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP));
+       get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP));
+@@ -1053,14 +1046,6 @@ static void do_checkpoint(struct f2fs_sb
+       /* wait for previous submitted meta pages writeback */
+       wait_on_all_pages_writeback(sbi);
+-      /*
+-       * invalidate meta page which is used temporarily for zeroing out
+-       * block at the end of warm node chain.
+-       */
+-      if (invalidate)
+-              invalidate_mapping_pages(META_MAPPING(sbi), discard_blk,
+-                                                              discard_blk);
+-
+       release_dirty_inode(sbi);
+       if (unlikely(f2fs_cp_error(sbi)))
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -1780,7 +1780,6 @@ bool is_checkpointed_data(struct f2fs_sb
+ void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t);
+ void clear_prefree_segments(struct f2fs_sb_info *, struct cp_control *);
+ void release_discard_addrs(struct f2fs_sb_info *);
+-bool discard_next_dnode(struct f2fs_sb_info *, block_t);
+ int npages_for_summary_flush(struct f2fs_sb_info *, bool);
+ void allocate_new_segments(struct f2fs_sb_info *);
+ int f2fs_trim_fs(struct f2fs_sb_info *, struct fstrim_range *);
+--- a/fs/f2fs/node.h
++++ b/fs/f2fs/node.h
+@@ -212,6 +212,37 @@ static inline void set_to_next_nat(struc
+       f2fs_change_bit(block_off, nm_i->nat_bitmap);
+ }
++static inline nid_t ino_of_node(struct page *node_page)
++{
++      struct f2fs_node *rn = F2FS_NODE(node_page);
++      return le32_to_cpu(rn->footer.ino);
++}
++
++static inline nid_t nid_of_node(struct page *node_page)
++{
++      struct f2fs_node *rn = F2FS_NODE(node_page);
++      return le32_to_cpu(rn->footer.nid);
++}
++
++static inline unsigned int ofs_of_node(struct page *node_page)
++{
++      struct f2fs_node *rn = F2FS_NODE(node_page);
++      unsigned flag = le32_to_cpu(rn->footer.flag);
++      return flag >> OFFSET_BIT_SHIFT;
++}
++
++static inline __u64 cpver_of_node(struct page *node_page)
++{
++      struct f2fs_node *rn = F2FS_NODE(node_page);
++      return le64_to_cpu(rn->footer.cp_ver);
++}
++
++static inline block_t next_blkaddr_of_node(struct page *node_page)
++{
++      struct f2fs_node *rn = F2FS_NODE(node_page);
++      return le32_to_cpu(rn->footer.next_blkaddr);
++}
++
+ static inline void fill_node_footer(struct page *page, nid_t nid,
+                               nid_t ino, unsigned int ofs, bool reset)
+ {
+@@ -242,40 +273,30 @@ static inline void fill_node_footer_blka
+ {
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page));
+       struct f2fs_node *rn = F2FS_NODE(page);
++      size_t crc_offset = le32_to_cpu(ckpt->checksum_offset);
++      __u64 cp_ver = le64_to_cpu(ckpt->checkpoint_ver);
+-      rn->footer.cp_ver = ckpt->checkpoint_ver;
++      if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
++              __u64 crc = le32_to_cpu(*((__le32 *)
++                              ((unsigned char *)ckpt + crc_offset)));
++              cp_ver |= (crc << 32);
++      }
++      rn->footer.cp_ver = cpu_to_le64(cp_ver);
+       rn->footer.next_blkaddr = cpu_to_le32(blkaddr);
+ }
+-static inline nid_t ino_of_node(struct page *node_page)
+-{
+-      struct f2fs_node *rn = F2FS_NODE(node_page);
+-      return le32_to_cpu(rn->footer.ino);
+-}
+-
+-static inline nid_t nid_of_node(struct page *node_page)
+-{
+-      struct f2fs_node *rn = F2FS_NODE(node_page);
+-      return le32_to_cpu(rn->footer.nid);
+-}
+-
+-static inline unsigned int ofs_of_node(struct page *node_page)
+-{
+-      struct f2fs_node *rn = F2FS_NODE(node_page);
+-      unsigned flag = le32_to_cpu(rn->footer.flag);
+-      return flag >> OFFSET_BIT_SHIFT;
+-}
+-
+-static inline unsigned long long cpver_of_node(struct page *node_page)
++static inline bool is_recoverable_dnode(struct page *page)
+ {
+-      struct f2fs_node *rn = F2FS_NODE(node_page);
+-      return le64_to_cpu(rn->footer.cp_ver);
+-}
++      struct f2fs_checkpoint *ckpt = F2FS_CKPT(F2FS_P_SB(page));
++      size_t crc_offset = le32_to_cpu(ckpt->checksum_offset);
++      __u64 cp_ver = cur_cp_version(ckpt);
+-static inline block_t next_blkaddr_of_node(struct page *node_page)
+-{
+-      struct f2fs_node *rn = F2FS_NODE(node_page);
+-      return le32_to_cpu(rn->footer.next_blkaddr);
++      if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) {
++              __u64 crc = le32_to_cpu(*((__le32 *)
++                              ((unsigned char *)ckpt + crc_offset)));
++              cp_ver |= (crc << 32);
++      }
++      return cpu_to_le64(cp_ver) == cpver_of_node(page);
+ }
+ /*
+--- a/fs/f2fs/recovery.c
++++ b/fs/f2fs/recovery.c
+@@ -193,7 +193,6 @@ static void recover_inode(struct inode *
+ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
+ {
+-      unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
+       struct curseg_info *curseg;
+       struct inode *inode;
+       struct page *page = NULL;
+@@ -214,7 +213,7 @@ static int find_fsync_dnodes(struct f2fs
+               page = get_tmp_page(sbi, blkaddr);
+-              if (cp_ver != cpver_of_node(page))
++              if (!is_recoverable_dnode(page))
+                       break;
+               if (!is_fsync_dnode(page))
+@@ -483,7 +482,6 @@ out:
+ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
+                                               struct list_head *dir_list)
+ {
+-      unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
+       struct curseg_info *curseg;
+       struct page *page = NULL;
+       int err = 0;
+@@ -503,7 +501,7 @@ static int recover_data(struct f2fs_sb_i
+               page = get_tmp_page(sbi, blkaddr);
+-              if (cp_ver != cpver_of_node(page)) {
++              if (!is_recoverable_dnode(page)) {
+                       f2fs_put_page(page, 1);
+                       break;
+               }
+@@ -595,31 +593,15 @@ out:
+       }
+       clear_sbi_flag(sbi, SBI_POR_DOING);
+-      if (err) {
+-              bool invalidate = false;
+-
+-              if (discard_next_dnode(sbi, blkaddr))
+-                      invalidate = true;
+-
+-              /* Flush all the NAT/SIT pages */
+-              while (get_pages(sbi, F2FS_DIRTY_META))
+-                      sync_meta_pages(sbi, META, LONG_MAX);
+-
+-              /* invalidate temporary meta page */
+-              if (invalidate)
+-                      invalidate_mapping_pages(META_MAPPING(sbi),
+-                                                      blkaddr, blkaddr);
+-
++      if (err)
+               set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
+-              mutex_unlock(&sbi->cp_mutex);
+-      } else if (need_writecp) {
++      mutex_unlock(&sbi->cp_mutex);
++
++      if (!err && need_writecp) {
+               struct cp_control cpc = {
+                       .reason = CP_RECOVERY,
+               };
+-              mutex_unlock(&sbi->cp_mutex);
+               write_checkpoint(sbi, &cpc);
+-      } else {
+-              mutex_unlock(&sbi->cp_mutex);
+       }
+       destroy_fsync_dnodes(&dir_list);
+--- a/fs/f2fs/segment.c
++++ b/fs/f2fs/segment.c
+@@ -519,28 +519,6 @@ static int f2fs_issue_discard(struct f2f
+       return blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0);
+ }
+-bool discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr)
+-{
+-      int err = -ENOTSUPP;
+-
+-      if (test_opt(sbi, DISCARD)) {
+-              struct seg_entry *se = get_seg_entry(sbi,
+-                              GET_SEGNO(sbi, blkaddr));
+-              unsigned int offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
+-
+-              if (f2fs_test_bit(offset, se->discard_map))
+-                      return false;
+-
+-              err = f2fs_issue_discard(sbi, blkaddr, 1);
+-      }
+-
+-      if (err) {
+-              update_meta_page(sbi, NULL, blkaddr);
+-              return true;
+-      }
+-      return false;
+-}
+-
+ static void __add_discard_entry(struct f2fs_sb_info *sbi,
+               struct cp_control *cpc, struct seg_entry *se,
+               unsigned int start, unsigned int end)
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -1457,6 +1457,9 @@ try_onemore:
+               if (need_fsck)
+                       set_sbi_flag(sbi, SBI_NEED_FSCK);
++              if (!retry)
++                      goto skip_recovery;
++
+               err = recover_fsync_data(sbi, false);
+               if (err < 0) {
+                       need_fsck = true;
+@@ -1474,7 +1477,7 @@ try_onemore:
+                       goto free_kobj;
+               }
+       }
+-
++skip_recovery:
+       /* recover_fsync_data() cleared this already */
+       clear_sbi_flag(sbi, SBI_POR_DOING);
+--- a/include/linux/f2fs_fs.h
++++ b/include/linux/f2fs_fs.h
+@@ -99,6 +99,7 @@ struct f2fs_super_block {
+ /*
+  * For checkpoint
+  */
++#define CP_CRC_RECOVERY_FLAG  0x00000040
+ #define CP_FASTBOOT_FLAG      0x00000020
+ #define CP_FSCK_FLAG          0x00000010
+ #define CP_ERROR_FLAG         0x00000008
index 4f847767cdf96e71a96fc009f995ff2d70272e93..3c22acb859aae22a87908e45656d378bd5aa2d68 100644 (file)
@@ -1,2 +1,37 @@
 tty-ldsem-wake-up-readers-after-timed-out-down_write.patch
 can-gw-ensure-dlc-boundaries-after-can-frame-modification.patch
+f2fs-clean-up-argument-of-recover_data.patch
+f2fs-cover-more-area-with-nat_tree_lock.patch
+f2fs-move-sanity-checking-of-cp-into-get_valid_checkpoint.patch
+f2fs-fix-to-convert-inline-directory-correctly.patch
+f2fs-give-einval-for-norecovery-and-rw-mount.patch
+f2fs-remove-an-obsolete-variable.patch
+f2fs-factor-out-fsync-inode-entry-operations.patch
+f2fs-fix-inode-cache-leak.patch
+f2fs-fix-to-avoid-reading-out-encrypted-data-in-page-cache.patch
+f2fs-not-allow-to-write-illegal-blkaddr.patch
+f2fs-avoid-unneeded-loop-in-build_sit_entries.patch
+f2fs-use-crc-and-cp-version-to-determine-roll-forward-recovery.patch
+f2fs-introduce-get_checkpoint_version-for-cleanup.patch
+f2fs-put-directory-inodes-before-checkpoint-in-roll-forward-recovery.patch
+f2fs-fix-to-determine-start_cp_addr-by-sbi-cur_cp_pack.patch
+f2fs-detect-wrong-layout.patch
+f2fs-free-meta-pages-if-sanity-check-for-ckpt-is-failed.patch
+f2fs-fix-race-condition-in-between-free-nid-allocator-initializer.patch
+f2fs-return-error-during-fill_super.patch
+f2fs-check-blkaddr-more-accuratly-before-issue-a-bio.patch
+f2fs-sanity-check-on-sit-entry.patch
+f2fs-enhance-sanity_check_raw_super-to-avoid-potential-overflow.patch
+f2fs-clean-up-with-is_valid_blkaddr.patch
+f2fs-introduce-and-spread-verify_blkaddr.patch
+f2fs-fix-to-do-sanity-check-with-secs_per_zone.patch
+f2fs-fix-to-do-sanity-check-with-user_block_count.patch
+f2fs-add-sanity_check_inode-function.patch
+f2fs-fix-to-do-sanity-check-with-node-footer-and-iblocks.patch
+f2fs-fix-to-do-sanity-check-with-reserved-blkaddr-of-inline-inode.patch
+f2fs-fix-to-do-sanity-check-with-block-address-in-main-area.patch
+f2fs-fix-to-do-sanity-check-with-block-address-in-main-area-v2.patch
+f2fs-fix-to-do-sanity-check-with-cp_pack_start_sum.patch
+f2fs-fix-invalid-memory-access.patch
+f2fs-fix-missing-up_read.patch
+f2fs-fix-validation-of-the-block-count-in-sanity_check_raw_super.patch