f2fs系列文章fsck(三)
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);
}