This original patch was from Weichao Guo. We may encounter both checkpoints invalid in such a case: 1. kernel writes CP A; 2. power-cut when kernel writes CP B, then CP B is corrupted; 3. fsck: load CP A, fix meta/data; 4. power-cut when fsck writes CP A in-place, then CP A is corrupted too;
To avoid both checkpoints being invalid, this patch changes to duplicate valid checkpoint to mirror position first, and then, write fixed checkpoint to CP #0 position. This can make sure that, while fsck repairing, even there is sudden power-cut, last valid checkpoint can be kept in CP #1 position. Signed-off-by: Weichao Guo <[email protected]> Signed-off-by: Chao Yu <[email protected]> --- v2: - duplicate valid CP to mirror position, update CP on #0 position. fsck/f2fs.h | 2 ++ fsck/fsck.c | 14 ++++++++++++-- fsck/fsck.h | 2 ++ fsck/mount.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 66 insertions(+), 3 deletions(-) diff --git a/fsck/f2fs.h b/fsck/f2fs.h index 4dc6698..52e68ec 100644 --- a/fsck/f2fs.h +++ b/fsck/f2fs.h @@ -195,6 +195,8 @@ struct f2fs_sb_info { unsigned int cur_victim_sec; /* current victim section num */ u32 free_segments; + + int cp_backuped; /* backup valid checkpoint */ }; static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi) diff --git a/fsck/fsck.c b/fsck/fsck.c index 8953ca1..aee45d9 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -2127,6 +2127,16 @@ static void fix_checkpoint(struct f2fs_sb_info *sbi) ASSERT(ret >= 0); } +static void fix_checkpoints(struct f2fs_sb_info *sbi) +{ + /* copy valid checkpoint to its mirror position */ + duplicate_checkpoint(sbi); + + /* repair checkpoint at CP #0 position */ + sbi->cur_cp = 1; + fix_checkpoint(sbi); +} + int check_curseg_offset(struct f2fs_sb_info *sbi, int type) { struct curseg_info *curseg = CURSEG_I(sbi, type); @@ -2777,10 +2787,10 @@ int fsck_verify(struct f2fs_sb_info *sbi) rewrite_sit_area_bitmap(sbi); fix_curseg_info(sbi); fix_checksum(sbi); - fix_checkpoint(sbi); + fix_checkpoints(sbi); } else if (is_set_ckpt_flags(cp, CP_FSCK_FLAG) || is_set_ckpt_flags(cp, CP_QUOTA_NEED_FSCK_FLAG)) { - write_checkpoint(sbi); + write_checkpoints(sbi); } } return ret; diff --git a/fsck/fsck.h b/fsck/fsck.h index d38e8de..3699b35 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -191,7 +191,9 @@ extern void flush_sit_entries(struct f2fs_sb_info *); extern void move_curseg_info(struct f2fs_sb_info *, u64, int); extern void write_curseg_info(struct f2fs_sb_info *); extern int find_next_free_block(struct f2fs_sb_info *, u64 *, int, int); +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_superblock(struct f2fs_super_block *, int); extern void update_data_blkaddr(struct f2fs_sb_info *, nid_t, u16, block_t); extern void update_nat_blkaddr(struct f2fs_sb_info *, nid_t, nid_t, block_t); diff --git a/fsck/mount.c b/fsck/mount.c index 60e0e4a..89f538b 100644 --- a/fsck/mount.c +++ b/fsck/mount.c @@ -2229,7 +2229,7 @@ void flush_journal_entries(struct f2fs_sb_info *sbi) int n_sits = flush_sit_journal_entries(sbi); if (n_nats || n_sits) - write_checkpoint(sbi); + write_checkpoints(sbi); } void flush_sit_entries(struct f2fs_sb_info *sbi) @@ -2478,6 +2478,45 @@ void nullify_nat_entry(struct f2fs_sb_info *sbi, u32 nid) free(nat_block); } +void duplicate_checkpoint(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + unsigned long long dst, src; + void *buf; + unsigned int seg_size = 1 << get_sb(log_blocks_per_seg); + int ret; + + if (sbi->cp_backuped) + return; + + buf = malloc(F2FS_BLKSIZE * seg_size); + ASSERT(buf); + + if (sbi->cur_cp == 1) { + src = get_sb(cp_blkaddr); + dst = src + seg_size; + } else { + dst = get_sb(cp_blkaddr); + src = dst + seg_size; + } + + ret = dev_read(buf, src << F2FS_BLKSIZE_BITS, seg_size); + ASSERT(ret >= 0); + + ret = dev_write(buf, dst << F2FS_BLKSIZE_BITS, seg_size); + ASSERT(ret >= 0); + + free(buf); + + ret = f2fs_fsync_device(); + ASSERT(ret >= 0); + + sbi->cp_backuped = 1; + + MSG(0, "Info: Duplicate valid checkpoint to mirror position " + "%llu -> %llu\n", src, dst); +} + void write_checkpoint(struct f2fs_sb_info *sbi) { struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); @@ -2557,6 +2596,16 @@ void write_checkpoint(struct f2fs_sb_info *sbi) ASSERT(ret >= 0); } +void write_checkpoints(struct f2fs_sb_info *sbi) +{ + /* copy valid checkpoint to its mirror position */ + duplicate_checkpoint(sbi); + + /* repair checkpoint at CP #0 position */ + sbi->cur_cp = 1; + write_checkpoint(sbi); +} + void build_nat_area_bitmap(struct f2fs_sb_info *sbi) { struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); -- 2.18.0.rc1 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
