diff options
author | Sheng Yong <shengyong1@huawei.com> | 2016-03-14 14:16:53 +0800 |
---|---|---|
committer | Luca Stefani <luca.stefani.ge1@gmail.com> | 2016-11-12 11:32:44 +0100 |
commit | 2e43334233ed12bd5d1cdd3041b1c47366f9c17c (patch) | |
tree | d36bc060fd9b1556bd6261905cdf1f74870da021 /fsck | |
parent | 0d11d6b7bc35c6ec24e95b22b008a37699047bd1 (diff) | |
download | android_external_f2fs-tools-2e43334233ed12bd5d1cdd3041b1c47366f9c17c.tar.gz android_external_f2fs-tools-2e43334233ed12bd5d1cdd3041b1c47366f9c17c.tar.bz2 android_external_f2fs-tools-2e43334233ed12bd5d1cdd3041b1c47366f9c17c.zip |
fsck.f2fs: introduce -p option to check meta
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>
Diffstat (limited to 'fsck')
-rw-r--r-- | fsck/fsck.c | 59 | ||||
-rw-r--r-- | fsck/fsck.h | 7 | ||||
-rw-r--r-- | fsck/main.c | 39 | ||||
-rw-r--r-- | fsck/mount.c | 4 |
4 files changed, 104 insertions, 5 deletions
diff --git a/fsck/fsck.c b/fsck/fsck.c index c68eae7..fede8e1 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -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); diff --git a/fsck/fsck.h b/fsck/fsck.h index 45e4366..f03efb8 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -15,6 +15,12 @@ #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 *); diff --git a/fsck/main.c b/fsck/main.c index 0e23c81..93008a5 100644 --- a/fsck/main.c +++ b/fsck/main.c @@ -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 */ diff --git a/fsck/mount.c b/fsck/mount.c index 153055e..af1e0c3 100644 --- a/fsck/mount.c +++ b/fsck/mount.c @@ -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; } |