This patch adds nat_bits in the last one ore two 4KB-sized blocks of first checkpoint segment. So, now a set of checkpoint *segment* consists of:
< checkpoint segment > ---------------------- | cp page #1 | 4KB ---------------------- | compacted data sum | 4KB ---------------------- | node sum #1 | 4KB ---------------------- | node sum #2 | 4KB ---------------------- | node sum #3 | 4KB ---------------------- | cp page #2 | 4KB ---------------------- ... ---------------------- | crc|cpver | 8 bytes ---------------------- | full NAT bits | # of NAT segments / 2 * 512 / 8 bytes ---------------------- | empty NAT bits | # of NAT segments / 2 * 512 / 8 bytes ---------------------- Signed-off-by: Jaegeuk Kim <jaeg...@kernel.org> --- fsck/fsck.c | 8 +++- fsck/fsck.h | 5 +++ fsck/mount.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++-- fsck/resize.c | 12 ++++- include/f2fs_fs.h | 12 +++++ mkfs/f2fs_format.c | 48 ++++++++++++++++++-- 6 files changed, 203 insertions(+), 9 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index b625153..116eae5 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -1779,9 +1779,11 @@ static void fix_checkpoint(struct f2fs_sb_info *sbi) flags |= CP_ORPHAN_PRESENT_FLAG; } - set_cp(ckpt_flags, flags); set_cp(cp_pack_total_block_count, 8 + orphan_blks + get_sb(cp_payload)); + flags = update_nat_bits_flags(sb, cp, flags); + set_cp(ckpt_flags, flags); + set_cp(free_segment_count, get_free_segments(sbi)); set_cp(valid_block_count, fsck->chk.valid_blk_cnt); set_cp(valid_node_count, fsck->chk.valid_node_cnt); @@ -1814,6 +1816,10 @@ static void fix_checkpoint(struct f2fs_sb_info *sbi) ret = dev_write_block(cp, cp_blk_no++); ASSERT(ret >= 0); + + /* Write nat bits */ + if (flags & CP_NAT_BITS_FLAG) + write_nat_bits(sbi, sb, cp, sbi->cur_cp); } int check_curseg_offset(struct f2fs_sb_info *sbi) diff --git a/fsck/fsck.h b/fsck/fsck.h index 5a6f018..b6c9cbd 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -178,6 +178,11 @@ extern struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *, extern void rewrite_current_sit_page(struct f2fs_sb_info *, unsigned int, struct f2fs_sit_block *); +extern u32 update_nat_bits_flags(struct f2fs_super_block *, + struct f2fs_checkpoint *, u32); +extern void write_nat_bits(struct f2fs_sb_info *, struct f2fs_super_block *, + struct f2fs_checkpoint *, int); + /* dump.c */ struct dump_option { nid_t nid; diff --git a/fsck/mount.c b/fsck/mount.c index 761baa0..5008437 100644 --- a/fsck/mount.c +++ b/fsck/mount.c @@ -257,6 +257,8 @@ void print_cp_state(u32 flag) MSG(0, "%s", " orphan_inodes"); if (flag & CP_FASTBOOT_FLAG) MSG(0, "%s", " fastboot"); + if (flag & CP_NAT_BITS_FLAG) + MSG(0, "%s", " nat_bits"); if (flag & CP_UMOUNT_FLAG) MSG(0, "%s", " unmount"); else @@ -746,6 +748,92 @@ static int f2fs_init_nid_bitmap(struct f2fs_sb_info *sbi) return 0; } +u32 update_nat_bits_flags(struct f2fs_super_block *sb, + struct f2fs_checkpoint *cp, u32 flags) +{ + u_int32_t nat_bits_bytes, nat_bits_blocks; + + nat_bits_bytes = get_sb(segment_count_nat) << 5; + nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 + + F2FS_BLKSIZE - 1); + if (get_cp(cp_pack_total_block_count) <= + (1 << get_sb(log_blocks_per_seg)) - nat_bits_blocks) + flags |= CP_NAT_BITS_FLAG; + else + flags &= (~CP_NAT_BITS_FLAG); + + return flags; +} + +/* should call flush_journal_entries() bfore this */ +void write_nat_bits(struct f2fs_sb_info *sbi, + struct f2fs_super_block *sb, struct f2fs_checkpoint *cp, int set) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + u_int32_t nat_blocks = get_sb(segment_count_nat) << + (get_sb(log_blocks_per_seg) - 1); + u_int32_t nat_bits_bytes = nat_blocks >> 3; + u_int32_t nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + + 8 + F2FS_BLKSIZE - 1); + unsigned char *nat_bits, *full_nat_bits, *empty_nat_bits; + struct f2fs_nat_block *nat_block; + u_int32_t i, j; + block_t blkaddr; + int ret; + + nat_bits = calloc(F2FS_BLKSIZE, nat_bits_blocks); + ASSERT(nat_bits); + + nat_block = malloc(F2FS_BLKSIZE); + ASSERT(nat_block); + + full_nat_bits = nat_bits + 8; + empty_nat_bits = full_nat_bits + nat_bits_bytes; + + memset(full_nat_bits, 0, nat_bits_bytes); + memset(empty_nat_bits, 0, nat_bits_bytes); + + for (i = 0; i < nat_blocks; i++) { + int seg_off = i >> get_sb(log_blocks_per_seg); + int valid = 0; + + blkaddr = (pgoff_t)(get_sb(nat_blkaddr) + + (seg_off << get_sb(log_blocks_per_seg) << 1) + + (i & ((1 << get_sb(log_blocks_per_seg)) - 1))); + + if (f2fs_test_bit(i, nm_i->nat_bitmap)) + blkaddr += (1 << get_sb(log_blocks_per_seg)); + + ret = dev_read_block(nat_block, blkaddr); + ASSERT(ret >= 0); + + for (j = 0; j < NAT_ENTRY_PER_BLOCK; j++) { + if ((i == 0 && j == 0) || + nat_block->entries[j].block_addr != NULL_ADDR) + valid++; + } + if (valid == 0) + test_and_set_bit_le(i, empty_nat_bits); + else if (valid == NAT_ENTRY_PER_BLOCK) + test_and_set_bit_le(i, full_nat_bits); + } + *(__le64 *)nat_bits = get_cp_crc(cp); + free(nat_block); + + blkaddr = get_sb(segment0_blkaddr) + (set << + get_sb(log_blocks_per_seg)) - nat_bits_blocks; + + DBG(1, "\tWriting NAT bits pages, at offset 0x%08x\n", blkaddr); + + for (i = 0; i < nat_bits_blocks; i++) { + if (dev_write_block(nat_bits + i * F2FS_BLKSIZE, blkaddr + i)) + ASSERT_MSG("\tError: write NAT bits to disk!!!\n"); + } + MSG(0, "Info: Write valid nat_bits in checkpoint\n"); + + free(nat_bits); +} + int init_node_manager(struct f2fs_sb_info *sbi) { struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); @@ -1781,12 +1869,13 @@ void write_checkpoint(struct f2fs_sb_info *sbi) flags |= CP_ORPHAN_PRESENT_FLAG; } - set_cp(ckpt_flags, flags); - set_cp(free_segment_count, get_free_segments(sbi)); set_cp(valid_block_count, sbi->total_valid_block_count); set_cp(cp_pack_total_block_count, 8 + orphan_blks + get_sb(cp_payload)); + flags = update_nat_bits_flags(sb, cp, flags); + set_cp(ckpt_flags, flags); + crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, cp, CHECKSUM_OFFSET); *((__le32 *)((unsigned char *)cp + CHECKSUM_OFFSET)) = cpu_to_le32(crc); @@ -1820,6 +1909,10 @@ void write_checkpoint(struct f2fs_sb_info *sbi) /* write the last cp */ ret = dev_write_block(cp, cp_blk_no++); ASSERT(ret >= 0); + + /* Write nat bits */ + if (flags & CP_NAT_BITS_FLAG) + write_nat_bits(sbi, sb, cp, sbi->cur_cp); } void build_nat_area_bitmap(struct f2fs_sb_info *sbi) @@ -1995,6 +2088,7 @@ static int check_sector_size(struct f2fs_super_block *sb) int f2fs_do_mount(struct f2fs_sb_info *sbi) { struct f2fs_checkpoint *cp = NULL; + struct f2fs_super_block *sb = NULL; int ret; sbi->active_logs = NR_CURSEG_TYPE; @@ -2004,12 +2098,13 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi) if (ret) return -1; } + sb = F2FS_RAW_SUPER(sbi); - ret = check_sector_size(sbi->raw_super); + ret = check_sector_size(sb); if (ret) return -1; - print_raw_sb_info(F2FS_RAW_SUPER(sbi)); + print_raw_sb_info(sb); init_sb_info(sbi); @@ -2055,6 +2150,30 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi) return -1; } + /* Check nat_bits */ + if (is_set_ckpt_flags(cp, CP_NAT_BITS_FLAG)) { + u_int32_t nat_bits_bytes, nat_bits_blocks; + __le64 *kaddr; + u_int32_t blk; + + blk = get_sb(cp_blkaddr) + (1 << get_sb(log_blocks_per_seg)); + if (sbi->cur_cp == 2) + blk += 1 << get_sb(log_blocks_per_seg); + + nat_bits_bytes = get_sb(segment_count_nat) << 5; + nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 + + F2FS_BLKSIZE - 1); + blk -= nat_bits_blocks; + + kaddr = malloc(PAGE_SIZE); + ret = dev_read_block(kaddr, blk); + ASSERT(ret >= 0); + if (*kaddr != get_cp_crc(cp)) + write_nat_bits(sbi, sb, cp, sbi->cur_cp); + else + MSG(0, "Info: Found valid nat_bits in checkpoint\n"); + free(kaddr); + } return 0; } diff --git a/fsck/resize.c b/fsck/resize.c index 4791f74..4584d6f 100644 --- a/fsck/resize.c +++ b/fsck/resize.c @@ -423,6 +423,7 @@ static void rebuild_checkpoint(struct f2fs_sb_info *sbi, block_t orphan_blks = 0; block_t new_cp_blk_no, old_cp_blk_no; u_int32_t crc = 0; + u32 flags; void *buf; int i, ret; @@ -475,12 +476,17 @@ static void rebuild_checkpoint(struct f2fs_sb_info *sbi, ((get_newsb(segment_count_nat) / 2) << get_newsb(log_blocks_per_seg)) / 8); + /* update nat_bits flag */ + flags = update_nat_bits_flags(new_sb, cp, get_cp(ckpt_flags)); + set_cp(ckpt_flags, flags); + memcpy(new_cp, cp, (unsigned char *)cp->sit_nat_version_bitmap - (unsigned char *)cp); new_cp->checkpoint_ver = cpu_to_le64(cp_ver + 1); crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, new_cp, CHECKSUM_OFFSET); - *((__le32 *)((unsigned char *)new_cp + CHECKSUM_OFFSET)) = cpu_to_le32(crc); + *((__le32 *)((unsigned char *)new_cp + CHECKSUM_OFFSET)) = + cpu_to_le32(crc); /* Write a new checkpoint in the other set */ new_cp_blk_no = old_cp_blk_no = get_sb(cp_blkaddr); @@ -521,6 +527,10 @@ static void rebuild_checkpoint(struct f2fs_sb_info *sbi, ret = dev_write_block(new_cp, new_cp_blk_no++); ASSERT(ret >= 0); + /* Write nat bits */ + if (flags & CP_NAT_BITS_FLAG) + write_nat_bits(sbi, new_sb, new_cp, sbi->cur_cp == 1 ? 2 : 1); + /* disable old checkpoint */ memset(buf, 0, BLOCK_SZ); ret = dev_write_block(buf, old_cp_blk_no); diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h index 44c5d61..057adf3 100644 --- a/include/f2fs_fs.h +++ b/include/f2fs_fs.h @@ -514,6 +514,7 @@ struct f2fs_super_block { /* * For checkpoint */ +#define CP_NAT_BITS_FLAG 0x00000080 #define CP_CRC_RECOVERY_FLAG 0x00000040 #define CP_FASTBOOT_FLAG 0x00000020 #define CP_FSCK_FLAG 0x00000010 @@ -1084,4 +1085,15 @@ static inline double get_best_overprovision(struct f2fs_super_block *sb) return max_ovp; } +static inline __le64 get_cp_crc(struct f2fs_checkpoint *cp) +{ + u_int64_t cp_ver = get_cp(checkpoint_ver); + size_t crc_offset = get_cp(checksum_offset); + u_int32_t crc = le32_to_cpu(*(__le32 *)((unsigned char *)cp + + crc_offset)); + + cp_ver |= ((u_int64_t)crc << 32); + return cpu_to_le64(cp_ver); +} + #endif /*__F2FS_FS_H */ diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c index e61adaa..f6279b5 100644 --- a/mkfs/f2fs_format.c +++ b/mkfs/f2fs_format.c @@ -472,8 +472,10 @@ static int f2fs_write_check_point_pack(void) struct f2fs_summary_block *sum = NULL; struct f2fs_journal *journal; u_int32_t blk_size_bytes; + u_int32_t nat_bits_bytes, nat_bits_blocks; + unsigned char *nat_bits = NULL, *empty_nat_bits; u_int64_t cp_seg_blk = 0; - u_int32_t crc = 0; + u_int32_t crc = 0, flags; unsigned int i; char *cp_payload = NULL; char *sum_compact, *sum_compact_p; @@ -499,10 +501,19 @@ static int f2fs_write_check_point_pack(void) } sum_compact_p = sum_compact; + nat_bits_bytes = get_sb(segment_count_nat) << 5; + nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 + + F2FS_BLKSIZE - 1); + nat_bits = calloc(F2FS_BLKSIZE, nat_bits_blocks); + if (nat_bits == NULL) { + MSG(1, "\tError: Calloc Failed for nat bits buffer!!!\n"); + goto free_sum_compact; + } + cp_payload = calloc(F2FS_BLKSIZE, 1); if (cp_payload == NULL) { MSG(1, "\tError: Calloc Failed for cp_payload!!!\n"); - goto free_sum_compact; + goto free_nat_bits; } /* 1. cp page 1 of checkpoint pack 1 */ @@ -539,7 +550,11 @@ static int f2fs_write_check_point_pack(void) get_cp(overprov_segment_count)) * c.blks_per_seg)); /* cp page (2), data summaries (1), node summaries (3) */ set_cp(cp_pack_total_block_count, 6 + get_sb(cp_payload)); - set_cp(ckpt_flags, CP_UMOUNT_FLAG | CP_COMPACT_SUM_FLAG); + flags = CP_UMOUNT_FLAG | CP_COMPACT_SUM_FLAG; + if (get_cp(cp_pack_total_block_count) <= + (1 << get_sb(log_blocks_per_seg)) - nat_bits_blocks) + flags |= CP_NAT_BITS_FLAG; + set_cp(ckpt_flags, flags); set_cp(cp_pack_start_sum, 1 + get_sb(cp_payload)); set_cp(valid_node_count, 1); set_cp(valid_inode_count, 1); @@ -702,6 +717,31 @@ static int f2fs_write_check_point_pack(void) goto free_cp_payload; } + /* write NAT bits, if possible */ + if (flags & CP_NAT_BITS_FLAG) { + int i; + + *(__le64 *)nat_bits = get_cp_crc(cp); + empty_nat_bits = nat_bits + 8 + nat_bits_bytes; + memset(empty_nat_bits, 0xff, nat_bits_bytes); + test_and_clear_bit_le(0, empty_nat_bits); + + /* write the last blocks in cp pack */ + cp_seg_blk = get_sb(segment0_blkaddr) + (1 << + get_sb(log_blocks_per_seg)) - nat_bits_blocks; + + DBG(1, "\tWriting NAT bits pages, at offset 0x%08"PRIx64"\n", + cp_seg_blk); + + for (i = 0; i < nat_bits_blocks; i++) { + if (dev_write_block(nat_bits + i * + F2FS_BLKSIZE, cp_seg_blk + i)) { + MSG(1, "\tError: write NAT bits to disk!!!\n"); + goto free_cp_payload; + } + } + } + /* cp page 1 of check point pack 2 * Initiatialize other checkpoint pack with version zero */ @@ -741,6 +781,8 @@ static int f2fs_write_check_point_pack(void) free_cp_payload: free(cp_payload); +free_nat_bits: + free(nat_bits); free_sum_compact: free(sum_compact); free_sum: -- 2.11.0 ------------------------------------------------------------------------------ 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