do_fsck首先调用fsck_init对f2fs_fsxk的一些字段进行初始化。
fsck_init首先对f2fs_fsck的nr_main_blks,main_area_bitmap_sz和main_area_bitmap进行一个初始化,nr_main_blks初始化为f2fs文件系统的main area的block的数量,然后是main_area_bitmap_sz初始化为记录nr_main_blks个block的位图所需的字节大小。最后是分配nr_main_blks个字节大小的空间给main_area_bitmap,并将其置位全部都是0,这个有效位图在后面检查的时候,每次检查到一个块地址时,将其置位为1,但是,如果检查到一个块地址的时候发现已经只为了,说明这个块地址被重复使用。所以,在结束的时候,这个位图会记录所有被用到的块。这个位图正常情况下应该是跟f2fs_sit_map中的位图合并起来是一致的。然后build_nat_area_bitmap对f2fs_fsck的nr_nat_entries、nat_area_bitmap_sz和 nat_area_bitmap以及entries进行初始化。最后build_sit_area_bitmap对f2fs_fsck中的sit_area_bitmap_sz、sit_area_bitmap和check_result中的 sit_valid_blocks、sit_free_segs的初始化。
void fsck_init(struct f2fs_sb_info *sbi)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_sm_info *sm_i = SM_I(sbi);
fsck->nr_main_blks = sm_i->main_segments << sbi->log_blocks_per_seg;
fsck->main_area_bitmap_sz = (fsck->nr_main_blks + 7) / 8;
fsck->main_area_bitmap = calloc(fsck->main_area_bitmap_sz, 1);
ASSERT(fsck->main_area_bitmap != NULL);
build_nat_area_bitmap(sbi);
build_sit_area_bitmap(sbi);
ASSERT(tree_mark_size != 0);
tree_mark = calloc(tree_mark_size, 1);
ASSERT(tree_mark != NULL);
}
build_nat_area_bitmap首先对f2fs_fsck的nr_nat_entries、nat_area_bitmap_sz和 nat_area_bitmap进行初始化,nr_nat_entries初始化为f2fs文件系统的f2fs_nat_entry的数量,然后是nat_area_bitmap_sz初始化为记录nr_nat_entries个位图所需的字节大小。接下来是分配nr_nat_entries个字节大小的空间给nat_area_bitmap(这个位图在初始化的时候如果nid==0,meta_inode,node_inode出现问题,那么就将其进行置位,这个在f2fs_verify的时候会对这个问题进行处理,对于其他的nid,初始化的时候只有正常的情况下才会置位,这是因为在后面的检查中,凡是遇到正常的nid都会将nat_area_bitmap中的位clear掉,也就是正常情况下,检查结束的时候这个位图应该是全部清位的,nid==0,meta_inode,node_inode这三个出问题在这里初始化的时候就要置位是因为后面的遍历是不会遍历这三个nid的),最后分配nr_nat_entries个f2fs_nat_entry的空间给f2fs_fsck中的entries来保存所有正常的f2fs_nat_entries,当然,不正常的地方初始化为0就行了。接下来由于f2fs_entry_blcok每个都有两个副本,但是有效的那个记录在check point pack中的nat_bitmap中,所以根据这个将所有有效的f2fs_nat_entry读取出来。这些f2fs_nat_entry有些nid是用到的,有些却是没有用到的,而且还有一些由于用作特殊用途,所以我们区分出这些情况来将真正有效的选出来在nat_area_bitmap中置位,并将相应的f2fs_nat_entry拷贝到f2fs_fsck的entries数组的相应位置。这些特殊情况有:addr==0表示相应的nid是没有用到的;ino==0也是不可能的,nid=0是文件系统保留的;nid==0的addr应该是0,不是0也是错误;node_inode和meta_inode对应的nid是f2fs文件系统为了元数据的page cache和node的page cache所设计的两个inode,在磁盘上实际是没有对应的inode与其对应的,其地址固化为0x1,如果不是,那就说明除了问题,进行置位。
void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
{
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
struct f2fs_journal *journal = &curseg->sum_blk->journal;
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct f2fs_nat_block *nat_block;
struct node_info ni;
u32 nid, nr_nat_blks;
pgoff_t block_off;
pgoff_t block_addr;
int seg_off;
int ret;
unsigned int i;
nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
ASSERT(nat_block);
nr_nat_blks = (get_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;
fsck->nat_area_bitmap = calloc(fsck->nat_area_bitmap_sz, 1);
ASSERT(fsck->nat_area_bitmap);
fsck->entries = calloc(sizeof(struct f2fs_nat_entry),fsck->nr_nat_entries);
ASSERT(fsck->entries);
for (block_off = 0; block_off < nr_nat_blks; block_off++) {
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);
nid = block_off * NAT_ENTRY_PER_BLOCK;
for (i = 0; i < NAT_ENTRY_PER_BLOCK; i++) {
ni.nid = nid + i;
if ((nid + i) == F2FS_NODE_INO(sbi) || (nid + i) == F2FS_META_INO(sbi)) {
if (le32_to_cpu(nat_block->entries[i].block_addr) != 0x1) {
ASSERT_MSG("\tError: ino[0x%x] block_addr[0x%x] is invalid\n",
nid + i, le32_to_cpu(nat_block->entries[i].block_addr));
f2fs_set_bit(nid + i, fsck->nat_area_bitmap);
}
continue;
}
node_info_from_raw_nat(&ni, &nat_block->entries[i]);
if (ni.blk_addr == 0x0)
continue;
if (ni.ino == 0x0) {
ASSERT_MSG("\tError: ino[0x%8x] or blk_addr[0x%16x]"
" is invalid\n", ni.ino, ni.blk_addr);
}
if (ni.ino == (nid + i)) {
fsck->nat_valid_inode_cnt++;
DBG(3, "ino[0x%8x] maybe is inode\n", ni.ino);
}
if (nid + i == 0) {
ASSERT_MSG("Invalid nat entry[0]: " "blk_addr[0x%x]\n", ni.blk_addr);
fsck->chk.valid_nat_entry_cnt--;
}
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++;
fsck->entries[nid + i] = nat_block->entries[i];
}
}
}
build_sit_area_bitmap主要是对f2fs_fsck中的sit_area_bitmap_sz、sit_area_bitmap和check_result中的 sit_valid_blocks、sit_free_segs的初始化。sit_area_bitmap_sz初始化为记录main area的blcok数目的bitmap所需要的字节数。然后分配sit_area_bitmap_sz个字节大小的空间给sit_area_bitmap,并且根据seg_entry中的位图一次赋值给sit_area_bitmap。在这个遍历的过程中也统计除current segment之外的有效块数和free的segment的数量。将check_result中的 sit_valid_blocks初始化为有效块数,将check_result中的sit_free_segs初始化为统计的除current segment之外的free的segment的数量。
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);
unsigned int segno = 0;
char *ptr = NULL;
u32 sum_vblocks = 0;
u32 free_segs = 0;
struct seg_entry *se;
fsck->sit_area_bitmap_sz = sm_i->main_segments * SIT_VBLOCK_MAP_SIZE;
fsck->sit_area_bitmap = calloc(1, fsck->sit_area_bitmap_sz);
ASSERT(fsck->sit_area_bitmap);
ptr = fsck->sit_area_bitmap;
ASSERT(fsck->sit_area_bitmap_sz == fsck->main_area_bitmap_sz);
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;
if (se->valid_blocks == 0x0) {
if (le32_to_cpu(sbi->ckpt->cur_node_segno[0]) == segno ||
le32_to_cpu(sbi->ckpt->cur_data_segno[0]) == segno ||
le32_to_cpu(sbi->ckpt->cur_node_segno[1]) == segno ||
le32_to_cpu(sbi->ckpt->cur_data_segno[1]) == segno ||
le32_to_cpu(sbi->ckpt->cur_node_segno[2]) == segno ||
le32_to_cpu(sbi->ckpt->cur_data_segno[2]) == segno) {
continue;
} else {
free_segs++;
}
} else {
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,
free_segs, free_segs);
}