diff options
Diffstat (limited to 'fsck/mount.c')
-rw-r--r-- | fsck/mount.c | 518 |
1 files changed, 334 insertions, 184 deletions
diff --git a/fsck/mount.c b/fsck/mount.c index e2f3ace..415f977 100644 --- a/fsck/mount.c +++ b/fsck/mount.c @@ -12,7 +12,7 @@ void print_inode_info(struct f2fs_inode *inode) { - int i = 0; + unsigned int i = 0; int namelen = le32_to_cpu(inode->i_namelen); DISP_u32(inode, i_mode); @@ -53,7 +53,7 @@ void print_inode_info(struct f2fs_inode *inode) for (i = 4; i < ADDRS_PER_INODE(inode); i++) { if (inode->i_addr[i] != 0x0) { - printf("i_addr[0x%x] points data block\r\t\t\t\t[0x%4x]\n", + printf("i_addr[0x%x] points data block\r\t\t[0x%4x]\n", i, inode->i_addr[i]); break; } @@ -79,9 +79,11 @@ void print_node_info(struct f2fs_node *node_block) } else { int i; u32 *dump_blk = (u32 *)node_block; - DBG(0, "Node ID [0x%x:%u] is direct node or indirect node.\n", nid, nid); + DBG(0, "Node ID [0x%x:%u] is direct node or indirect node.\n", + nid, nid); for (i = 0; i <= 10; i++) - MSG(0, "[%d]\t\t\t[0x%8x : %d]\n", i, dump_blk[i], dump_blk[i]); + MSG(0, "[%d]\t\t\t[0x%8x : %d]\n", + i, dump_blk[i], dump_blk[i]); } } @@ -129,6 +131,7 @@ void print_raw_sb_info(struct f2fs_sb_info *sbi) DISP_u32(sb, root_ino); DISP_u32(sb, node_ino); DISP_u32(sb, meta_ino); + DISP_u32(sb, cp_payload); printf("\n"); } @@ -210,7 +213,8 @@ int sanity_check_raw_super(struct f2fs_super_block *raw_super) return -1; } - if (F2FS_LOG_SECTORS_PER_BLOCK != le32_to_cpu(raw_super->log_sectors_per_block)) { + if (F2FS_LOG_SECTORS_PER_BLOCK != + le32_to_cpu(raw_super->log_sectors_per_block)) { return -1; } @@ -229,7 +233,7 @@ int validate_super_block(struct f2fs_sb_info *sbi, int block) return 0; free(sbi->raw_super); - MSG(0, "\tCan't find a valid F2FS filesystem in %d superblock\n", block); + MSG(0, "\tCan't find a valid F2FS superblock at 0x%x\n", block); return -EINVAL; } @@ -257,7 +261,8 @@ int init_sb_info(struct f2fs_sb_info *sbi) return 0; } -void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, unsigned long long *version) +void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, + unsigned long long *version) { void *cp_page_1, *cp_page_2; struct f2fs_checkpoint *cp_block; @@ -285,6 +290,7 @@ void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, unsigned lo /* Read the 2nd cp block in this CP pack */ cp_page_2 = malloc(PAGE_SIZE); cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1; + if (dev_read_block(cp_page_2, cp_addr) < 0) goto invalid_cp2; @@ -295,7 +301,7 @@ void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, unsigned lo crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset); if (f2fs_crc_valid(crc, cp_block, crc_offset)) - goto invalid_cp1; + goto invalid_cp2; cur_version = le64_to_cpu(cp_block->checkpoint_ver); @@ -319,8 +325,10 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) unsigned long blk_size = sbi->blocksize; unsigned long long cp1_version = 0, cp2_version = 0; unsigned long long cp_start_blk_no; + unsigned int cp_blks = 1 + le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload); + int ret; - sbi->ckpt = malloc(blk_size); + sbi->ckpt = malloc(cp_blks * blk_size); if (!sbi->ckpt) return -ENOMEM; /* @@ -335,14 +343,19 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version); if (cp1 && cp2) { - if (ver_after(cp2_version, cp1_version)) + if (ver_after(cp2_version, cp1_version)) { cur_page = cp2; - else + sbi->cur_cp = 2; + } else { cur_page = cp1; + sbi->cur_cp = 1; + } } else if (cp1) { cur_page = cp1; + sbi->cur_cp = 1; } else if (cp2) { cur_page = cp2; + sbi->cur_cp = 2; } else { free(cp1); free(cp2); @@ -351,6 +364,22 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi) memcpy(sbi->ckpt, cur_page, blk_size); + if (cp_blks > 1) { + unsigned int i; + unsigned long long cp_blk_no; + + cp_blk_no = le32_to_cpu(raw_sb->cp_blkaddr); + if (cur_page == cp2) + cp_blk_no += 1 << + le32_to_cpu(raw_sb->log_blocks_per_seg); + /* copy sit bitmap */ + for (i = 1; i < cp_blks; i++) { + unsigned char *ckpt = (unsigned char *)sbi->ckpt; + ret = dev_read_block(cur_page, cp_blk_no + i); + ASSERT(ret >= 0); + memcpy(ckpt + i * blk_size, cur_page, blk_size); + } + } free(cp1); free(cp2); return 0; @@ -470,199 +499,181 @@ int build_sit_info(struct f2fs_sb_info *sbi) return 0; } -void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified) +void reset_curseg(struct f2fs_sb_info *sbi, int type) { struct curseg_info *curseg = CURSEG_I(sbi, type); + struct summary_footer *sum_footer; + struct seg_entry *se; - curseg->segno = curseg->next_segno; - curseg->zone = GET_ZONENO_FROM_SEGNO(sbi, curseg->segno); - curseg->next_blkoff = 0; - curseg->next_segno = NULL_SEGNO; - + sum_footer = &(curseg->sum_blk->footer); + memset(sum_footer, 0, sizeof(struct summary_footer)); + if (IS_DATASEG(type)) + SET_SUM_TYPE(sum_footer, SUM_TYPE_DATA); + if (IS_NODESEG(type)) + SET_SUM_TYPE(sum_footer, SUM_TYPE_NODE); + se = get_seg_entry(sbi, curseg->segno); + se->type = type; } -int read_compacted_summaries(struct f2fs_sb_info *sbi) +static void read_compacted_summaries(struct f2fs_sb_info *sbi) { - struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct curseg_info *curseg; + unsigned int i, j, offset; block_t start; char *kaddr; - unsigned int i, j, offset; + int ret; start = start_sum_block(sbi); kaddr = (char *)malloc(PAGE_SIZE); - dev_read_block(kaddr, start++); + ret = dev_read_block(kaddr, start++); + ASSERT(ret >= 0); curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); memcpy(&curseg->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE); curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); - memcpy(&curseg->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE); + memcpy(&curseg->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE, + SUM_JOURNAL_SIZE); offset = 2 * SUM_JOURNAL_SIZE; for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { unsigned short blk_off; - unsigned int segno; + struct curseg_info *curseg = CURSEG_I(sbi, i); - curseg = CURSEG_I(sbi, i); - segno = le32_to_cpu(ckpt->cur_data_segno[i]); - blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); - curseg->next_segno = segno; - reset_curseg(sbi, i, 0); - curseg->alloc_type = ckpt->alloc_type[i]; - curseg->next_blkoff = blk_off; + reset_curseg(sbi, i); if (curseg->alloc_type == SSR) blk_off = sbi->blocks_per_seg; + else + blk_off = curseg->next_blkoff; for (j = 0; j < blk_off; j++) { struct f2fs_summary *s; s = (struct f2fs_summary *)(kaddr + offset); curseg->sum_blk->entries[j] = *s; offset += SUMMARY_SIZE; - if (offset + SUMMARY_SIZE <= PAGE_CACHE_SIZE - SUM_FOOTER_SIZE) + if (offset + SUMMARY_SIZE <= + PAGE_CACHE_SIZE - SUM_FOOTER_SIZE) continue; memset(kaddr, 0, PAGE_SIZE); - dev_read_block(kaddr, start++); + ret = dev_read_block(kaddr, start++); + ASSERT(ret >= 0); offset = 0; } } - free(kaddr); - return 0; } -int restore_node_summary(struct f2fs_sb_info *sbi, +static void restore_node_summary(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk) { struct f2fs_node *node_blk; struct f2fs_summary *sum_entry; - void *page; block_t addr; - int i; + unsigned int i; + int ret; - page = malloc(PAGE_SIZE); - if (!page) - return -ENOMEM; + node_blk = malloc(F2FS_BLKSIZE); + ASSERT(node_blk); /* scan the node segment */ addr = START_BLOCK(sbi, segno); sum_entry = &sum_blk->entries[0]; for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) { - if (dev_read_block(page, addr)) - goto out; - - node_blk = (struct f2fs_node *)page; + ret = dev_read_block(node_blk, addr); + ASSERT(ret >= 0); sum_entry->nid = node_blk->footer.nid; - /* do not change original value */ -#if 0 - sum_entry->version = 0; - sum_entry->ofs_in_node = 0; -#endif addr++; - } -out: - free(page); - return 0; + free(node_blk); } -int read_normal_summaries(struct f2fs_sb_info *sbi, int type) +static void read_normal_summaries(struct f2fs_sb_info *sbi, int type) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct f2fs_summary_block *sum_blk; struct curseg_info *curseg; - unsigned short blk_off; unsigned int segno = 0; block_t blk_addr = 0; + int ret; if (IS_DATASEG(type)) { segno = le32_to_cpu(ckpt->cur_data_segno[type]); - blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - CURSEG_HOT_DATA]); - if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type); else blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); } else { - segno = le32_to_cpu(ckpt->cur_node_segno[type - CURSEG_HOT_NODE]); - blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - CURSEG_HOT_NODE]); - + segno = le32_to_cpu(ckpt->cur_node_segno[type - + CURSEG_HOT_NODE]); if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) - blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, type - CURSEG_HOT_NODE); + blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, + type - CURSEG_HOT_NODE); else blk_addr = GET_SUM_BLKADDR(sbi, segno); } sum_blk = (struct f2fs_summary_block *)malloc(PAGE_SIZE); - dev_read_block(sum_blk, blk_addr); - - if (IS_NODESEG(type)) { - if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) { - struct f2fs_summary *sum_entry = &sum_blk->entries[0]; - int i; - for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) { - /* do not change original value */ -#if 0 - sum_entry->version = 0; - sum_entry->ofs_in_node = 0; -#endif - } - } else { - if (restore_node_summary(sbi, segno, sum_blk)) { - free(sum_blk); - return -EINVAL; - } - } - } + ret = dev_read_block(sum_blk, blk_addr); + ASSERT(ret >= 0); + + if (IS_NODESEG(type) && !is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) + restore_node_summary(sbi, segno, sum_blk); curseg = CURSEG_I(sbi, type); memcpy(curseg->sum_blk, sum_blk, PAGE_CACHE_SIZE); - curseg->next_segno = segno; - reset_curseg(sbi, type, 0); - curseg->alloc_type = ckpt->alloc_type[type]; - curseg->next_blkoff = blk_off; + reset_curseg(sbi, type); free(sum_blk); - - return 0; } -int restore_curseg_summaries(struct f2fs_sb_info *sbi) +static void restore_curseg_summaries(struct f2fs_sb_info *sbi) { int type = CURSEG_HOT_DATA; if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) { - if (read_compacted_summaries(sbi)) - return -EINVAL; + read_compacted_summaries(sbi); type = CURSEG_HOT_NODE; } - for (; type <= CURSEG_COLD_NODE; type++) { - if (read_normal_summaries(sbi, type)) - return -EINVAL; - } - return 0; + for (; type <= CURSEG_COLD_NODE; type++) + read_normal_summaries(sbi, type); } -int build_curseg(struct f2fs_sb_info *sbi) +static void build_curseg(struct f2fs_sb_info *sbi) { + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct curseg_info *array; + unsigned short blk_off; + unsigned int segno; int i; array = malloc(sizeof(*array) * NR_CURSEG_TYPE); + ASSERT(array); SM_I(sbi)->curseg_array = array; for (i = 0; i < NR_CURSEG_TYPE; i++) { array[i].sum_blk = malloc(PAGE_CACHE_SIZE); - if (!array[i].sum_blk) - return -ENOMEM; - array[i].segno = NULL_SEGNO; - array[i].next_blkoff = 0; + ASSERT(array[i].sum_blk); + if (i <= CURSEG_COLD_DATA) { + blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); + segno = le32_to_cpu(ckpt->cur_data_segno[i]); + } + if (i > CURSEG_COLD_DATA) { + blk_off = le16_to_cpu(ckpt->cur_node_blkoff[i - + CURSEG_HOT_NODE]); + segno = le32_to_cpu(ckpt->cur_node_segno[i - + CURSEG_HOT_NODE]); + } + array[i].segno = segno; + array[i].zone = GET_ZONENO_FROM_SEGNO(sbi, segno); + array[i].next_segno = NULL_SEGNO; + array[i].next_blkoff = blk_off; + array[i].alloc_type = ckpt->alloc_type[i]; } - return restore_curseg_summaries(sbi); + restore_curseg_summaries(sbi); } inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) @@ -671,12 +682,14 @@ inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) ASSERT(segno <= end_segno); } -struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi, unsigned int segno) +static struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi, + unsigned int segno) { struct sit_info *sit_i = SIT_I(sbi); unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno); block_t blk_addr = sit_i->sit_base_addr + offset; struct f2fs_sit_block *sit_blk = calloc(BLOCK_SZ, 1); + int ret; check_seg_range(sbi, segno); @@ -684,30 +697,56 @@ struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi, unsigned i if (f2fs_test_bit(offset, sit_i->sit_bitmap)) blk_addr += sit_i->sit_blocks; - dev_read_block(sit_blk, blk_addr); + ret = dev_read_block(sit_blk, blk_addr); + ASSERT(ret >= 0); return sit_blk; } +void rewrite_current_sit_page(struct f2fs_sb_info *sbi, + unsigned int segno, struct f2fs_sit_block *sit_blk) +{ + struct sit_info *sit_i = SIT_I(sbi); + unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno); + block_t blk_addr = sit_i->sit_base_addr + offset; + int ret; + + /* calculate sit block address */ + if (f2fs_test_bit(offset, sit_i->sit_bitmap)) + blk_addr += sit_i->sit_blocks; + + ret = dev_write_block(sit_blk, blk_addr); + ASSERT(ret >= 0); +} + void check_block_count(struct f2fs_sb_info *sbi, - int segno, struct f2fs_sit_entry *raw_sit) + unsigned int segno, struct f2fs_sit_entry *raw_sit) { struct f2fs_sm_info *sm_info = SM_I(sbi); unsigned int end_segno = sm_info->segment_count - 1; int valid_blocks = 0; - int i; + unsigned int i; /* check segment usage */ - ASSERT(GET_SIT_VBLOCKS(raw_sit) <= sbi->blocks_per_seg); + if (GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg) + ASSERT_MSG("Invalid SIT vblocks: segno=0x%x, %u", + segno, GET_SIT_VBLOCKS(raw_sit)); /* check boundary of a given segment number */ - ASSERT(segno <= end_segno); + if (segno > end_segno) + ASSERT_MSG("Invalid SEGNO: 0x%x", segno); /* check bitmap with valid block count */ - for (i = 0; i < sbi->blocks_per_seg; i++) - if (f2fs_test_bit(i, (char *)raw_sit->valid_map)) - valid_blocks++; - ASSERT(GET_SIT_VBLOCKS(raw_sit) == valid_blocks); + for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++) + valid_blocks += get_bits_in_byte(raw_sit->valid_map[i]); + + if (GET_SIT_VBLOCKS(raw_sit) != valid_blocks) + ASSERT_MSG("Wrong SIT valid blocks: segno=0x%x, %u vs. %u", + segno, GET_SIT_VBLOCKS(raw_sit), valid_blocks); + + if (GET_SIT_TYPE(raw_sit) >= NO_CHECK_TYPE) + ASSERT_MSG("Wrong SIT type: segno=0x%x, %u", + segno, GET_SIT_TYPE(raw_sit)); } void seg_info_from_raw_sit(struct seg_entry *se, @@ -728,7 +767,8 @@ struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi, return &sit_i->sentries[segno]; } -int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk) +int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, + struct f2fs_summary_block *sum_blk) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct curseg_info *curseg; @@ -739,18 +779,30 @@ int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summ for (type = 0; type < NR_CURSEG_NODE_TYPE; type++) { if (segno == ckpt->cur_node_segno[type]) { curseg = CURSEG_I(sbi, CURSEG_HOT_NODE + type); + if (!IS_SUM_NODE_SEG(curseg->sum_blk->footer)) { + ASSERT_MSG("segno [0x%x] indicates a data " + "segment, but should be node", + segno); + return -EINVAL; + } memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ); - return SEG_TYPE_CUR_NODE; /* current node seg was not stored */ + return SEG_TYPE_CUR_NODE; } } for (type = 0; type < NR_CURSEG_DATA_TYPE; type++) { if (segno == ckpt->cur_data_segno[type]) { curseg = CURSEG_I(sbi, type); + if (IS_SUM_NODE_SEG(curseg->sum_blk->footer)) { + ASSERT_MSG("segno [0x%x] indicates a node " + "segment, but should be data", + segno); + return -EINVAL; + } + DBG(2, "segno [0x%x] is current data seg[0x%x]\n", + segno, type); memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ); - ASSERT(!IS_SUM_NODE_SEG(sum_blk->footer)); - DBG(2, "segno [0x%x] is current data seg[0x%x]\n", segno, type); - return SEG_TYPE_CUR_DATA; /* current data seg was not stored */ + return SEG_TYPE_CUR_DATA; } } @@ -764,7 +816,8 @@ int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summ } -int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *sum_entry) +int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, + struct f2fs_summary *sum_entry) { struct f2fs_summary_block *sum_blk; u32 segno, offset; @@ -776,16 +829,15 @@ int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *s sum_blk = calloc(BLOCK_SZ, 1); ret = get_sum_block(sbi, segno, sum_blk); - - memcpy(sum_entry, &(sum_blk->entries[offset]), sizeof(struct f2fs_summary)); - + memcpy(sum_entry, &(sum_blk->entries[offset]), + sizeof(struct f2fs_summary)); free(sum_blk); return ret; } -int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *raw_nat) +static void get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, + struct f2fs_nat_entry *raw_nat) { - struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nat_block *nat_block; pgoff_t block_off; @@ -793,13 +845,8 @@ int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *ra int seg_off, entry_off; int ret; - if ((nid / NAT_ENTRY_PER_BLOCK) > fsck->nr_nat_entries) { - DBG(0, "nid is over max nid\n"); - return -EINVAL; - } - if (lookup_nat_in_journal(sbi, nid, raw_nat) >= 0) - return 0; + return; nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1); @@ -817,21 +864,17 @@ int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *ra ret = dev_read_block(nat_block, block_addr); ASSERT(ret >= 0); - memcpy(raw_nat, &nat_block->entries[entry_off], sizeof(struct f2fs_nat_entry)); + memcpy(raw_nat, &nat_block->entries[entry_off], + sizeof(struct f2fs_nat_entry)); free(nat_block); - - return 0; } -int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) +void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) { struct f2fs_nat_entry raw_nat; - int ret; - - ret = get_nat_entry(sbi, nid, &raw_nat); + get_nat_entry(sbi, nid, &raw_nat); ni->nid = nid; node_info_from_raw_nat(ni, &raw_nat); - return ret; } void build_sit_entries(struct f2fs_sb_info *sbi) @@ -892,17 +935,14 @@ int build_segment_manager(struct f2fs_sb_info *sbi) return 0; } -int build_sit_area_bitmap(struct f2fs_sb_info *sbi) +void build_sit_area_bitmap(struct f2fs_sb_info *sbi) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct f2fs_sm_info *sm_i = SM_I(sbi); - int segno = 0, j = 0; + unsigned int segno = 0; char *ptr = NULL; - u32 sum_vblocks = 0; u32 free_segs = 0; - u32 vblocks = 0; - struct seg_entry *se; fsck->sit_area_bitmap_sz = sm_i->main_segments * SIT_VBLOCK_MAP_SIZE; @@ -911,20 +951,13 @@ int build_sit_area_bitmap(struct f2fs_sb_info *sbi) ASSERT(fsck->sit_area_bitmap_sz == fsck->main_area_bitmap_sz); - for (segno = 0; segno < sm_i->main_segments; segno++) { + for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) { se = get_seg_entry(sbi, segno); memcpy(ptr, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); ptr += SIT_VBLOCK_MAP_SIZE; - vblocks = 0; - for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++) { - vblocks += get_bits_in_byte(se->cur_valid_map[j]); - } - ASSERT(vblocks == se->valid_blocks); - if (se->valid_blocks == 0x0) { - if (sbi->ckpt->cur_node_segno[0] == segno || sbi->ckpt->cur_data_segno[0] == segno || sbi->ckpt->cur_node_segno[1] == segno || @@ -935,22 +968,76 @@ int build_sit_area_bitmap(struct f2fs_sb_info *sbi) } else { free_segs++; } - } else { - ASSERT(se->valid_blocks <= 512); sum_vblocks += se->valid_blocks; } } - fsck->chk.sit_valid_blocks = sum_vblocks; fsck->chk.sit_free_segs = free_segs; - DBG(1, "Blocks [0x%x : %d] Free Segs [0x%x : %d]\n\n", sum_vblocks, sum_vblocks, + DBG(1, "Blocks [0x%x : %d] Free Segs [0x%x : %d]\n\n", + sum_vblocks, sum_vblocks, free_segs, free_segs); - return 0; } -int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_entry *raw_nat) +void rewrite_sit_area_bitmap(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); + struct sit_info *sit_i = SIT_I(sbi); + unsigned int segno = 0; + struct f2fs_summary_block *sum = curseg->sum_blk; + char *ptr = NULL; + + /* remove sit journal */ + sum->n_sits = 0; + + fsck->chk.free_segs = 0; + + ptr = fsck->main_area_bitmap; + + for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) { + struct f2fs_sit_block *sit_blk; + struct f2fs_sit_entry *sit; + struct seg_entry *se; + u16 valid_blocks = 0; + u16 type; + int i; + + sit_blk = get_current_sit_page(sbi, segno); + sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)]; + memcpy(sit->valid_map, ptr, SIT_VBLOCK_MAP_SIZE); + + /* update valid block count */ + for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++) + valid_blocks += get_bits_in_byte(sit->valid_map[i]); + + se = get_seg_entry(sbi, segno); + type = se->type; + if (type >= NO_CHECK_TYPE) { + ASSERT(valid_blocks); + type = 0; + } + sit->vblocks = cpu_to_le16((type << SIT_VBLOCKS_SHIFT) | + valid_blocks); + rewrite_current_sit_page(sbi, segno, sit_blk); + free(sit_blk); + + if (valid_blocks == 0 && + sbi->ckpt->cur_node_segno[0] != segno && + sbi->ckpt->cur_data_segno[0] != segno && + sbi->ckpt->cur_node_segno[1] != segno && + sbi->ckpt->cur_data_segno[1] != segno && + sbi->ckpt->cur_node_segno[2] != segno && + sbi->ckpt->cur_data_segno[2] != segno) + fsck->chk.free_segs++; + + ptr += SIT_VBLOCK_MAP_SIZE; + } +} + +int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, + struct f2fs_nat_entry *raw_nat) { struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); struct f2fs_summary_block *sum = curseg->sum_blk; @@ -958,7 +1045,8 @@ int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_ent for (i = 0; i < nats_in_cursum(sum); i++) { if (le32_to_cpu(nid_in_journal(sum, i)) == nid) { - memcpy(raw_nat, &nat_in_journal(sum, i), sizeof(struct f2fs_nat_entry)); + memcpy(raw_nat, &nat_in_journal(sum, i), + sizeof(struct f2fs_nat_entry)); DBG(3, "==> Found nid [0x%x] in nat cache\n", nid); return i; } @@ -966,6 +1054,51 @@ int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_ent return -1; } +void nullify_nat_entry(struct f2fs_sb_info *sbi, u32 nid) +{ + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_summary_block *sum = curseg->sum_blk; + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct f2fs_nat_block *nat_block; + pgoff_t block_off; + pgoff_t block_addr; + int seg_off, entry_off; + int ret; + int i = 0; + + /* check in journal */ + for (i = 0; i < nats_in_cursum(sum); i++) { + if (le32_to_cpu(nid_in_journal(sum, i)) == nid) { + memset(&nat_in_journal(sum, i), 0, + sizeof(struct f2fs_nat_entry)); + FIX_MSG("Remove nid [0x%x] in nat journal\n", nid); + return; + } + } + nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1); + + block_off = nid / NAT_ENTRY_PER_BLOCK; + entry_off = nid % NAT_ENTRY_PER_BLOCK; + + seg_off = block_off >> sbi->log_blocks_per_seg; + block_addr = (pgoff_t)(nm_i->nat_blkaddr + + (seg_off << sbi->log_blocks_per_seg << 1) + + (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); + + if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) + block_addr += sbi->blocks_per_seg; + + ret = dev_read_block(nat_block, block_addr); + ASSERT(ret >= 0); + + memset(&nat_block->entries[entry_off], 0, + sizeof(struct f2fs_nat_entry)); + + ret = dev_write_block(nat_block, block_addr); + ASSERT(ret >= 0); + free(nat_block); +} + void build_nat_area_bitmap(struct f2fs_sb_info *sbi) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); @@ -973,17 +1106,18 @@ void build_nat_area_bitmap(struct f2fs_sb_info *sbi) struct f2fs_nm_info *nm_i = NM_I(sbi); struct f2fs_nat_block *nat_block; u32 nid, nr_nat_blks; - pgoff_t block_off; pgoff_t block_addr; int seg_off; - int ret, i; - + int ret; + unsigned int i; nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1); + ASSERT(nat_block); /* Alloc & build nat entry bitmap */ - nr_nat_blks = (le32_to_cpu(raw_sb->segment_count_nat) / 2) << sbi->log_blocks_per_seg; + nr_nat_blks = (le32_to_cpu(raw_sb->segment_count_nat) / 2) << + sbi->log_blocks_per_seg; fsck->nr_nat_entries = nr_nat_blks * NAT_ENTRY_PER_BLOCK; fsck->nat_area_bitmap_sz = (fsck->nr_nat_entries + 7) / 8; @@ -994,8 +1128,8 @@ void build_nat_area_bitmap(struct f2fs_sb_info *sbi) seg_off = block_off >> sbi->log_blocks_per_seg; block_addr = (pgoff_t)(nm_i->nat_blkaddr + - (seg_off << sbi->log_blocks_per_seg << 1) + - (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); + (seg_off << sbi->log_blocks_per_seg << 1) + + (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) block_addr += sbi->blocks_per_seg; @@ -1009,44 +1143,47 @@ void build_nat_area_bitmap(struct f2fs_sb_info *sbi) struct node_info ni; ni.nid = nid + i; - if ((nid + i) == F2FS_NODE_INO(sbi) || (nid + i) == F2FS_META_INO(sbi)) { + if ((nid + i) == F2FS_NODE_INO(sbi) || + (nid + i) == F2FS_META_INO(sbi)) { ASSERT(nat_block->entries[i].block_addr != 0x0); continue; } - if (lookup_nat_in_journal(sbi, nid + i, &raw_nat) >= 0) { + if (lookup_nat_in_journal(sbi, nid + i, + &raw_nat) >= 0) { node_info_from_raw_nat(&ni, &raw_nat); if (ni.blk_addr != 0x0) { - f2fs_set_bit(nid + i, fsck->nat_area_bitmap); + f2fs_set_bit(nid + i, + fsck->nat_area_bitmap); fsck->chk.valid_nat_entry_cnt++; - DBG(3, "nid[0x%x] in nat cache\n", nid + i); + DBG(3, "nid[0x%x] in nat cache\n", + nid + i); } } else { - node_info_from_raw_nat(&ni, &nat_block->entries[i]); - if (ni.blk_addr != 0) { - ASSERT(nid + i != 0x0); - - DBG(3, "nid[0x%8x] in nat entry [0x%16x] [0x%8x]\n", - nid + i, - ni.blk_addr, - ni.ino); - - f2fs_set_bit(nid + i, fsck->nat_area_bitmap); - fsck->chk.valid_nat_entry_cnt++; - } + node_info_from_raw_nat(&ni, + &nat_block->entries[i]); + if (ni.blk_addr == 0) + continue; + ASSERT(nid + i != 0x0); + + DBG(3, "nid[0x%8x] addr[0x%16x] ino[0x%8x]\n", + nid + i, ni.blk_addr, ni.ino); + f2fs_set_bit(nid + i, fsck->nat_area_bitmap); + fsck->chk.valid_nat_entry_cnt++; } } } free(nat_block); DBG(1, "valid nat entries (block_addr != 0x0) [0x%8x : %u]\n", - fsck->chk.valid_nat_entry_cnt, fsck->chk.valid_nat_entry_cnt); - + fsck->chk.valid_nat_entry_cnt, + fsck->chk.valid_nat_entry_cnt); } int f2fs_do_mount(struct f2fs_sb_info *sbi) { int ret; + sbi->active_logs = NR_CURSEG_TYPE; ret = validate_super_block(sbi, 0); if (ret) { @@ -1072,10 +1209,23 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi) print_ckpt_info(sbi); + if (config.auto_fix) { + u32 flag = le32_to_cpu(sbi->ckpt->ckpt_flags); + + if (flag & CP_FSCK_FLAG) + config.fix_on = 1; + else + return 1; + } + + config.bug_on = 0; + sbi->total_valid_node_count = le32_to_cpu(sbi->ckpt->valid_node_count); - sbi->total_valid_inode_count = le32_to_cpu(sbi->ckpt->valid_inode_count); + sbi->total_valid_inode_count = + le32_to_cpu(sbi->ckpt->valid_inode_count); sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count); - sbi->total_valid_block_count = le64_to_cpu(sbi->ckpt->valid_block_count); + sbi->total_valid_block_count = + le64_to_cpu(sbi->ckpt->valid_block_count); sbi->last_valid_block_count = sbi->total_valid_block_count; sbi->alloc_valid_block_count = 0; @@ -1089,7 +1239,7 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi) return -1; } - return ret; + return 0; } void f2fs_do_umount(struct f2fs_sb_info *sbi) @@ -1097,7 +1247,7 @@ void f2fs_do_umount(struct f2fs_sb_info *sbi) struct sit_info *sit_i = SIT_I(sbi); struct f2fs_sm_info *sm_i = SM_I(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi); - int i; + unsigned int i; /* free nm_info */ free(nm_i->nat_bitmap); |