aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@kernel.org>2014-08-26 17:26:01 -0700
committerJaegeuk Kim <jaegeuk@kernel.org>2014-08-29 13:43:27 -0700
commit6f4106c12bb2faa6cd9922ae3a03b400bdf49fde (patch)
tree1d8b88411b6c064ea42cd2997970b106e50b864a
parentf46078949bdc58736170a2c85ea5b8bd3bcefa25 (diff)
downloadandroid_external_f2fs-tools-6f4106c12bb2faa6cd9922ae3a03b400bdf49fde.tar.gz
android_external_f2fs-tools-6f4106c12bb2faa6cd9922ae3a03b400bdf49fde.tar.bz2
android_external_f2fs-tools-6f4106c12bb2faa6cd9922ae3a03b400bdf49fde.zip
fsck.f2fs: retry to fix corrupted image
This patch adds a facility to retry conducting fsck. Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fsck/fsck.c9
-rw-r--r--fsck/main.c141
-rw-r--r--include/f2fs_fs.h5
3 files changed, 104 insertions, 51 deletions
diff --git a/fsck/fsck.c b/fsck/fsck.c
index 303ba8d..9a4c26c 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -761,6 +761,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
node->nid, node->links);
node = node->next;
}
+ config.bug_on = 1;
}
printf("[FSCK] Unreachable nat entries ");
@@ -769,6 +770,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", nr_unref_nid);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] SIT valid block bitmap checking ");
@@ -777,6 +779,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf("[Fail]\n");
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] Hard link checking for regular file ");
@@ -785,6 +788,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.multi_hard_link_files);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_block_count matching with CP ");
@@ -793,6 +797,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", (u32)fsck->chk.valid_blk_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_node_count matcing with CP (de lookup) ");
@@ -801,6 +806,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_node_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_node_count matcing with CP (nat lookup) ");
@@ -809,6 +815,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_nat_entry_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_inode_count matched with CP ");
@@ -817,8 +824,8 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_inode_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
-
return ret;
}
diff --git a/fsck/main.c b/fsck/main.c
index 46f5d04..266e9b5 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -11,9 +11,7 @@
#include "fsck.h"
#include <libgen.h>
-struct f2fs_fsck gfsck = {
- .sbi = { .fsck = &gfsck, },
-};
+struct f2fs_fsck gfsck;
void fsck_usage()
{
@@ -42,22 +40,27 @@ void f2fs_parse_options(int argc, char *argv[])
char *prog = basename(argv[0]);
if (!strcmp("fsck.f2fs", prog)) {
- const char *option_string = "d:t";
+ const char *option_string = "d:tf";
config.func = FSCK;
while ((option = getopt(argc, argv, option_string)) != EOF) {
switch (option) {
- case 'd':
- config.dbg_lv = atoi(optarg);
- MSG(0, "Info: Debug level = %d\n", config.dbg_lv);
- break;
- case 't':
- config.dbg_lv = -1;
- break;
- default:
- MSG(0, "\tError: Unknown option %c\n",option);
- fsck_usage();
- break;
+ case 'd':
+ config.dbg_lv = atoi(optarg);
+ MSG(0, "Info: Debug level = %d\n",
+ config.dbg_lv);
+ break;
+ case 't':
+ config.dbg_lv = -1;
+ break;
+ case 'f':
+ config.fix_on = 1;
+ MSG(0, "Info: Force to fix corruption\n");
+ break;
+ default:
+ MSG(0, "\tError: Unknown option %c\n", option);
+ fsck_usage();
+ break;
}
}
} else if (!strcmp("dump.f2fs", prog)) {
@@ -73,34 +76,46 @@ void f2fs_parse_options(int argc, char *argv[])
config.func = DUMP;
while ((option = getopt(argc, argv, option_string)) != EOF) {
+ int ret = 0;
+
switch (option) {
- case 'd':
- config.dbg_lv = atoi(optarg);
- MSG(0, "Info: Debug level = %d\n", config.dbg_lv);
- break;
- case 'i':
- if (strncmp(optarg, "0x", 2))
- sscanf(optarg, "%d", &dump_opt.nid);
- else
- sscanf(optarg, "%x", &dump_opt.nid);
- break;
- case 's':
- sscanf(optarg, "%d~%d", &dump_opt.start_sit, &dump_opt.end_sit);
- break;
- case 'a':
- sscanf(optarg, "%d~%d", &dump_opt.start_ssa, &dump_opt.end_ssa);
- break;
- case 'b':
- if (strncmp(optarg, "0x", 2))
- sscanf(optarg, "%d", &dump_opt.blk_addr);
- else
- sscanf(optarg, "%x", &dump_opt.blk_addr);
- break;
- default:
- MSG(0, "\tError: Unknown option %c\n", option);
- dump_usage();
- break;
+ case 'd':
+ config.dbg_lv = atoi(optarg);
+ MSG(0, "Info: Debug level = %d\n",
+ config.dbg_lv);
+ break;
+ case 'i':
+ if (strncmp(optarg, "0x", 2))
+ ret = sscanf(optarg, "%d",
+ &dump_opt.nid);
+ else
+ ret = sscanf(optarg, "%x",
+ &dump_opt.nid);
+ break;
+ case 's':
+ ret = sscanf(optarg, "%d~%d",
+ &dump_opt.start_sit,
+ &dump_opt.end_sit);
+ break;
+ case 'a':
+ ret = sscanf(optarg, "%d~%d",
+ &dump_opt.start_ssa,
+ &dump_opt.end_ssa);
+ break;
+ case 'b':
+ if (strncmp(optarg, "0x", 2))
+ ret = sscanf(optarg, "%d",
+ &dump_opt.blk_addr);
+ else
+ ret = sscanf(optarg, "%x",
+ &dump_opt.blk_addr);
+ break;
+ default:
+ MSG(0, "\tError: Unknown option %c\n", option);
+ dump_usage();
+ break;
}
+ ASSERT(ret >= 0);
}
config.private = &dump_opt;
@@ -121,13 +136,15 @@ int do_fsck(struct f2fs_sb_info *sbi)
u32 blk_cnt;
int ret;
+ config.bug_on = 0;
+
ret = fsck_init(sbi);
if (ret < 0)
return ret;
fsck_chk_orphan_node(sbi);
- /* Travses all block recursively from root inode */
+ /* Traverse all block recursively from root inode */
blk_cnt = 1;
ret = fsck_chk_node_blk(sbi,
NULL,
@@ -139,7 +156,6 @@ int do_fsck(struct f2fs_sb_info *sbi)
goto out1;
ret = fsck_verify(sbi);
-
out1:
fsck_free(sbi);
return ret;
@@ -176,7 +192,7 @@ cleanup:
int main (int argc, char **argv)
{
- struct f2fs_sb_info *sbi = &gfsck.sbi;
+ struct f2fs_sb_info *sbi;
int ret = 0;
f2fs_init_configuration(&config);
@@ -189,21 +205,46 @@ int main (int argc, char **argv)
/* Get device */
if (f2fs_get_device_info(&config) < 0)
return -1;
+fsck_again:
+ memset(&gfsck, 0, sizeof(gfsck));
+ gfsck.sbi.fsck = &gfsck;
+ sbi = &gfsck.sbi;
if (f2fs_do_mount(sbi) < 0)
return -1;
switch (config.func) {
- case FSCK:
- ret = do_fsck(sbi);
- break;
- case DUMP:
- ret = do_dump(sbi);
- break;
+ case FSCK:
+ ret = do_fsck(sbi);
+ break;
+ case DUMP:
+ ret = do_dump(sbi);
+ break;
}
f2fs_do_umount(sbi);
+ if (config.func == FSCK && config.bug_on) {
+ if (config.fix_on == 0) {
+ char ans[255] = {0};
+retry:
+ printf("Do you want to fix this partition? [Y/N] ");
+ ret = scanf("%s", ans);
+ ASSERT(ret >= 0);
+ if (!strcasecmp(ans, "y"))
+ config.fix_cnt++;
+ else if (!strcasecmp(ans, "n"))
+ config.fix_cnt = 0;
+ else
+ goto retry;
+ } else {
+ config.fix_cnt++;
+ }
+ /* avoid infinite trials */
+ if (config.fix_cnt > 0 && config.fix_cnt < 4)
+ goto fsck_again;
+ }
+
f2fs_finalize_device(&config);
printf("\nDone.\n");
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index aebb1d2..49911a0 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -60,6 +60,7 @@ typedef unsigned long pgoff_t;
printf("\nAssertion failed!\n"); \
printf("[%s:%4d] " #exp, __func__, __LINE__); \
printf("\n --> "fmt, ##__VA_ARGS__); \
+ config.bug_on = 1; \
exit(-1); \
} \
} while (0);
@@ -69,6 +70,7 @@ typedef unsigned long pgoff_t;
if (!(exp)) { \
printf("\nAssertion failed!\n"); \
printf("[%s:%4d] " #exp"\n", __func__, __LINE__);\
+ config.bug_on = 1; \
exit(-1); \
} \
} while (0);
@@ -180,6 +182,9 @@ struct f2fs_configuration {
int trim;
int func;
void *private;
+ int fix_on;
+ int fix_cnt;
+ int bug_on;
} __attribute__((packed));
#ifdef CONFIG_64BIT