fsck.f2fs: introduce -p option to check meta
authorSheng Yong <shengyong1@huawei.com>
Mon, 14 Mar 2016 06:16:53 +0000 (14:16 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 22 Mar 2016 21:10:00 +0000 (14:10 -0700)
This patch introduces a new option '-p' to do more checks on NAT/SIT areas.
'-p' has 2 levels: level 1 has the same sematics as '-a'; level 2 checks
NAT/SIT counters to see if they matches the status in SB and CP.

A new function, fsck_chk_meta, is called by '-p 1' to implement these
comparsion. If errors are detected, fix_on is set, which means fsck will
do a 'fsck -f' immediately.

Signed-off-by: Sheng Yong <shengyong1@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fsck/fsck.c
fsck/fsck.h
fsck/main.c
fsck/mount.c
include/f2fs_fs.h

index c68eae7..fede8e1 100644 (file)
@@ -1517,6 +1517,65 @@ void fsck_chk_orphan_node(struct f2fs_sb_info *sbi)
        free(new_blk);
 }
 
+int fsck_chk_meta(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+       struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
+       struct seg_entry *se;
+       unsigned int sit_valid_segs = 0, sit_node_blks = 0;
+       unsigned int i;
+
+       /* 1. check sit usage with CP: curseg is lost? */
+       for (i = 0; i < TOTAL_SEGS(sbi); i++) {
+               se = get_seg_entry(sbi, i);
+               if (se->valid_blocks != 0)
+                       sit_valid_segs++;
+               else if (IS_CUR_SEGNO(sbi, i, NO_CHECK_TYPE)) {
+                       /* curseg has not been written back to device */
+                       MSG(1, "\tInfo: curseg %u is counted in valid segs\n", i);
+                       sit_valid_segs++;
+               }
+               if (IS_NODESEG(se->type))
+                       sit_node_blks += se->valid_blocks;
+       }
+       if (fsck->chk.sit_free_segs + sit_valid_segs != TOTAL_SEGS(sbi)) {
+               ASSERT_MSG("SIT usage does not match: sit_free_segs %u, "
+                               "sit_valid_segs %u, total_segs %u",
+                       fsck->chk.sit_free_segs, sit_valid_segs,
+                       TOTAL_SEGS(sbi));
+               return -EINVAL;
+       }
+
+       /* 2. check node count */
+       if (fsck->chk.valid_nat_entry_cnt != sit_node_blks) {
+               ASSERT_MSG("node count does not match: valid_nat_entry_cnt %u,"
+                       " sit_node_blks %u",
+                       fsck->chk.valid_nat_entry_cnt, sit_node_blks);
+               return -EINVAL;
+       }
+
+       /* 3. check SIT with CP */
+       if (fsck->chk.sit_free_segs != le32_to_cpu(cp->free_segment_count)) {
+               ASSERT_MSG("free segs does not match: sit_free_segs %u, "
+                               "free_segment_count %u",
+                               fsck->chk.sit_free_segs,
+                               le32_to_cpu(cp->free_segment_count));
+               return -EINVAL;
+       }
+
+       /* 4. check NAT with CP */
+       if (fsck->chk.valid_nat_entry_cnt !=
+                                       le32_to_cpu(cp->valid_node_count)) {
+               ASSERT_MSG("valid node does not match: valid_nat_entry_cnt %u,"
+                               " valid_node_count %u",
+                               fsck->chk.valid_nat_entry_cnt,
+                               le32_to_cpu(cp->valid_node_count));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 void fsck_init(struct f2fs_sb_info *sbi)
 {
        struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
index 45e4366..f03efb8 100644 (file)
 
 #define FSCK_UNMATCHED_EXTENT          0x00000001
 
+enum {
+       PREEN_MODE_0,
+       PREEN_MODE_1,
+       PREEN_MODE_MAX
+};
+
 /* fsck.c */
 struct orphan_info {
        u32 nr_inodes;
@@ -119,6 +125,7 @@ extern int fsck_chk_dentry_blk(struct f2fs_sb_info *, u32, struct child_info *,
                int, int);
 int fsck_chk_inline_dentries(struct f2fs_sb_info *, struct f2fs_node *,
                struct child_info *);
+int fsck_chk_meta(struct f2fs_sb_info *sbi);
 
 void print_cp_state(u32);
 extern void print_node_info(struct f2fs_node *);
index 0e23c81..93008a5 100644 (file)
@@ -22,7 +22,7 @@ void fsck_usage()
        MSG(0, "  -a check/fix potential corruption, reported by f2fs\n");
        MSG(0, "  -d debug level [default:0]\n");
        MSG(0, "  -f check/fix entire partition\n");
-       MSG(0, "  -p preen mode [default is same as -a]\n");
+       MSG(0, "  -p preen mode [default:0 the same as -a [0|1]]\n");
        MSG(0, "  -t show directory tree [-d -1]\n");
        exit(1);
 }
@@ -58,16 +58,30 @@ void f2fs_parse_options(int argc, char *argv[])
        char *prog = basename(argv[0]);
 
        if (!strcmp("fsck.f2fs", prog)) {
-               const char *option_string = "ad:fpt";
+               const char *option_string = "ad:fp:t";
 
                config.func = FSCK;
                while ((option = getopt(argc, argv, option_string)) != EOF) {
                        switch (option) {
                        case 'a':
-                       case 'p':
                                config.auto_fix = 1;
                                MSG(0, "Info: Fix the reported corruption.\n");
                                break;
+                       case 'p':
+                               /* preen mode has different levels:
+                                *  0: default level, the same as -a
+                                *  1: check meta
+                                */
+                               config.preen_mode = atoi(optarg);
+                               if (config.preen_mode < 0)
+                                       config.preen_mode = PREEN_MODE_0;
+                               else if (config.preen_mode >= PREEN_MODE_MAX)
+                                       config.preen_mode = PREEN_MODE_MAX - 1;
+                               if (config.preen_mode == PREEN_MODE_0)
+                                       config.auto_fix = 1;
+                               MSG(0, "Info: Fix the reported corruption in "
+                                       "preen mode %d\n", config.preen_mode);
+                               break;
                        case 'd':
                                config.dbg_lv = atoi(optarg);
                                MSG(0, "Info: Debug level = %d\n",
@@ -213,6 +227,25 @@ static void do_fsck(struct f2fs_sb_info *sbi)
 
        print_cp_state(flag);
 
+       if (!config.fix_on && !config.bug_on) {
+               switch (config.preen_mode) {
+               case PREEN_MODE_1:
+                       if (fsck_chk_meta(sbi)) {
+                               MSG(0, "[FSCK] F2FS metadata   [Fail]");
+                               MSG(0, "\tError: meta does not match, "
+                                       "force check all\n");
+                       } else {
+                               MSG(0, "[FSCK] F2FS metadata   [Ok..]");
+                               fsck_free(sbi);
+                               return;
+                       }
+
+                       if (!config.ro)
+                               config.fix_on = 1;
+                       break;
+               }
+       }
+
        fsck_chk_orphan_node(sbi);
 
        /* Traverse all block recursively from root inode */
index 153055e..af1e0c3 100644 (file)
@@ -1749,12 +1749,12 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
 
        print_ckpt_info(sbi);
 
-       if (config.auto_fix) {
+       if (config.auto_fix || config.preen_mode) {
                u32 flag = get_cp(ckpt_flags);
 
                if (flag & CP_FSCK_FLAG)
                        config.fix_on = 1;
-               else
+               else if (!config.preen_mode)
                        return 1;
        }
 
index 0046be6..330cbe5 100644 (file)
@@ -251,6 +251,7 @@ struct f2fs_configuration {
        int fix_on;
        int bug_on;
        int auto_fix;
+       int preen_mode;
        int ro;
        __le32 feature;                 /* defined features */