We may encounter both checkpoints invalid in such a case: 1. write checkpoint A, B, C; 2. sudden power-cut during write checkpoint D; 3. fsck changes the total block count of checkpoint C; 4. sudden power-cut during fsck write checkpoint C in place
--------- --------- | ver C | | ver D | | ... | | ... | | content | | content | | ... | | ... | | ver C | | | | ver A | | ver B | --------- --------- As the total # of checkpoint C is changed, an old cp block like ver A or an invalid cp block may be referenced. To avoid both checkpoints invalid, and considering fsck should not update the checkpoint version, fsck could write checkpoint out of place first and then write checkpoint in place. This makes sure the file system is fixed by fsck and at least one of the two checkpoints is valid. Signed-off-by: Weichao Guo <guoweic...@huawei.com> --- fsck/fsck.c | 13 ++++++++++++- fsck/mount.c | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 91c8529..28320d5 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1954,6 +1954,7 @@ static void fix_checkpoint(struct f2fs_sb_info *sbi) u32 i; int ret; u_int32_t crc = 0; + int phase = 0; if (is_set_ckpt_flags(cp, CP_ORPHAN_PRESENT_FLAG)) { orphan_blks = __start_sum_addr(sbi) - 1; @@ -1975,9 +1976,11 @@ static void fix_checkpoint(struct f2fs_sb_info *sbi) *((__le32 *)((unsigned char *)cp + CHECKSUM_OFFSET)) = cpu_to_le32(crc); cp_blk_no = get_sb(cp_blkaddr); - if (sbi->cur_cp == 2) + /* write checkpoint with current version out of place first */ + if (sbi->cur_cp == 1) cp_blk_no += 1 << get_sb(log_blocks_per_seg); +next_step: ret = dev_write_block(cp, cp_blk_no++); ASSERT(ret >= 0); @@ -2002,6 +2005,14 @@ static void fix_checkpoint(struct f2fs_sb_info *sbi) /* Write nat bits */ if (flags & CP_NAT_BITS_FLAG) write_nat_bits(sbi, sb, cp, sbi->cur_cp); + + if (phase == 0) { + cp_blk_no = get_sb(cp_blkaddr); + if (sbi->cur_cp == 2) + cp_blk_no += 1 << get_sb(log_blocks_per_seg); + phase++; + goto next_step; + } } int check_curseg_offset(struct f2fs_sb_info *sbi) diff --git a/fsck/mount.c b/fsck/mount.c index e5574c5..8d7a9bb 100644 --- a/fsck/mount.c +++ b/fsck/mount.c @@ -2088,6 +2088,7 @@ void write_checkpoint(struct f2fs_sb_info *sbi) u32 flags = CP_UMOUNT_FLAG; int i, ret; u_int32_t crc = 0; + int phase = 0; if (is_set_ckpt_flags(cp, CP_ORPHAN_PRESENT_FLAG)) { orphan_blks = __start_sum_addr(sbi) - 1; @@ -2105,9 +2106,11 @@ void write_checkpoint(struct f2fs_sb_info *sbi) *((__le32 *)((unsigned char *)cp + CHECKSUM_OFFSET)) = cpu_to_le32(crc); cp_blk_no = get_sb(cp_blkaddr); - if (sbi->cur_cp == 2) + /* write checkpoint with current version out of place first */ + if (sbi->cur_cp == 1) cp_blk_no += 1 << get_sb(log_blocks_per_seg); +next_step: /* write the first cp */ ret = dev_write_block(cp, cp_blk_no++); ASSERT(ret >= 0); @@ -2142,6 +2145,14 @@ void write_checkpoint(struct f2fs_sb_info *sbi) /* write the last cp */ ret = dev_write_block(cp, cp_blk_no++); ASSERT(ret >= 0); + + if (phase == 0) { + cp_blk_no = get_sb(cp_blkaddr); + if (sbi->cur_cp == 2) + cp_blk_no += 1 << get_sb(log_blocks_per_seg); + phase++; + goto next_step; + } } void build_nat_area_bitmap(struct f2fs_sb_info *sbi) -- 2.10.1 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel