@@ -236,12 +236,14 @@ extern int find_next_free_block(struct f2fs_sb_info *, u64 *, int, int, bool);
extern void duplicate_checkpoint(struct f2fs_sb_info *);
extern void write_checkpoint(struct f2fs_sb_info *);
extern void write_checkpoints(struct f2fs_sb_info *);
+extern void update_checkpoint(struct f2fs_sb_info *, int);
extern void update_superblock(struct f2fs_super_block *, int);
extern void update_data_blkaddr(struct f2fs_sb_info *, nid_t, u16, block_t,
struct f2fs_node *);
extern void update_nat_blkaddr(struct f2fs_sb_info *, nid_t, nid_t, block_t);
extern void print_raw_sb_info(struct f2fs_super_block *);
+extern void print_ckpt_info(struct f2fs_sb_info *);
extern bool is_checkpoint_stop(struct f2fs_super_block *, bool);
extern bool is_inconsistent_error(struct f2fs_super_block *);
extern pgoff_t current_nat_addr(struct f2fs_sb_info *, nid_t, int *);
@@ -23,6 +23,7 @@ void inject_usage(void)
MSG(0, " --str <new string> new string to set\n");
MSG(0, " --idx <slot index> which slot is injected in an array\n");
MSG(0, " --sb <0|1|2> --mb <name> [--idx <index>] --val/str <value/string> inject superblock\n");
+ MSG(0, " --cp <0|1|2> --mb <name> [--idx <index>] --val <value> inject checkpoint\n");
MSG(0, " --dry-run do not really inject\n");
exit(1);
@@ -42,6 +43,22 @@ static void inject_sb_usage(void)
MSG(0, " devs.path: inject path in devs array selected by --idx <index> specified by --str <string>\n");
}
+static void inject_cp_usage(void)
+{
+ MSG(0, "inject.f2fs --cp <0|1|2> --mb <name> [--idx <index>] --val <value> inject checkpoint\n");
+ MSG(0, "[cp]:\n");
+ MSG(0, " 0: auto select the current cp pack\n");
+ MSG(0, " 1: select the first cp pack\n");
+ MSG(0, " 2: select the second cp pack\n");
+ MSG(0, "[mb]:\n");
+ MSG(0, " checkpoint_ver: inject checkpoint_ver\n");
+ MSG(0, " ckpt_flags: inject ckpt_flags\n");
+ MSG(0, " cur_node_segno: inject cur_node_segno array selected by --idx <index>\n");
+ MSG(0, " cur_node_blkoff: inject cur_node_blkoff array selected by --idx <index>\n");
+ MSG(0, " cur_data_segno: inject cur_data_segno array selected by --idx <index>\n");
+ MSG(0, " cur_data_blkoff: inject cur_data_blkoff array selected by --idx <index>\n");
+}
+
int inject_parse_options(int argc, char *argv[], struct inject_option *opt)
{
int o = 0;
@@ -54,6 +71,7 @@ int inject_parse_options(int argc, char *argv[], struct inject_option *opt)
{"val", required_argument, 0, 4},
{"str", required_argument, 0, 5},
{"sb", required_argument, 0, 6},
+ {"cp", required_argument, 0, 7},
{0, 0, 0, 0}
};
@@ -91,6 +109,12 @@ int inject_parse_options(int argc, char *argv[], struct inject_option *opt)
return -ERANGE;
MSG(0, "Info: inject sb %s\n", pack[opt->sb]);
break;
+ case 7:
+ opt->cp = atoi(optarg);
+ if (opt->cp < 0 || opt->cp > 2)
+ return -ERANGE;
+ MSG(0, "Info: inject cp pack %s\n", pack[opt->cp]);
+ break;
case 'd':
if (optarg[0] == '-' || !is_digits(optarg))
return EWRONG_OPT;
@@ -105,6 +129,9 @@ int inject_parse_options(int argc, char *argv[], struct inject_option *opt)
if (opt->sb >= 0) {
inject_sb_usage();
exit(0);
+ } else if (opt->cp >= 0) {
+ inject_cp_usage();
+ exit(0);
}
return EUNKNOWN_OPT;
}
@@ -184,6 +211,101 @@ out:
return ret;
}
+static int inject_cp(struct f2fs_sb_info *sbi, struct inject_option *opt)
+{
+ struct f2fs_checkpoint *cp, *cur_cp = F2FS_CKPT(sbi);
+ char *buf = NULL;
+ int ret = 0;
+
+ if (opt->cp == 0)
+ opt->cp = sbi->cur_cp;
+
+ if (opt->cp != sbi->cur_cp) {
+ struct f2fs_super_block *sb = sbi->raw_super;
+ block_t cp_addr;
+
+ buf = calloc(1, F2FS_BLKSIZE);
+ ASSERT(buf != NULL);
+
+ cp_addr = get_sb(cp_blkaddr);
+ if (opt->cp == 2)
+ cp_addr += 1 << get_sb(log_blocks_per_seg);
+ ret = dev_read_block(buf, cp_addr);
+ ASSERT(ret >= 0);
+
+ cp = (struct f2fs_checkpoint *)buf;
+ sbi->ckpt = cp;
+ } else {
+ cp = cur_cp;
+ }
+
+ if (!strcmp(opt->mb, "checkpoint_ver")) {
+ MSG(0, "Info: inject checkpoint_ver of cp %d: 0x%llx -> 0x%lx\n",
+ opt->cp, get_cp(checkpoint_ver), (u64)opt->val);
+ set_cp(checkpoint_ver, (u64)opt->val);
+ } else if (!strcmp(opt->mb, "ckpt_flags")) {
+ MSG(0, "Info: inject ckpt_flags of cp %d: 0x%x -> 0x%x\n",
+ opt->cp, get_cp(ckpt_flags), (u32)opt->val);
+ set_cp(ckpt_flags, (u32)opt->val);
+ } else if (!strcmp(opt->mb, "cur_node_segno")) {
+ if (opt->idx >= MAX_ACTIVE_NODE_LOGS) {
+ ERR_MSG("invalid index %u of sb->cur_node_segno[]\n",
+ opt->idx);
+ ret = -EINVAL;
+ goto out;
+ }
+ MSG(0, "Info: inject cur_node_segno[%d] of cp %d: 0x%x -> 0x%x\n",
+ opt->idx, opt->cp, get_cp(cur_node_segno[opt->idx]),
+ (u32)opt->val);
+ set_cp(cur_node_segno[opt->idx], (u32)opt->val);
+ } else if (!strcmp(opt->mb, "cur_node_blkoff")) {
+ if (opt->idx >= MAX_ACTIVE_NODE_LOGS) {
+ ERR_MSG("invalid index %u of sb->cur_node_blkoff[]\n",
+ opt->idx);
+ ret = -EINVAL;
+ goto out;
+ }
+ MSG(0, "Info: inject cur_node_blkoff[%d] of cp %d: 0x%x -> 0x%x\n",
+ opt->idx, opt->cp, get_cp(cur_node_blkoff[opt->idx]),
+ (u32)opt->val);
+ set_cp(cur_node_blkoff[opt->idx], (u32)opt->val);
+ } else if (!strcmp(opt->mb, "cur_data_segno")) {
+ if (opt->idx >= MAX_ACTIVE_DATA_LOGS) {
+ ERR_MSG("invalid index %u of sb->cur_data_segno[]\n",
+ opt->idx);
+ ret = -EINVAL;
+ goto out;
+ }
+ MSG(0, "Info: inject cur_data_segno[%d] of cp %d: 0x%x -> 0x%x\n",
+ opt->idx, opt->cp, get_cp(cur_data_segno[opt->idx]),
+ (u32)opt->val);
+ set_cp(cur_data_segno[opt->idx], (u32)opt->val);
+ } else if (!strcmp(opt->mb, "cur_data_blkoff")) {
+ if (opt->idx >= MAX_ACTIVE_DATA_LOGS) {
+ ERR_MSG("invalid index %u of sb->cur_data_blkoff[]\n",
+ opt->idx);
+ ret = -EINVAL;
+ goto out;
+ }
+ MSG(0, "Info: inject cur_data_blkoff[%d] of cp %d: 0x%x -> 0x%x\n",
+ opt->idx, opt->cp, get_cp(cur_data_blkoff[opt->idx]),
+ (u32)opt->val);
+ set_cp(cur_data_blkoff[opt->idx], (u32)opt->val);
+ } else {
+ ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ print_ckpt_info(sbi);
+ update_checkpoint(sbi, opt->cp);
+
+out:
+ free(buf);
+ sbi->ckpt = cur_cp;
+ return ret;
+}
+
int do_inject(struct f2fs_sb_info *sbi)
{
struct inject_option *opt = (struct inject_option *)c.private;
@@ -191,6 +313,8 @@ int do_inject(struct f2fs_sb_info *sbi)
if (opt->sb >= 0)
ret = inject_sb(sbi, opt);
+ else if (opt->cp >= 0)
+ ret = inject_cp(sbi, opt);
return ret;
}
@@ -25,6 +25,7 @@ struct inject_option {
long long val; /* new value */
char *str; /* new string */
int sb; /* which sb */
+ int cp; /* which cp */
};
void inject_usage(void);
@@ -819,6 +819,7 @@ void f2fs_parse_options(int argc, char *argv[])
#ifdef WITH_INJECT
static struct inject_option inject_opt = {
.sb = -1,
+ .cp = -1,
.idx = -1,
};
@@ -3426,6 +3426,12 @@ void write_checkpoints(struct f2fs_sb_info *sbi)
write_checkpoint(sbi);
}
+void update_checkpoint(struct f2fs_sb_info *sbi, int which)
+{
+ sbi->cur_cp = which == 1 ? 2 : 1;
+ write_checkpoint(sbi);
+}
+
void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
{
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
This patch enables injecting checkpoint. To archive this, a helper update_checkpoint() is added to write specific cp. And print_ckpt_info() is exported to show new checkpoint info. The meanings of options are: * cp: means cp is injected, its argument chooses which cp pack to be injected, where 0 means the current valid cp is choosen automatically. The members could be injected in cp contains: * checkpoint_ver: checkpoint version * ckpt_flags: checkpoint flags * cur_node_segno: cur_node_segno array * cur_node_blkoff: cur_node_blkoff array * cur_data_segno: cur_data_segno array * cur_data_blkoff: cur_data_blkoff array Signed-off-by: Sheng Yong <shengyong@oppo.com> --- fsck/fsck.h | 2 + fsck/inject.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++ fsck/inject.h | 1 + fsck/main.c | 1 + fsck/mount.c | 6 +++ 5 files changed, 134 insertions(+)