aboutsummaryrefslogtreecommitdiffstats
path: root/fsck
diff options
context:
space:
mode:
authorSheng Yong <shengyong1@huawei.com>2016-03-14 14:16:53 +0800
committerLuca Stefani <luca.stefani.ge1@gmail.com>2016-11-12 11:32:44 +0100
commit2e43334233ed12bd5d1cdd3041b1c47366f9c17c (patch)
treed36bc060fd9b1556bd6261905cdf1f74870da021 /fsck
parent0d11d6b7bc35c6ec24e95b22b008a37699047bd1 (diff)
downloadandroid_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.c59
-rw-r--r--fsck/fsck.h7
-rw-r--r--fsck/main.c39
-rw-r--r--fsck/mount.c4
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;
}