fsck_chk_inode_blk接下来就是对一个文件进行处理了,内容比较丰富。首先对inode对应的地址在f2fs_fsck的main_area_bitmap中有没有置位,如果没有置位,也就是检查到了一个新的inode,将f2fs_fsck中的check_result的valid_inode_cnt++,这里需要检查的原因是,可能有硬链接这些在之前就已经将main_area_bitmap相应的位置位了。
if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0)
fsck->chk.valid_inode_cnt++;
接下来处理文件的硬链接问题。由于目录是没有硬链接的,所以检查该inode对应的文件类型时候不是目录F2FS_FT_DIR,如果是目录就直接将main_area_bitmap中相应的位置位,然后跳过硬链接的处理。如果不是目录就需要检查该inode所在的block地址在main_area_bitmap中有没有置位过,如果没有置位,那就是第一次检查这个inode,检查其i_links是否大于1,也就是这个inode存不存在其他的硬链接,满足就先通过函数add_into_hard_link_list其加入到f2fs_fsck管理的一个硬链接链表hard_link_list_head中。如果i_link不大于1,那就说明不存在硬链接,不用管了。如果置位过,那就说明,这是之前检查的inode的硬链接了。通过函数find_and_dec_hard_link_list在f2fs_fsck管理的一个硬链接链表hard_link_list_head中找到该inode对应的链表node,然后减少链表node中的链接数,当这个链接数达到1时,说明这个inode所有链接的地方全部处理完了,从链表里面删掉。但是如果出现意外,没有在硬链接的链表中找到对应的链表node,那就说明,实际的硬链接数超过了inode字段中的i_links,这个时候如果要修复那就需要将inode中的i_links++。所以正常情况下,这个链表在所有的inode检查完成之后是NULL,如果不为NULL,那就说明该链表node对应的inode的i_links字段多了,而其实际的链接数就记录在链表node的actual_links字段中,这个会在f2fs_verify中处理。
if (ftype == F2FS_FT_DIR) {
f2fs_set_main_bitmap(sbi, ni->blk_addr, CURSEG_HOT_NODE);
} else {
if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) {
f2fs_set_main_bitmap(sbi, ni->blk_addr, CURSEG_WARM_NODE);
if (i_links > 1 && ftype != F2FS_FT_ORPHAN && !is_qf_ino(F2FS_RAW_SUPER(sbi), nid)) {
add_into_hard_link_list(sbi, nid, i_links);
fsck->chk.multi_hard_link_files++;
}
} else {
DBG(3, "[0x%x] has hard links [0x%x]\n", nid, i_links);
if (find_and_dec_hard_link_list(sbi, nid)) {
ASSERT_MSG("[0x%x] needs more i_links=0x%x", nid, i_links);
if (c.fix_on) {
node_blk->i.i_links = cpu_to_le32(i_links + 1);
need_fix = 1;
FIX_MSG("File: 0x%x " "i_links= 0x%x -> 0x%x", nid, i_links, i_links + 1);
}
goto skip_blkcnt_fix;
}
return;
}
}
接下来是内联属性的问题,这个通过函数fsck_chk_xattr_blk完成。fsck_chk_xattr_blk首先检查i_xattr_nid字段==0看一下存不存在内联属性块,如果没有直接返回。如果i_xattr_nid!=0,那就说明存在内联属性的node。存在内联属性的node之后,先调用sanity_check_nid对nid进行基本的检查,然后需要将inode的i_blocks++;并将内联node所在的block地址在f2fs_fsck的main_area_bitmap置位。如果检查过程中出错的话,这时其nid在f2fs_fsck的nat_area_bitmap是没有clear的,这个留着f2fs_verify处理,这时在inode对应的i_xattr_nid赋值0,表示丢掉这个内联的node。
if (fsck_chk_xattr_blk(sbi, nid, le32_to_cpu(node_blk->i.i_xattr_nid), blk_cnt) && c.fix_on) {
node_blk->i.i_xattr_nid = 0;
need_fix = 1;
FIX_MSG("Remove xattr block: 0x%x, x_nid = 0x%x", nid, le32_to_cpu(node_blk->i.i_xattr_nid));
}
static int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino, u32 x_nid, u32 *blk_cnt)
{
struct f2fs_node *node_blk = NULL;
struct node_info ni;
int ret = 0;
if (x_nid == 0x0)
return 0;
node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
ASSERT(node_blk != NULL);
if (sanity_check_nid(sbi, x_nid, node_blk, F2FS_FT_XATTR, TYPE_XATTR, &ni)) {
ret = -EINVAL;
goto out;
}
*blk_cnt = *blk_cnt + 1;
f2fs_set_main_bitmap(sbi, ni.blk_addr, CURSEG_COLD_NODE);
DBG(2, "ino[0x%x] x_nid[0x%x]\n", ino, x_nid);
out:
free(node_blk);
return ret;
}
如果文件类型是F2FS_FT_CHRDEV、F2FS_FT_BLKDEV、F2FS_FT_FIFO、F2FS_FT_SOCK直接跨过数据的检查。
if (ftype == F2FS_FT_CHRDEV || ftype == F2FS_FT_BLKDEV || ftype == F2FS_FT_FIFO || ftype == F2FS_FT_SOCK)
goto check;
接下来是处理inode下的数据的问题了,数据的检查分为下面的三种情况:
第一种情况是内联数据F2FS_INLINE_DATA。首先检查i_addr的起始地址应该是0,不是就进行修复。另外就是如果没有设置F2FS_DATA_EXIST,但是在f2fs_inode的盛放内联数据的区域有数据(不是全是0的这种就行),那就加上F2FS_DATA_EXIST这个标志。
if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
if (le32_to_cpu(node_blk->i.i_addr[ofs]) != 0) {
FIX_MSG("inline_data has wrong 0'th block = %x", le32_to_cpu(node_blk->i.i_addr[ofs]));
node_blk->i.i_addr[ofs] = 0;
node_blk->i.i_blocks = cpu_to_le64(*blk_cnt);
need_fix = 1;
}
if (!(node_blk->i.i_inline & F2FS_DATA_EXIST)) {
char buf[MAX_INLINE_DATA(node_blk)];
memset(buf, 0, MAX_INLINE_DATA(node_blk));
if (memcmp(buf, inline_data_addr(node_blk), MAX_INLINE_DATA(node_blk))) {
FIX_MSG("inline_data has DATA_EXIST");
node_blk->i.i_inline |= F2FS_DATA_EXIST;
need_fix = 1;
}
}
DBG(3, "ino[0x%x] has inline data!\n", nid);
goto check;
}
第二种情况是内联目录项F2FS_INLINE_DENTRY。首先检查i_addr的起始地址应该是0,不是就进行修复。然后调用fsck_chk_inline_dentries对内联目录项进行检查。
if ((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) {
DBG(3, "ino[0x%x] has inline dentry!\n", nid);
if (le32_to_cpu(node_blk->i.i_addr[ofs]) != 0) {
FIX_MSG("inline_dentry has wrong 0'th block = %x", le32_to_cpu(node_blk->i.i_addr[ofs]));
node_blk->i.i_addr[ofs] = 0;
node_blk->i.i_blocks = cpu_to_le64(*blk_cnt);
need_fix = 1;
}
ret = fsck_chk_inline_dentries(sbi, node_blk, &child);
if (ret < 0) {
need_fix = 1;
}
goto check;
}
fsck_chk_inline_dentries,首先计算好内联目录项区域中的bitmap、dentry数组起始指针、文件名filename、数组最大个数max,调用__chk_dentries对这个数组中的目录项进行下一步的检查。
int fsck_chk_inline_dentries(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk, struct child_info *child)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_dentry_ptr d;
void *inline_dentry;
int dentries;
inline_dentry = inline_data_addr(node_blk);
ASSERT(inline_dentry != NULL);
make_dentry_ptr(&d, node_blk, inline_dentry, 2);
fsck->dentry_depth++;
dentries = __chk_dentries(sbi, child,d.bitmap, d.dentry, d.filename, d.max, 1, file_is_encrypt(&node_blk->i));
if (dentries < 0) {
DBG(1, "[%3d] Inline Dentry Block Fixed hash_codes\n\n", fsck->dentry_depth);
} else {
DBG(1, "[%3d] Inline Dentry Block Done : " "dentries:%d in %d slots (len:%d)\n\n",
fsck->dentry_depth, dentries, d.max, F2FS_NAME_LEN);
}
fsck->dentry_depth--;
return dentries;
}
__chk_dentries,首先遍历dentry数组,根据bitmap找到有效的目录项,然后对目录项的ino进行有效性检查,对ino所在的块地址进行有效性检查,然后对这些inode进行预读。
for (i = 0; i < max; i++) {
u32 ino;
if (test_bit_le(i, bitmap) == 0)
continue;
ino = le32_to_cpu(dentry[i].ino);
if (IS_VALID_NID(sbi, ino)) {
struct node_info ni;
get_node_info(sbi, ino, &ni);
if (IS_VALID_BLK_ADDR(sbi, ni.blk_addr)) {
dev_reada_block(ni.blk_addr);
name_len = le16_to_cpu(dentry[i].name_len);
if (name_len > 0)
i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN - 1;
}
}
}
上一步基本没有完成任何的检查,只是完成一个预读。接下来进行真正的检查,在此遍历一下dentry数组,如果dentry对应的bit无效,没直接跨过,如果有效就进行接下来的动作。首先检查ino的有效性,如果无效,则将bitmap中相应的bit清位,如果有效进入下一步。
if (test_bit_le(i, bitmap) == 0) {
i++;
continue;
}
if (!IS_VALID_NID(sbi, le32_to_cpu(dentry[i].ino))) {
ASSERT_MSG("Bad dentry 0x%x with invalid NID/ino 0x%x", i, le32_to_cpu(dentry[i].ino));
if (c.fix_on) {
FIX_MSG("Clear bad dentry 0x%x with bad ino 0x%x", i, le32_to_cpu(dentry[i].ino));
test_and_clear_bit_le(i, bitmap);
fixed = 1;
}
i++;
continue;
}
检查目录项的文件类型,只允许是宏定义的几种,不在此范围之内的就将bitmap中相应的bit清位,没有错误就下一步。接下来是目录项名称长度的检查,(0, F2FS_NAME_LEN)是其允许范围,不在此范围之内的就将bitmap中相应的bit清位,没有错误就下一步。
ftype = dentry[i].file_type;
if ((ftype <= F2FS_FT_UNKNOWN || ftype > F2FS_FT_LAST_FILE_TYPE)) {
ASSERT_MSG("Bad dentry 0x%x with unexpected ftype 0x%x", le32_to_cpu(dentry[i].ino), ftype);
if (c.fix_on) {
FIX_MSG("Clear bad dentry 0x%x with bad ftype 0x%x", i, ftype);
test_and_clear_bit_le(i, bitmap);
fixed = 1;
}
i++;
continue;
}
name_len = le16_to_cpu(dentry[i].name_len);
if (name_len == 0 || name_len > F2FS_NAME_LEN) {
ASSERT_MSG("Bad dentry 0x%x with invalid name_len", i);
if (c.fix_on) {
FIX_MSG("Clear bad dentry 0x%x", i);
test_and_clear_bit_le(i, bitmap);
fixed = 1;
}
i++;
continue;
}
接下来是关于两个目录./和../两个目录的检查,这个功能是通过__chk_dots_dentries函数完成的,__chk_dots_dentries会对比这两个目录的ino必须是当前目录或者是父目录的ino,另外还要进行hash code的检查,最后目录名的最后一个字符必须是‘\0’。如果有超过两个满足这种目录条件的,那就调用函数nullify_dentry清掉bitmap中的位和清空dentry和名称。将这种目录的个数记录在dots中,后续要进行置位处理,这里作废掉的不算数,所以dots最大是2。
if (ftype == F2FS_FT_DIR) {
if ((name[0] == '.' && name_len == 1) || (name[0] == '.' && name[1] == '.' && name_len == 2)) {
ret = __chk_dots_dentries(sbi, &dentry[i], child, name, name_len, &filenames[i], enc_name);
switch (ret) {
case 1:
fixed = 1;
case 0:
child->dots++;
break;
}
if (child->dots > 2) {
ASSERT_MSG("More than one '.' or '..', should delete the extra one\n");
nullify_dentry(&dentry[i], i, &filenames[i], &bitmap);
child->dots--;
fixed = 1;
}
i++;
free(name);
continue;
}
}
接下来是关于hash code的检查。然后由于f2fs的目录项的放置规则,所以当前检查的f2fs_dentry_block的pgofs应该根据hash code放置在正确的桶中的正确的block中,这个是通过函数f2fs_check_dirent_position来完成的,如果不对也要对相应的目录项进行清位处理。接下来对目录信息进行输出(名称有解密加密处理)。对单个的目录项就此完成了,然后通过fsck_chk_node_blk递归对目录项的ino进行同样的处理。如果检查出错,那就对相应的目录项进行清位。至此,目录项的检查完成。不管是内联还是不内联的最终都是通过这个函数来完成目录项的检查。
if (f2fs_check_hash_code(dentry + i, name, name_len, enc_name))
fixed = 1;
if (max == NR_DENTRY_IN_BLOCK) {
ret = f2fs_check_dirent_position(name, name_len, child->pgofs, child->dir_level, child->p_ino);
if (ret) {
if (c.fix_on) {
FIX_MSG("Clear bad dentry 0x%x", i);
test_and_clear_bit_le(i, bitmap);
fixed = 1;
}
i++;
free(name);
continue;
}
}
en_len = convert_encrypted_name(name, name_len, en, enc_name);
en[en_len] = '\0';
DBG(1, "[%3u]-[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n", fsck->dentry_depth, i, en, name_len,
le32_to_cpu(dentry[i].ino), dentry[i].file_type);
print_dentry(fsck->dentry_depth, name, bitmap, dentry, max, i, last_blk, enc_name);
blk_cnt = 1;
child->i_namelen = name_len;
ret = fsck_chk_node_blk(sbi, NULL, le32_to_cpu(dentry[i].ino), ftype, TYPE_INODE, &blk_cnt, child);
if (ret && c.fix_on) {
int j;
for (j = 0; j < slots; j++)
test_and_clear_bit_le(i + j, bitmap);
FIX_MSG("Unlink [0x%x] - %s len[0x%x], type[0x%x]", le32_to_cpu(dentry[i].ino),
en, name_len, dentry[i].file_type);
fixed = 1;
} else if (ret == 0) {
if (ftype == F2FS_FT_DIR)
child->links++;
dentries++;
child->files++;
}
第三种情况是正常的索引数据(这里面包含目录项)。这种情况下,首先得到inode中的direct node、indirectnode、dindirect node的nid,如果nid!=0且有效,那么就对相应的node进行预读。然后是真正的对文件的node和data block进行检查,在这个过程中会对inode的extent进行一个核查,仅仅在基于inode中的extent进行一个检查,不符合就直接作废掉就行了。首先是923个块地址的检查,如果!=0,那就调用fsck_chk_data_blk对数据块进行检查,返回成功就将i_block++;错误就将该地址置为0。然后是后五个node了,调用fsck_chk_node_blk对其进行检查,返回成功就将i_block++;错误就将该nid置为0。
for (idx = 0; idx < 5; idx++) {
u32 nid = le32_to_cpu(node_blk->i.i_nid[idx]);
if (nid != 0 && IS_VALID_NID(sbi, nid)) {
struct node_info ni;
get_node_info(sbi, nid, &ni);
if (IS_VALID_BLK_ADDR(sbi, ni.blk_addr))
dev_reada_block(ni.blk_addr);
}
}
get_extent_info(&child.ei, &node_blk->i.i_ext);
child.last_blk = 0;
for (idx = 0; idx < ADDRS_PER_INODE(&node_blk->i); idx++, child.pgofs++) {
block_t blkaddr = le32_to_cpu(node_blk->i.i_addr[ofs + idx]);
check_extent_info(&child, blkaddr, 0);
if (blkaddr != 0) {
ret = fsck_chk_data_blk(sbi, blkaddr, &child, (i_blocks == *blk_cnt),
ftype, nid, idx, ni->version, file_is_encrypt(&node_blk->i));
if (!ret) {
*blk_cnt = *blk_cnt + 1;
} else if (c.fix_on) {
node_blk->i.i_addr[ofs + idx] = 0;
need_fix = 1;
FIX_MSG("[0x%x] i_addr[%d] = 0", nid, ofs + idx);
}
}
}
for (idx = 0; idx < 5; idx++) {
nid_t i_nid = le32_to_cpu(node_blk->i.i_nid[idx]);
if (idx == 0 || idx == 1)
ntype = TYPE_DIRECT_NODE;
else if (idx == 2 || idx == 3)
ntype = TYPE_INDIRECT_NODE;
else if (idx == 4)
ntype = TYPE_DOUBLE_INDIRECT_NODE;
else
ASSERT(0);
if (i_nid == 0x0)
goto skip;
ret = fsck_chk_node_blk(sbi, &node_blk->i, i_nid, ftype, ntype, blk_cnt, &child);
if (!ret) {
*blk_cnt = *blk_cnt + 1;
} else if (ret == -EINVAL) {
if (c.fix_on) {
node_blk->i.i_nid[idx] = 0;
need_fix = 1;
FIX_MSG("[0x%x] i_nid[%d] = 0", nid, idx);
}
skip:
if (ntype == TYPE_DIRECT_NODE)
child.pgofs += ADDRS_PER_BLOCK;
else if (ntype == TYPE_INDIRECT_NODE)
child.pgofs += ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
else
child.pgofs += ADDRS_PER_BLOCK * NIDS_PER_BLOCK * NIDS_PER_BLOCK;
}
}
check_extent_info(&child, 0, 1);
if (child.state & FSCK_UNMATCHED_EXTENT) {
ASSERT_MSG("ino: 0x%x has wrong ext: [pgofs:%u, blk:%u, len:%u]",
nid, child.ei.fofs, child.ei.blk, child.ei.len);
if (c.fix_on)
need_fix = 1;
}
fsck_chk_data_blk完成数据块的核对检查。首先如果块地址是NEW_ADDR,直接将f2fs_fsck中的check_result的valid_blk_cnt++就直接返回。然后检查块地址的有效性,不要超过mian area的范围。然后通过函数is_valid_ssa_data_blk来完成summary和nat的前后一致性,还有就是summary和seg_entry的类型的一致性。sit_bitmap中的该块地址应该置位了,main_area_bitmap应该是没有置位的。否则打印信息。如果是目录项的数据块,现将该块地址在main_area_bitmap中置位,然后调用fsck_chk_dentry_blk来进行目录项的检查,这个在之前讲过,这里不重复讲了。不是目录就直接在main_area_bitmap中置位就可以返回了。
int fsck_chk_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr, struct child_info *child, int last_blk,
enum FILE_TYPE ftype, u32 parent_nid, u16 idx_in_node, u8 ver, int enc_name)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
if (blk_addr == NEW_ADDR) {
fsck->chk.valid_blk_cnt++;
return 0;
}
if (!IS_VALID_BLK_ADDR(sbi, blk_addr)) {
ASSERT_MSG("blkaddress is not valid. [0x%x]", blk_addr);
return -EINVAL;
}
if (is_valid_ssa_data_blk(sbi, blk_addr, parent_nid, idx_in_node, ver)) {
ASSERT_MSG("summary data block is not valid. [0x%x]", parent_nid);
return -EINVAL;
}
if (f2fs_test_sit_bitmap(sbi, blk_addr) == 0)
ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]", blk_addr);
if (f2fs_test_main_bitmap(sbi, blk_addr) != 0)
ASSERT_MSG("Duplicated data [0x%x]. pnid[0x%x] idx[0x%x]",
blk_addr, parent_nid, idx_in_node);
fsck->chk.valid_blk_cnt++;
if (ftype == F2FS_FT_DIR) {
f2fs_set_main_bitmap(sbi, blk_addr, CURSEG_HOT_DATA);
return fsck_chk_dentry_blk(sbi, blk_addr, child, last_blk, enc_name);
} else {
f2fs_set_main_bitmap(sbi, blk_addr, CURSEG_WARM_DATA);
}
return 0;
}
以上就是关于文件的数据的检查的三种情况,至此文件数据检查完成了,所有的文件的类型回到一致的检查点上。接下来是关于i_block的检查,这个字段记录了文件的node和data block所有的block数量,它应该与child的blk_cnt是一致的,如果不一致就对i_block进行修改。然后是对于inode中的文件长度i_namelen进行检查,如果大于文件的最大可能长度F2FS_NAME_LEN,那就修改至与目录项中的文件长度相同。然后打印F2FS_FT_ORPHAN和quota inode的信息。接着是对于目录F2FS_FT_DIR,检查一下i_link,child中记录着该目录的链接数(但是初始化为2有些疑问),还有就是如果child中的dots没有达到两个,说明没有完成的./和../两个目录,这个时候应该讲文件设置F2FS_INLINE_DOTS。对于软链接文件F2FS_FT_SYMLINK,size可能需要修正,orphan inode的链接数也必须修正为0。如果在检查过程中修复过,那么僵inode的i_ext的长度设置为0,删掉这个extent。然后是关于文件的i_inode_checksum的检查。最后,如果inode修复过的inode写回。
if (i_blocks != *blk_cnt) {
ASSERT_MSG("ino: 0x%x has i_blocks: %08"PRIx64", " "but has %u blocks", nid, i_blocks, *blk_cnt);
if (c.fix_on) {
node_blk->i.i_blocks = cpu_to_le64(*blk_cnt);
need_fix = 1;
FIX_MSG("[0x%x] i_blocks=0x%08"PRIx64" -> 0x%x", nid, i_blocks, *blk_cnt);
}
}
skip_blkcnt_fix:
en = malloc(F2FS_NAME_LEN + 1);
ASSERT(en);
namelen = le32_to_cpu(node_blk->i.i_namelen);
if (namelen > F2FS_NAME_LEN) {
if (child_d && child_d->i_namelen <= F2FS_NAME_LEN) {
ASSERT_MSG("ino: 0x%x has i_namelen: 0x%x, " "but has %d characters for name",
nid, namelen, child_d->i_namelen);
if (c.fix_on) {
FIX_MSG("[0x%x] i_namelen=0x%x -> 0x%x", nid, namelen, child_d->i_namelen);
node_blk->i.i_namelen = cpu_to_le32(child_d->i_namelen);
need_fix = 1;
}
namelen = child_d->i_namelen;
} else
namelen = F2FS_NAME_LEN;
}
namelen = convert_encrypted_name(node_blk->i.i_name, namelen, en, file_enc_name(&node_blk->i));
en[namelen] = '\0';
if (ftype == F2FS_FT_ORPHAN)
DBG(1, "Orphan Inode: 0x%x [%s] i_blocks: %u\n\n", le32_to_cpu(node_blk->footer.ino), en, (u32)i_blocks);
if (is_qf_ino(F2FS_RAW_SUPER(sbi), nid))
DBG(1, "Quota Inode: 0x%x [%s] i_blocks: %u\n\n", le32_to_cpu(node_blk->footer.ino),en, (u32)i_blocks);
if (ftype == F2FS_FT_DIR) {
DBG(1, "Directory Inode: 0x%x [%s] depth: %d has %d files\n\n", le32_to_cpu(node_blk->footer.ino), en,
le32_to_cpu(node_blk->i.i_current_depth), child.files);
if (i_links != child.links) {
ASSERT_MSG("ino: 0x%x i_links: %u, real links: %u", nid, i_links, child.links);
if (c.fix_on) {
node_blk->i.i_links = cpu_to_le32(child.links);
need_fix = 1;
FIX_MSG("Dir: 0x%x i_links= 0x%x -> 0x%x", nid, i_links, child.links);
}
}
if (child.dots < 2 && !(node_blk->i.i_inline & F2FS_INLINE_DOTS)) {
ASSERT_MSG("ino: 0x%x dots: %u", nid, child.dots);
if (c.fix_on) {
node_blk->i.i_inline |= F2FS_INLINE_DOTS;
need_fix = 1;
FIX_MSG("Dir: 0x%x set inline_dots", nid);
}
}
}
free(en);
if (ftype == F2FS_FT_SYMLINK && i_blocks && i_size == 0) {
DBG(1, "ino: 0x%x i_blocks: %lu with zero i_size", nid, (unsigned long)i_blocks);
if (c.fix_on) {
u64 i_size = i_blocks * F2FS_BLKSIZE;
node_blk->i.i_size = cpu_to_le64(i_size);
need_fix = 1;
FIX_MSG("Symlink: recover 0x%x with i_size=%lu", nid, (unsigned long)i_size);
}
}
if (ftype == F2FS_FT_ORPHAN && i_links) {
MSG(0, "ino: 0x%x is orphan inode, but has i_links: %u", nid, i_links);
if (c.fix_on) {
node_blk->i.i_links = 0;
need_fix = 1;
FIX_MSG("ino: 0x%x orphan_inode, i_links= 0x%x -> 0", nid, i_links);
}
}
if (need_fix && !c.ro)
node_blk->i.i_ext.len = 0;
if ((c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM)) && f2fs_has_extra_isize(&node_blk->i)) {
__u32 provided, calculated;
provided = le32_to_cpu(node_blk->i.i_inode_checksum);
calculated = f2fs_inode_chksum(node_blk);
if (provided != calculated) {
ASSERT_MSG("ino: 0x%x chksum:0x%x, but calculated one is: 0x%x", nid, provided, calculated);
if (c.fix_on) {
node_blk->i.i_inode_checksum = cpu_to_le32(calculated);
need_fix = 1;
FIX_MSG("ino: 0x%x recover, i_inode_checksum= 0x%x -> 0x%x", nid, provided, calculated);
}
}
}
if (need_fix && !c.ro) {
ret = dev_write_block(node_blk, ni->blk_addr);
ASSERT(ret >= 0);
}