f2fs: check in-memory block bitmap
authorChao Yu <yuchao0@huawei.com>
Sat, 7 Jan 2017 10:51:01 +0000 (18:51 +0800)
committerGreg Kroah-Hartman <gregkh@google.com>
Tue, 3 Oct 2017 15:22:12 +0000 (15:22 +0000)
commit 355e78913c0d57492076d545b6f44b94fec2bf6b upstream.

This patch adds a mirror for valid block bitmap, and use it to detect
in-memory bitmap corruption which may be caused by bit-transition of
cache or memory overflow.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/segment.c
fs/f2fs/segment.h

index 6a870677d58a1ded9621bb4a932593065d368238..aae1c2ea7a1dbffba07a94ac8aba04086e418d68 100644 (file)
@@ -1101,14 +1101,32 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
 
        /* Update valid block bitmap */
        if (del > 0) {
-               if (f2fs_test_and_set_bit(offset, se->cur_valid_map))
+               if (f2fs_test_and_set_bit(offset, se->cur_valid_map)) {
+#ifdef CONFIG_F2FS_CHECK_FS
+                       if (f2fs_test_and_set_bit(offset,
+                                               se->cur_valid_map_mir))
+                               f2fs_bug_on(sbi, 1);
+                       else
+                               WARN_ON(1);
+#else
                        f2fs_bug_on(sbi, 1);
+#endif
+               }
                if (f2fs_discard_en(sbi) &&
                        !f2fs_test_and_set_bit(offset, se->discard_map))
                        sbi->discard_blks--;
        } else {
-               if (!f2fs_test_and_clear_bit(offset, se->cur_valid_map))
+               if (!f2fs_test_and_clear_bit(offset, se->cur_valid_map)) {
+#ifdef CONFIG_F2FS_CHECK_FS
+                       if (!f2fs_test_and_clear_bit(offset,
+                                               se->cur_valid_map_mir))
+                               f2fs_bug_on(sbi, 1);
+                       else
+                               WARN_ON(1);
+#else
                        f2fs_bug_on(sbi, 1);
+#endif
+               }
                if (f2fs_discard_en(sbi) &&
                        f2fs_test_and_clear_bit(offset, se->discard_map))
                        sbi->discard_blks++;
@@ -2432,6 +2450,13 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
                                !sit_i->sentries[start].ckpt_valid_map)
                        return -ENOMEM;
 
+#ifdef CONFIG_F2FS_CHECK_FS
+               sit_i->sentries[start].cur_valid_map_mir
+                       = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+               if (!sit_i->sentries[start].cur_valid_map_mir)
+                       return -ENOMEM;
+#endif
+
                if (f2fs_discard_en(sbi)) {
                        sit_i->sentries[start].discard_map
                                = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
@@ -2861,6 +2886,9 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)
        if (sit_i->sentries) {
                for (start = 0; start < MAIN_SEGS(sbi); start++) {
                        kfree(sit_i->sentries[start].cur_valid_map);
+#ifdef CONFIG_F2FS_CHECK_FS
+                       kfree(sit_i->sentries[start].cur_valid_map_mir);
+#endif
                        kfree(sit_i->sentries[start].ckpt_valid_map);
                        kfree(sit_i->sentries[start].discard_map);
                }
index 08f1455c812c1a49c027a47d0223dff4adfb44bd..9af95194db069c99233be81506281d4d6e211521 100644 (file)
@@ -164,6 +164,9 @@ struct seg_entry {
        unsigned int ckpt_valid_blocks:10;      /* # of valid blocks last cp */
        unsigned int padding:6;         /* padding */
        unsigned char *cur_valid_map;   /* validity bitmap of blocks */
+#ifdef CONFIG_F2FS_CHECK_FS
+       unsigned char *cur_valid_map_mir;       /* mirror of current valid bitmap */
+#endif
        /*
         * # of valid blocks and the validity bitmap stored in the the last
         * checkpoint pack. This information is used by the SSR mode.
@@ -320,6 +323,9 @@ static inline void seg_info_from_raw_sit(struct seg_entry *se,
        se->ckpt_valid_blocks = GET_SIT_VBLOCKS(rs);
        memcpy(se->cur_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
        memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
+#ifdef CONFIG_F2FS_CHECK_FS
+       memcpy(se->cur_valid_map_mir, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
+#endif
        se->type = GET_SIT_TYPE(rs);
        se->mtime = le64_to_cpu(rs->mtime);
 }