15e5c12b0Sopenharmony_ci/** 25e5c12b0Sopenharmony_ci * fsck.c 35e5c12b0Sopenharmony_ci * 45e5c12b0Sopenharmony_ci * Copyright (c) 2013 Samsung Electronics Co., Ltd. 55e5c12b0Sopenharmony_ci * http://www.samsung.com/ 65e5c12b0Sopenharmony_ci * 75e5c12b0Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 85e5c12b0Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 95e5c12b0Sopenharmony_ci * published by the Free Software Foundation. 105e5c12b0Sopenharmony_ci */ 115e5c12b0Sopenharmony_ci#include "fsck.h" 125e5c12b0Sopenharmony_ci#include "xattr.h" 135e5c12b0Sopenharmony_ci#include "quotaio.h" 145e5c12b0Sopenharmony_ci#include <time.h> 155e5c12b0Sopenharmony_ci 165e5c12b0Sopenharmony_cichar *tree_mark; 175e5c12b0Sopenharmony_ciuint32_t tree_mark_size = 256; 185e5c12b0Sopenharmony_ci 195e5c12b0Sopenharmony_ciint f2fs_set_main_bitmap(struct f2fs_sb_info *sbi, u32 blk, int type) 205e5c12b0Sopenharmony_ci{ 215e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 225e5c12b0Sopenharmony_ci struct seg_entry *se; 235e5c12b0Sopenharmony_ci int fix = 0; 245e5c12b0Sopenharmony_ci 255e5c12b0Sopenharmony_ci se = get_seg_entry(sbi, GET_SEGNO(sbi, blk)); 265e5c12b0Sopenharmony_ci if (se->type >= NO_CHECK_TYPE) 275e5c12b0Sopenharmony_ci fix = 1; 285e5c12b0Sopenharmony_ci else if (IS_DATASEG(se->type) != IS_DATASEG(type)) 295e5c12b0Sopenharmony_ci fix = 1; 305e5c12b0Sopenharmony_ci 315e5c12b0Sopenharmony_ci /* just check data and node types */ 325e5c12b0Sopenharmony_ci if (fix) { 335e5c12b0Sopenharmony_ci DBG(1, "Wrong segment type [0x%x] %x -> %x", 345e5c12b0Sopenharmony_ci GET_SEGNO(sbi, blk), se->type, type); 355e5c12b0Sopenharmony_ci se->type = type; 365e5c12b0Sopenharmony_ci } 375e5c12b0Sopenharmony_ci return f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->main_area_bitmap); 385e5c12b0Sopenharmony_ci} 395e5c12b0Sopenharmony_ci 405e5c12b0Sopenharmony_cistatic inline int f2fs_test_main_bitmap(struct f2fs_sb_info *sbi, u32 blk) 415e5c12b0Sopenharmony_ci{ 425e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 435e5c12b0Sopenharmony_ci 445e5c12b0Sopenharmony_ci return f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk), 455e5c12b0Sopenharmony_ci fsck->main_area_bitmap); 465e5c12b0Sopenharmony_ci} 475e5c12b0Sopenharmony_ci 485e5c12b0Sopenharmony_cistatic inline int f2fs_clear_main_bitmap(struct f2fs_sb_info *sbi, u32 blk) 495e5c12b0Sopenharmony_ci{ 505e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 515e5c12b0Sopenharmony_ci 525e5c12b0Sopenharmony_ci return f2fs_clear_bit(BLKOFF_FROM_MAIN(sbi, blk), 535e5c12b0Sopenharmony_ci fsck->main_area_bitmap); 545e5c12b0Sopenharmony_ci} 555e5c12b0Sopenharmony_ci 565e5c12b0Sopenharmony_cistatic inline int f2fs_test_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk) 575e5c12b0Sopenharmony_ci{ 585e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 595e5c12b0Sopenharmony_ci 605e5c12b0Sopenharmony_ci return f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->sit_area_bitmap); 615e5c12b0Sopenharmony_ci} 625e5c12b0Sopenharmony_ci 635e5c12b0Sopenharmony_ciint f2fs_set_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk) 645e5c12b0Sopenharmony_ci{ 655e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 665e5c12b0Sopenharmony_ci 675e5c12b0Sopenharmony_ci return f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->sit_area_bitmap); 685e5c12b0Sopenharmony_ci} 695e5c12b0Sopenharmony_ci 705e5c12b0Sopenharmony_cistatic int add_into_hard_link_list(struct f2fs_sb_info *sbi, 715e5c12b0Sopenharmony_ci u32 nid, u32 link_cnt) 725e5c12b0Sopenharmony_ci{ 735e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 745e5c12b0Sopenharmony_ci struct hard_link_node *node = NULL, *tmp = NULL, *prev = NULL; 755e5c12b0Sopenharmony_ci 765e5c12b0Sopenharmony_ci node = calloc(sizeof(struct hard_link_node), 1); 775e5c12b0Sopenharmony_ci ASSERT(node != NULL); 785e5c12b0Sopenharmony_ci 795e5c12b0Sopenharmony_ci node->nid = nid; 805e5c12b0Sopenharmony_ci node->links = link_cnt; 815e5c12b0Sopenharmony_ci node->actual_links = 1; 825e5c12b0Sopenharmony_ci node->next = NULL; 835e5c12b0Sopenharmony_ci 845e5c12b0Sopenharmony_ci if (fsck->hard_link_list_head == NULL) { 855e5c12b0Sopenharmony_ci fsck->hard_link_list_head = node; 865e5c12b0Sopenharmony_ci goto out; 875e5c12b0Sopenharmony_ci } 885e5c12b0Sopenharmony_ci 895e5c12b0Sopenharmony_ci tmp = fsck->hard_link_list_head; 905e5c12b0Sopenharmony_ci 915e5c12b0Sopenharmony_ci /* Find insertion position */ 925e5c12b0Sopenharmony_ci while (tmp && (nid < tmp->nid)) { 935e5c12b0Sopenharmony_ci ASSERT(tmp->nid != nid); 945e5c12b0Sopenharmony_ci prev = tmp; 955e5c12b0Sopenharmony_ci tmp = tmp->next; 965e5c12b0Sopenharmony_ci } 975e5c12b0Sopenharmony_ci 985e5c12b0Sopenharmony_ci if (tmp == fsck->hard_link_list_head) { 995e5c12b0Sopenharmony_ci node->next = tmp; 1005e5c12b0Sopenharmony_ci fsck->hard_link_list_head = node; 1015e5c12b0Sopenharmony_ci } else { 1025e5c12b0Sopenharmony_ci prev->next = node; 1035e5c12b0Sopenharmony_ci node->next = tmp; 1045e5c12b0Sopenharmony_ci } 1055e5c12b0Sopenharmony_ci 1065e5c12b0Sopenharmony_ciout: 1075e5c12b0Sopenharmony_ci DBG(2, "ino[0x%x] has hard links [0x%x]\n", nid, link_cnt); 1085e5c12b0Sopenharmony_ci return 0; 1095e5c12b0Sopenharmony_ci} 1105e5c12b0Sopenharmony_ci 1115e5c12b0Sopenharmony_cistatic int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid) 1125e5c12b0Sopenharmony_ci{ 1135e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 1145e5c12b0Sopenharmony_ci struct hard_link_node *node = NULL, *prev = NULL; 1155e5c12b0Sopenharmony_ci 1165e5c12b0Sopenharmony_ci if (fsck->hard_link_list_head == NULL) 1175e5c12b0Sopenharmony_ci return -EINVAL; 1185e5c12b0Sopenharmony_ci 1195e5c12b0Sopenharmony_ci node = fsck->hard_link_list_head; 1205e5c12b0Sopenharmony_ci 1215e5c12b0Sopenharmony_ci while (node && (nid < node->nid)) { 1225e5c12b0Sopenharmony_ci prev = node; 1235e5c12b0Sopenharmony_ci node = node->next; 1245e5c12b0Sopenharmony_ci } 1255e5c12b0Sopenharmony_ci 1265e5c12b0Sopenharmony_ci if (node == NULL || (nid != node->nid)) 1275e5c12b0Sopenharmony_ci return -EINVAL; 1285e5c12b0Sopenharmony_ci 1295e5c12b0Sopenharmony_ci /* Decrease link count */ 1305e5c12b0Sopenharmony_ci node->links = node->links - 1; 1315e5c12b0Sopenharmony_ci node->actual_links++; 1325e5c12b0Sopenharmony_ci 1335e5c12b0Sopenharmony_ci /* if link count becomes one, remove the node */ 1345e5c12b0Sopenharmony_ci if (node->links == 1) { 1355e5c12b0Sopenharmony_ci if (fsck->hard_link_list_head == node) 1365e5c12b0Sopenharmony_ci fsck->hard_link_list_head = node->next; 1375e5c12b0Sopenharmony_ci else 1385e5c12b0Sopenharmony_ci prev->next = node->next; 1395e5c12b0Sopenharmony_ci free(node); 1405e5c12b0Sopenharmony_ci } 1415e5c12b0Sopenharmony_ci return 0; 1425e5c12b0Sopenharmony_ci} 1435e5c12b0Sopenharmony_ci 1445e5c12b0Sopenharmony_cistatic int is_valid_ssa_node_blk(struct f2fs_sb_info *sbi, u32 nid, 1455e5c12b0Sopenharmony_ci u32 blk_addr) 1465e5c12b0Sopenharmony_ci{ 1475e5c12b0Sopenharmony_ci struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 1485e5c12b0Sopenharmony_ci struct f2fs_summary_block *sum_blk; 1495e5c12b0Sopenharmony_ci struct f2fs_summary *sum_entry; 1505e5c12b0Sopenharmony_ci struct seg_entry * se; 1515e5c12b0Sopenharmony_ci u32 segno, offset; 1525e5c12b0Sopenharmony_ci int need_fix = 0, ret = 0; 1535e5c12b0Sopenharmony_ci int type; 1545e5c12b0Sopenharmony_ci 1555e5c12b0Sopenharmony_ci if (get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) 1565e5c12b0Sopenharmony_ci return 0; 1575e5c12b0Sopenharmony_ci 1585e5c12b0Sopenharmony_ci segno = GET_SEGNO(sbi, blk_addr); 1595e5c12b0Sopenharmony_ci offset = OFFSET_IN_SEG(sbi, blk_addr); 1605e5c12b0Sopenharmony_ci 1615e5c12b0Sopenharmony_ci sum_blk = get_sum_block(sbi, segno, &type); 1625e5c12b0Sopenharmony_ci 1635e5c12b0Sopenharmony_ci if (type != SEG_TYPE_NODE && type != SEG_TYPE_CUR_NODE) { 1645e5c12b0Sopenharmony_ci /* can't fix current summary, then drop the block */ 1655e5c12b0Sopenharmony_ci if (!c.fix_on || type < 0) { 1665e5c12b0Sopenharmony_ci ASSERT_MSG("Summary footer is not for node segment"); 1675e5c12b0Sopenharmony_ci ret = -EINVAL; 1685e5c12b0Sopenharmony_ci goto out; 1695e5c12b0Sopenharmony_ci } 1705e5c12b0Sopenharmony_ci 1715e5c12b0Sopenharmony_ci need_fix = 1; 1725e5c12b0Sopenharmony_ci se = get_seg_entry(sbi, segno); 1735e5c12b0Sopenharmony_ci if(IS_NODESEG(se->type)) { 1745e5c12b0Sopenharmony_ci FIX_MSG("Summary footer indicates a node segment: 0x%x", segno); 1755e5c12b0Sopenharmony_ci sum_blk->footer.entry_type = SUM_TYPE_NODE; 1765e5c12b0Sopenharmony_ci } else { 1775e5c12b0Sopenharmony_ci ret = -EINVAL; 1785e5c12b0Sopenharmony_ci goto out; 1795e5c12b0Sopenharmony_ci } 1805e5c12b0Sopenharmony_ci } 1815e5c12b0Sopenharmony_ci 1825e5c12b0Sopenharmony_ci sum_entry = &(sum_blk->entries[offset]); 1835e5c12b0Sopenharmony_ci 1845e5c12b0Sopenharmony_ci if (le32_to_cpu(sum_entry->nid) != nid) { 1855e5c12b0Sopenharmony_ci if (!c.fix_on || type < 0) { 1865e5c12b0Sopenharmony_ci DBG(0, "nid [0x%x]\n", nid); 1875e5c12b0Sopenharmony_ci DBG(0, "target blk_addr [0x%x]\n", blk_addr); 1885e5c12b0Sopenharmony_ci DBG(0, "summary blk_addr [0x%x]\n", 1895e5c12b0Sopenharmony_ci GET_SUM_BLKADDR(sbi, 1905e5c12b0Sopenharmony_ci GET_SEGNO(sbi, blk_addr))); 1915e5c12b0Sopenharmony_ci DBG(0, "seg no / offset [0x%x / 0x%x]\n", 1925e5c12b0Sopenharmony_ci GET_SEGNO(sbi, blk_addr), 1935e5c12b0Sopenharmony_ci OFFSET_IN_SEG(sbi, blk_addr)); 1945e5c12b0Sopenharmony_ci DBG(0, "summary_entry.nid [0x%x]\n", 1955e5c12b0Sopenharmony_ci le32_to_cpu(sum_entry->nid)); 1965e5c12b0Sopenharmony_ci DBG(0, "--> node block's nid [0x%x]\n", nid); 1975e5c12b0Sopenharmony_ci ASSERT_MSG("Invalid node seg summary\n"); 1985e5c12b0Sopenharmony_ci ret = -EINVAL; 1995e5c12b0Sopenharmony_ci } else { 2005e5c12b0Sopenharmony_ci FIX_MSG("Set node summary 0x%x -> [0x%x] [0x%x]", 2015e5c12b0Sopenharmony_ci segno, nid, blk_addr); 2025e5c12b0Sopenharmony_ci sum_entry->nid = cpu_to_le32(nid); 2035e5c12b0Sopenharmony_ci need_fix = 1; 2045e5c12b0Sopenharmony_ci } 2055e5c12b0Sopenharmony_ci } 2065e5c12b0Sopenharmony_ci if (need_fix && f2fs_dev_is_writable()) { 2075e5c12b0Sopenharmony_ci u64 ssa_blk; 2085e5c12b0Sopenharmony_ci int ret2; 2095e5c12b0Sopenharmony_ci 2105e5c12b0Sopenharmony_ci ssa_blk = GET_SUM_BLKADDR(sbi, segno); 2115e5c12b0Sopenharmony_ci ret2 = dev_write_block(sum_blk, ssa_blk); 2125e5c12b0Sopenharmony_ci ASSERT(ret2 >= 0); 2135e5c12b0Sopenharmony_ci } 2145e5c12b0Sopenharmony_ciout: 2155e5c12b0Sopenharmony_ci if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || 2165e5c12b0Sopenharmony_ci type == SEG_TYPE_MAX) 2175e5c12b0Sopenharmony_ci free(sum_blk); 2185e5c12b0Sopenharmony_ci return ret; 2195e5c12b0Sopenharmony_ci} 2205e5c12b0Sopenharmony_ci 2215e5c12b0Sopenharmony_cistatic int is_valid_summary(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, 2225e5c12b0Sopenharmony_ci u32 blk_addr) 2235e5c12b0Sopenharmony_ci{ 2245e5c12b0Sopenharmony_ci u16 ofs_in_node = le16_to_cpu(sum->ofs_in_node); 2255e5c12b0Sopenharmony_ci u32 nid = le32_to_cpu(sum->nid); 2265e5c12b0Sopenharmony_ci struct f2fs_node *node_blk = NULL; 2275e5c12b0Sopenharmony_ci __le32 target_blk_addr; 2285e5c12b0Sopenharmony_ci struct node_info ni; 2295e5c12b0Sopenharmony_ci int ret = 0; 2305e5c12b0Sopenharmony_ci 2315e5c12b0Sopenharmony_ci node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1); 2325e5c12b0Sopenharmony_ci ASSERT(node_blk != NULL); 2335e5c12b0Sopenharmony_ci 2345e5c12b0Sopenharmony_ci if (!IS_VALID_NID(sbi, nid)) 2355e5c12b0Sopenharmony_ci goto out; 2365e5c12b0Sopenharmony_ci 2375e5c12b0Sopenharmony_ci get_node_info(sbi, nid, &ni); 2385e5c12b0Sopenharmony_ci 2395e5c12b0Sopenharmony_ci if (!IS_VALID_BLK_ADDR(sbi, ni.blk_addr)) 2405e5c12b0Sopenharmony_ci goto out; 2415e5c12b0Sopenharmony_ci 2425e5c12b0Sopenharmony_ci /* read node_block */ 2435e5c12b0Sopenharmony_ci ret = dev_read_block(node_blk, ni.blk_addr); 2445e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 2455e5c12b0Sopenharmony_ci 2465e5c12b0Sopenharmony_ci if (le32_to_cpu(node_blk->footer.nid) != nid) 2475e5c12b0Sopenharmony_ci goto out; 2485e5c12b0Sopenharmony_ci 2495e5c12b0Sopenharmony_ci /* check its block address */ 2505e5c12b0Sopenharmony_ci if (node_blk->footer.nid == node_blk->footer.ino) { 2515e5c12b0Sopenharmony_ci int ofs = get_extra_isize(node_blk); 2525e5c12b0Sopenharmony_ci 2535e5c12b0Sopenharmony_ci if (ofs + ofs_in_node >= DEF_ADDRS_PER_INODE) 2545e5c12b0Sopenharmony_ci goto out; 2555e5c12b0Sopenharmony_ci target_blk_addr = node_blk->i.i_addr[ofs + ofs_in_node]; 2565e5c12b0Sopenharmony_ci } else { 2575e5c12b0Sopenharmony_ci if (ofs_in_node >= DEF_ADDRS_PER_BLOCK) 2585e5c12b0Sopenharmony_ci goto out; 2595e5c12b0Sopenharmony_ci target_blk_addr = node_blk->dn.addr[ofs_in_node]; 2605e5c12b0Sopenharmony_ci } 2615e5c12b0Sopenharmony_ci 2625e5c12b0Sopenharmony_ci if (blk_addr == le32_to_cpu(target_blk_addr)) 2635e5c12b0Sopenharmony_ci ret = 1; 2645e5c12b0Sopenharmony_ciout: 2655e5c12b0Sopenharmony_ci free(node_blk); 2665e5c12b0Sopenharmony_ci return ret; 2675e5c12b0Sopenharmony_ci} 2685e5c12b0Sopenharmony_ci 2695e5c12b0Sopenharmony_cistatic int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr, 2705e5c12b0Sopenharmony_ci u32 parent_nid, u16 idx_in_node, u8 version) 2715e5c12b0Sopenharmony_ci{ 2725e5c12b0Sopenharmony_ci struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 2735e5c12b0Sopenharmony_ci struct f2fs_summary_block *sum_blk; 2745e5c12b0Sopenharmony_ci struct f2fs_summary *sum_entry; 2755e5c12b0Sopenharmony_ci struct seg_entry * se; 2765e5c12b0Sopenharmony_ci u32 segno, offset; 2775e5c12b0Sopenharmony_ci int need_fix = 0, ret = 0; 2785e5c12b0Sopenharmony_ci int type; 2795e5c12b0Sopenharmony_ci 2805e5c12b0Sopenharmony_ci if (get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) 2815e5c12b0Sopenharmony_ci return 0; 2825e5c12b0Sopenharmony_ci 2835e5c12b0Sopenharmony_ci segno = GET_SEGNO(sbi, blk_addr); 2845e5c12b0Sopenharmony_ci offset = OFFSET_IN_SEG(sbi, blk_addr); 2855e5c12b0Sopenharmony_ci 2865e5c12b0Sopenharmony_ci sum_blk = get_sum_block(sbi, segno, &type); 2875e5c12b0Sopenharmony_ci 2885e5c12b0Sopenharmony_ci if (type != SEG_TYPE_DATA && type != SEG_TYPE_CUR_DATA) { 2895e5c12b0Sopenharmony_ci /* can't fix current summary, then drop the block */ 2905e5c12b0Sopenharmony_ci if (!c.fix_on || type < 0) { 2915e5c12b0Sopenharmony_ci ASSERT_MSG("Summary footer is not for data segment"); 2925e5c12b0Sopenharmony_ci ret = -EINVAL; 2935e5c12b0Sopenharmony_ci goto out; 2945e5c12b0Sopenharmony_ci } 2955e5c12b0Sopenharmony_ci 2965e5c12b0Sopenharmony_ci need_fix = 1; 2975e5c12b0Sopenharmony_ci se = get_seg_entry(sbi, segno); 2985e5c12b0Sopenharmony_ci if (IS_DATASEG(se->type)) { 2995e5c12b0Sopenharmony_ci FIX_MSG("Summary footer indicates a data segment: 0x%x", segno); 3005e5c12b0Sopenharmony_ci sum_blk->footer.entry_type = SUM_TYPE_DATA; 3015e5c12b0Sopenharmony_ci } else { 3025e5c12b0Sopenharmony_ci ret = -EINVAL; 3035e5c12b0Sopenharmony_ci goto out; 3045e5c12b0Sopenharmony_ci } 3055e5c12b0Sopenharmony_ci } 3065e5c12b0Sopenharmony_ci 3075e5c12b0Sopenharmony_ci sum_entry = &(sum_blk->entries[offset]); 3085e5c12b0Sopenharmony_ci 3095e5c12b0Sopenharmony_ci if (le32_to_cpu(sum_entry->nid) != parent_nid || 3105e5c12b0Sopenharmony_ci sum_entry->version != version || 3115e5c12b0Sopenharmony_ci le16_to_cpu(sum_entry->ofs_in_node) != idx_in_node) { 3125e5c12b0Sopenharmony_ci if (!c.fix_on || type < 0) { 3135e5c12b0Sopenharmony_ci DBG(0, "summary_entry.nid [0x%x]\n", 3145e5c12b0Sopenharmony_ci le32_to_cpu(sum_entry->nid)); 3155e5c12b0Sopenharmony_ci DBG(0, "summary_entry.version [0x%x]\n", 3165e5c12b0Sopenharmony_ci sum_entry->version); 3175e5c12b0Sopenharmony_ci DBG(0, "summary_entry.ofs_in_node [0x%x]\n", 3185e5c12b0Sopenharmony_ci le16_to_cpu(sum_entry->ofs_in_node)); 3195e5c12b0Sopenharmony_ci DBG(0, "parent nid [0x%x]\n", 3205e5c12b0Sopenharmony_ci parent_nid); 3215e5c12b0Sopenharmony_ci DBG(0, "version from nat [0x%x]\n", version); 3225e5c12b0Sopenharmony_ci DBG(0, "idx in parent node [0x%x]\n", 3235e5c12b0Sopenharmony_ci idx_in_node); 3245e5c12b0Sopenharmony_ci 3255e5c12b0Sopenharmony_ci DBG(0, "Target data block addr [0x%x]\n", blk_addr); 3265e5c12b0Sopenharmony_ci ASSERT_MSG("Invalid data seg summary\n"); 3275e5c12b0Sopenharmony_ci ret = -EINVAL; 3285e5c12b0Sopenharmony_ci } else if (is_valid_summary(sbi, sum_entry, blk_addr)) { 3295e5c12b0Sopenharmony_ci /* delete wrong index */ 3305e5c12b0Sopenharmony_ci ret = -EINVAL; 3315e5c12b0Sopenharmony_ci } else { 3325e5c12b0Sopenharmony_ci FIX_MSG("Set data summary 0x%x -> [0x%x] [0x%x] [0x%x]", 3335e5c12b0Sopenharmony_ci segno, parent_nid, version, idx_in_node); 3345e5c12b0Sopenharmony_ci sum_entry->nid = cpu_to_le32(parent_nid); 3355e5c12b0Sopenharmony_ci sum_entry->version = version; 3365e5c12b0Sopenharmony_ci sum_entry->ofs_in_node = cpu_to_le16(idx_in_node); 3375e5c12b0Sopenharmony_ci need_fix = 1; 3385e5c12b0Sopenharmony_ci } 3395e5c12b0Sopenharmony_ci } 3405e5c12b0Sopenharmony_ci if (need_fix && f2fs_dev_is_writable()) { 3415e5c12b0Sopenharmony_ci u64 ssa_blk; 3425e5c12b0Sopenharmony_ci int ret2; 3435e5c12b0Sopenharmony_ci 3445e5c12b0Sopenharmony_ci ssa_blk = GET_SUM_BLKADDR(sbi, segno); 3455e5c12b0Sopenharmony_ci ret2 = dev_write_block(sum_blk, ssa_blk); 3465e5c12b0Sopenharmony_ci ASSERT(ret2 >= 0); 3475e5c12b0Sopenharmony_ci } 3485e5c12b0Sopenharmony_ciout: 3495e5c12b0Sopenharmony_ci if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || 3505e5c12b0Sopenharmony_ci type == SEG_TYPE_MAX) 3515e5c12b0Sopenharmony_ci free(sum_blk); 3525e5c12b0Sopenharmony_ci return ret; 3535e5c12b0Sopenharmony_ci} 3545e5c12b0Sopenharmony_ci 3555e5c12b0Sopenharmony_cistatic int __check_inode_mode(u32 nid, enum FILE_TYPE ftype, u16 mode) 3565e5c12b0Sopenharmony_ci{ 3575e5c12b0Sopenharmony_ci if (ftype >= F2FS_FT_MAX) 3585e5c12b0Sopenharmony_ci return 0; 3595e5c12b0Sopenharmony_ci /* f2fs_iget will return -EIO if mode is not valid file type */ 3605e5c12b0Sopenharmony_ci if (!S_ISLNK(mode) && !S_ISREG(mode) && !S_ISDIR(mode) && 3615e5c12b0Sopenharmony_ci !S_ISCHR(mode) && !S_ISBLK(mode) && !S_ISFIFO(mode) && 3625e5c12b0Sopenharmony_ci !S_ISSOCK(mode)) { 3635e5c12b0Sopenharmony_ci ASSERT_MSG("inode [0x%x] unknown file type i_mode [0x%x]", 3645e5c12b0Sopenharmony_ci nid, mode); 3655e5c12b0Sopenharmony_ci return -1; 3665e5c12b0Sopenharmony_ci } 3675e5c12b0Sopenharmony_ci 3685e5c12b0Sopenharmony_ci if (S_ISLNK(mode) && ftype != F2FS_FT_SYMLINK) 3695e5c12b0Sopenharmony_ci goto err; 3705e5c12b0Sopenharmony_ci if (S_ISREG(mode) && ftype != F2FS_FT_REG_FILE) 3715e5c12b0Sopenharmony_ci goto err; 3725e5c12b0Sopenharmony_ci if (S_ISDIR(mode) && ftype != F2FS_FT_DIR) 3735e5c12b0Sopenharmony_ci goto err; 3745e5c12b0Sopenharmony_ci if (S_ISCHR(mode) && ftype != F2FS_FT_CHRDEV) 3755e5c12b0Sopenharmony_ci goto err; 3765e5c12b0Sopenharmony_ci if (S_ISBLK(mode) && ftype != F2FS_FT_BLKDEV) 3775e5c12b0Sopenharmony_ci goto err; 3785e5c12b0Sopenharmony_ci if (S_ISFIFO(mode) && ftype != F2FS_FT_FIFO) 3795e5c12b0Sopenharmony_ci goto err; 3805e5c12b0Sopenharmony_ci if (S_ISSOCK(mode) && ftype != F2FS_FT_SOCK) 3815e5c12b0Sopenharmony_ci goto err; 3825e5c12b0Sopenharmony_ci return 0; 3835e5c12b0Sopenharmony_cierr: 3845e5c12b0Sopenharmony_ci ASSERT_MSG("inode [0x%x] mismatch i_mode [0x%x vs. 0x%x]", 3855e5c12b0Sopenharmony_ci nid, ftype, mode); 3865e5c12b0Sopenharmony_ci return -1; 3875e5c12b0Sopenharmony_ci} 3885e5c12b0Sopenharmony_ci 3895e5c12b0Sopenharmony_cistatic int sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid, 3905e5c12b0Sopenharmony_ci struct f2fs_node *node_blk, 3915e5c12b0Sopenharmony_ci enum FILE_TYPE ftype, enum NODE_TYPE ntype, 3925e5c12b0Sopenharmony_ci struct node_info *ni) 3935e5c12b0Sopenharmony_ci{ 3945e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 3955e5c12b0Sopenharmony_ci int ret; 3965e5c12b0Sopenharmony_ci 3975e5c12b0Sopenharmony_ci if (!IS_VALID_NID(sbi, nid)) { 3985e5c12b0Sopenharmony_ci ASSERT_MSG("nid is not valid. [0x%x]", nid); 3995e5c12b0Sopenharmony_ci return -EINVAL; 4005e5c12b0Sopenharmony_ci } 4015e5c12b0Sopenharmony_ci 4025e5c12b0Sopenharmony_ci get_node_info(sbi, nid, ni); 4035e5c12b0Sopenharmony_ci if (ni->ino == 0) { 4045e5c12b0Sopenharmony_ci ASSERT_MSG("nid[0x%x] ino is 0", nid); 4055e5c12b0Sopenharmony_ci return -EINVAL; 4065e5c12b0Sopenharmony_ci } 4075e5c12b0Sopenharmony_ci 4085e5c12b0Sopenharmony_ci if (ni->blk_addr == NEW_ADDR) { 4095e5c12b0Sopenharmony_ci ASSERT_MSG("nid is NEW_ADDR. [0x%x]", nid); 4105e5c12b0Sopenharmony_ci return -EINVAL; 4115e5c12b0Sopenharmony_ci } 4125e5c12b0Sopenharmony_ci 4135e5c12b0Sopenharmony_ci if (!IS_VALID_BLK_ADDR(sbi, ni->blk_addr)) { 4145e5c12b0Sopenharmony_ci ASSERT_MSG("blkaddress is not valid. [0x%x]", ni->blk_addr); 4155e5c12b0Sopenharmony_ci return -EINVAL; 4165e5c12b0Sopenharmony_ci } 4175e5c12b0Sopenharmony_ci 4185e5c12b0Sopenharmony_ci ret = dev_read_block(node_blk, ni->blk_addr); 4195e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 4205e5c12b0Sopenharmony_ci 4215e5c12b0Sopenharmony_ci if (ntype == TYPE_INODE && 4225e5c12b0Sopenharmony_ci node_blk->footer.nid != node_blk->footer.ino) { 4235e5c12b0Sopenharmony_ci ASSERT_MSG("nid[0x%x] footer.nid[0x%x] footer.ino[0x%x]", 4245e5c12b0Sopenharmony_ci nid, le32_to_cpu(node_blk->footer.nid), 4255e5c12b0Sopenharmony_ci le32_to_cpu(node_blk->footer.ino)); 4265e5c12b0Sopenharmony_ci return -EINVAL; 4275e5c12b0Sopenharmony_ci } 4285e5c12b0Sopenharmony_ci if (ni->ino != le32_to_cpu(node_blk->footer.ino)) { 4295e5c12b0Sopenharmony_ci ASSERT_MSG("nid[0x%x] nat_entry->ino[0x%x] footer.ino[0x%x]", 4305e5c12b0Sopenharmony_ci nid, ni->ino, le32_to_cpu(node_blk->footer.ino)); 4315e5c12b0Sopenharmony_ci return -EINVAL; 4325e5c12b0Sopenharmony_ci } 4335e5c12b0Sopenharmony_ci if (ntype != TYPE_INODE && 4345e5c12b0Sopenharmony_ci node_blk->footer.nid == node_blk->footer.ino) { 4355e5c12b0Sopenharmony_ci ASSERT_MSG("nid[0x%x] footer.nid[0x%x] footer.ino[0x%x]", 4365e5c12b0Sopenharmony_ci nid, le32_to_cpu(node_blk->footer.nid), 4375e5c12b0Sopenharmony_ci le32_to_cpu(node_blk->footer.ino)); 4385e5c12b0Sopenharmony_ci return -EINVAL; 4395e5c12b0Sopenharmony_ci } 4405e5c12b0Sopenharmony_ci 4415e5c12b0Sopenharmony_ci if (le32_to_cpu(node_blk->footer.nid) != nid) { 4425e5c12b0Sopenharmony_ci ASSERT_MSG("nid[0x%x] blk_addr[0x%x] footer.nid[0x%x]", 4435e5c12b0Sopenharmony_ci nid, ni->blk_addr, 4445e5c12b0Sopenharmony_ci le32_to_cpu(node_blk->footer.nid)); 4455e5c12b0Sopenharmony_ci return -EINVAL; 4465e5c12b0Sopenharmony_ci } 4475e5c12b0Sopenharmony_ci 4485e5c12b0Sopenharmony_ci if (ntype == TYPE_XATTR) { 4495e5c12b0Sopenharmony_ci u32 flag = le32_to_cpu(node_blk->footer.flag); 4505e5c12b0Sopenharmony_ci 4515e5c12b0Sopenharmony_ci if ((flag >> OFFSET_BIT_SHIFT) != XATTR_NODE_OFFSET) { 4525e5c12b0Sopenharmony_ci ASSERT_MSG("xnid[0x%x] has wrong ofs:[0x%x]", 4535e5c12b0Sopenharmony_ci nid, flag); 4545e5c12b0Sopenharmony_ci return -EINVAL; 4555e5c12b0Sopenharmony_ci } 4565e5c12b0Sopenharmony_ci } 4575e5c12b0Sopenharmony_ci 4585e5c12b0Sopenharmony_ci if ((ntype == TYPE_INODE && ftype == F2FS_FT_DIR) || 4595e5c12b0Sopenharmony_ci (ntype == TYPE_XATTR && ftype == F2FS_FT_XATTR)) { 4605e5c12b0Sopenharmony_ci /* not included '.' & '..' */ 4615e5c12b0Sopenharmony_ci if (f2fs_test_main_bitmap(sbi, ni->blk_addr) != 0) { 4625e5c12b0Sopenharmony_ci ASSERT_MSG("Duplicated node blk. nid[0x%x][0x%x]\n", 4635e5c12b0Sopenharmony_ci nid, ni->blk_addr); 4645e5c12b0Sopenharmony_ci return -EINVAL; 4655e5c12b0Sopenharmony_ci } 4665e5c12b0Sopenharmony_ci } 4675e5c12b0Sopenharmony_ci 4685e5c12b0Sopenharmony_ci /* this if only from fix_hard_links */ 4695e5c12b0Sopenharmony_ci if (ftype == F2FS_FT_MAX) 4705e5c12b0Sopenharmony_ci return 0; 4715e5c12b0Sopenharmony_ci 4725e5c12b0Sopenharmony_ci if (ntype == TYPE_INODE && 4735e5c12b0Sopenharmony_ci __check_inode_mode(nid, ftype, le16_to_cpu(node_blk->i.i_mode))) 4745e5c12b0Sopenharmony_ci return -EINVAL; 4755e5c12b0Sopenharmony_ci 4765e5c12b0Sopenharmony_ci /* workaround to fix later */ 4775e5c12b0Sopenharmony_ci if (ftype != F2FS_FT_ORPHAN || 4785e5c12b0Sopenharmony_ci f2fs_test_bit(nid, fsck->nat_area_bitmap) != 0) { 4795e5c12b0Sopenharmony_ci f2fs_clear_bit(nid, fsck->nat_area_bitmap); 4805e5c12b0Sopenharmony_ci /* avoid reusing nid when reconnecting files */ 4815e5c12b0Sopenharmony_ci f2fs_set_bit(nid, NM_I(sbi)->nid_bitmap); 4825e5c12b0Sopenharmony_ci } else 4835e5c12b0Sopenharmony_ci ASSERT_MSG("orphan or xattr nid is duplicated [0x%x]\n", 4845e5c12b0Sopenharmony_ci nid); 4855e5c12b0Sopenharmony_ci 4865e5c12b0Sopenharmony_ci if (is_valid_ssa_node_blk(sbi, nid, ni->blk_addr)) { 4875e5c12b0Sopenharmony_ci ASSERT_MSG("summary node block is not valid. [0x%x]", nid); 4885e5c12b0Sopenharmony_ci return -EINVAL; 4895e5c12b0Sopenharmony_ci } 4905e5c12b0Sopenharmony_ci 4915e5c12b0Sopenharmony_ci if (f2fs_test_sit_bitmap(sbi, ni->blk_addr) == 0) 4925e5c12b0Sopenharmony_ci ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]", 4935e5c12b0Sopenharmony_ci ni->blk_addr); 4945e5c12b0Sopenharmony_ci 4955e5c12b0Sopenharmony_ci if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) { 4965e5c12b0Sopenharmony_ci 4975e5c12b0Sopenharmony_ci fsck->chk.valid_blk_cnt++; 4985e5c12b0Sopenharmony_ci fsck->chk.valid_node_cnt++; 4995e5c12b0Sopenharmony_ci 5005e5c12b0Sopenharmony_ci /* Progress report */ 5015e5c12b0Sopenharmony_ci if (!c.show_file_map && sbi->total_valid_node_count > 1000) { 5025e5c12b0Sopenharmony_ci unsigned int p10 = sbi->total_valid_node_count / 10; 5035e5c12b0Sopenharmony_ci 5045e5c12b0Sopenharmony_ci if (sbi->fsck->chk.checked_node_cnt++ % p10) 5055e5c12b0Sopenharmony_ci return 0; 5065e5c12b0Sopenharmony_ci 5075e5c12b0Sopenharmony_ci printf("[FSCK] Check node %"PRIu64" / %u (%.2f%%)\n", 5085e5c12b0Sopenharmony_ci sbi->fsck->chk.checked_node_cnt, 5095e5c12b0Sopenharmony_ci sbi->total_valid_node_count, 5105e5c12b0Sopenharmony_ci 10 * (float)sbi->fsck->chk.checked_node_cnt / 5115e5c12b0Sopenharmony_ci p10); 5125e5c12b0Sopenharmony_ci } 5135e5c12b0Sopenharmony_ci } 5145e5c12b0Sopenharmony_ci return 0; 5155e5c12b0Sopenharmony_ci} 5165e5c12b0Sopenharmony_ci 5175e5c12b0Sopenharmony_ciint fsck_sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid, 5185e5c12b0Sopenharmony_ci struct f2fs_node *node_blk, 5195e5c12b0Sopenharmony_ci enum FILE_TYPE ftype, enum NODE_TYPE ntype, 5205e5c12b0Sopenharmony_ci struct node_info *ni) 5215e5c12b0Sopenharmony_ci{ 5225e5c12b0Sopenharmony_ci return sanity_check_nid(sbi, nid, node_blk, ftype, ntype, ni); 5235e5c12b0Sopenharmony_ci} 5245e5c12b0Sopenharmony_ci 5255e5c12b0Sopenharmony_cistatic int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino, 5265e5c12b0Sopenharmony_ci u32 x_nid, u32 *blk_cnt) 5275e5c12b0Sopenharmony_ci{ 5285e5c12b0Sopenharmony_ci struct f2fs_node *node_blk = NULL; 5295e5c12b0Sopenharmony_ci struct node_info ni; 5305e5c12b0Sopenharmony_ci int ret = 0; 5315e5c12b0Sopenharmony_ci 5325e5c12b0Sopenharmony_ci if (x_nid == 0x0) 5335e5c12b0Sopenharmony_ci return 0; 5345e5c12b0Sopenharmony_ci 5355e5c12b0Sopenharmony_ci node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1); 5365e5c12b0Sopenharmony_ci ASSERT(node_blk != NULL); 5375e5c12b0Sopenharmony_ci 5385e5c12b0Sopenharmony_ci /* Sanity check */ 5395e5c12b0Sopenharmony_ci if (sanity_check_nid(sbi, x_nid, node_blk, 5405e5c12b0Sopenharmony_ci F2FS_FT_XATTR, TYPE_XATTR, &ni)) { 5415e5c12b0Sopenharmony_ci ret = -EINVAL; 5425e5c12b0Sopenharmony_ci goto out; 5435e5c12b0Sopenharmony_ci } 5445e5c12b0Sopenharmony_ci 5455e5c12b0Sopenharmony_ci *blk_cnt = *blk_cnt + 1; 5465e5c12b0Sopenharmony_ci f2fs_set_main_bitmap(sbi, ni.blk_addr, CURSEG_COLD_NODE); 5475e5c12b0Sopenharmony_ci DBG(2, "ino[0x%x] x_nid[0x%x]\n", ino, x_nid); 5485e5c12b0Sopenharmony_ciout: 5495e5c12b0Sopenharmony_ci free(node_blk); 5505e5c12b0Sopenharmony_ci return ret; 5515e5c12b0Sopenharmony_ci} 5525e5c12b0Sopenharmony_ci 5535e5c12b0Sopenharmony_ciint fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, 5545e5c12b0Sopenharmony_ci u32 nid, enum FILE_TYPE ftype, enum NODE_TYPE ntype, 5555e5c12b0Sopenharmony_ci u32 *blk_cnt, struct f2fs_compr_blk_cnt *cbc, 5565e5c12b0Sopenharmony_ci struct child_info *child) 5575e5c12b0Sopenharmony_ci{ 5585e5c12b0Sopenharmony_ci struct node_info ni; 5595e5c12b0Sopenharmony_ci struct f2fs_node *node_blk = NULL; 5605e5c12b0Sopenharmony_ci 5615e5c12b0Sopenharmony_ci node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1); 5625e5c12b0Sopenharmony_ci ASSERT(node_blk != NULL); 5635e5c12b0Sopenharmony_ci 5645e5c12b0Sopenharmony_ci if (sanity_check_nid(sbi, nid, node_blk, ftype, ntype, &ni)) 5655e5c12b0Sopenharmony_ci goto err; 5665e5c12b0Sopenharmony_ci 5675e5c12b0Sopenharmony_ci if (ntype == TYPE_INODE) { 5685e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 5695e5c12b0Sopenharmony_ci 5705e5c12b0Sopenharmony_ci fsck_chk_inode_blk(sbi, nid, ftype, node_blk, blk_cnt, cbc, 5715e5c12b0Sopenharmony_ci &ni, child); 5725e5c12b0Sopenharmony_ci quota_add_inode_usage(fsck->qctx, nid, &node_blk->i); 5735e5c12b0Sopenharmony_ci } else { 5745e5c12b0Sopenharmony_ci switch (ntype) { 5755e5c12b0Sopenharmony_ci case TYPE_DIRECT_NODE: 5765e5c12b0Sopenharmony_ci f2fs_set_main_bitmap(sbi, ni.blk_addr, 5775e5c12b0Sopenharmony_ci CURSEG_WARM_NODE); 5785e5c12b0Sopenharmony_ci fsck_chk_dnode_blk(sbi, inode, nid, ftype, node_blk, 5795e5c12b0Sopenharmony_ci blk_cnt, cbc, child, &ni); 5805e5c12b0Sopenharmony_ci break; 5815e5c12b0Sopenharmony_ci case TYPE_INDIRECT_NODE: 5825e5c12b0Sopenharmony_ci f2fs_set_main_bitmap(sbi, ni.blk_addr, 5835e5c12b0Sopenharmony_ci CURSEG_COLD_NODE); 5845e5c12b0Sopenharmony_ci fsck_chk_idnode_blk(sbi, inode, ftype, node_blk, 5855e5c12b0Sopenharmony_ci blk_cnt, cbc, child); 5865e5c12b0Sopenharmony_ci break; 5875e5c12b0Sopenharmony_ci case TYPE_DOUBLE_INDIRECT_NODE: 5885e5c12b0Sopenharmony_ci f2fs_set_main_bitmap(sbi, ni.blk_addr, 5895e5c12b0Sopenharmony_ci CURSEG_COLD_NODE); 5905e5c12b0Sopenharmony_ci fsck_chk_didnode_blk(sbi, inode, ftype, node_blk, 5915e5c12b0Sopenharmony_ci blk_cnt, cbc, child); 5925e5c12b0Sopenharmony_ci break; 5935e5c12b0Sopenharmony_ci default: 5945e5c12b0Sopenharmony_ci ASSERT(0); 5955e5c12b0Sopenharmony_ci } 5965e5c12b0Sopenharmony_ci } 5975e5c12b0Sopenharmony_ci free(node_blk); 5985e5c12b0Sopenharmony_ci return 0; 5995e5c12b0Sopenharmony_cierr: 6005e5c12b0Sopenharmony_ci free(node_blk); 6015e5c12b0Sopenharmony_ci return -EINVAL; 6025e5c12b0Sopenharmony_ci} 6035e5c12b0Sopenharmony_ci 6045e5c12b0Sopenharmony_cistatic inline void get_extent_info(struct extent_info *ext, 6055e5c12b0Sopenharmony_ci struct f2fs_extent *i_ext) 6065e5c12b0Sopenharmony_ci{ 6075e5c12b0Sopenharmony_ci ext->fofs = le32_to_cpu(i_ext->fofs); 6085e5c12b0Sopenharmony_ci ext->blk = le32_to_cpu(i_ext->blk_addr); 6095e5c12b0Sopenharmony_ci ext->len = le32_to_cpu(i_ext->len); 6105e5c12b0Sopenharmony_ci} 6115e5c12b0Sopenharmony_ci 6125e5c12b0Sopenharmony_cistatic void check_extent_info(struct child_info *child, 6135e5c12b0Sopenharmony_ci block_t blkaddr, int last) 6145e5c12b0Sopenharmony_ci{ 6155e5c12b0Sopenharmony_ci struct extent_info *ei = &child->ei; 6165e5c12b0Sopenharmony_ci u32 pgofs = child->pgofs; 6175e5c12b0Sopenharmony_ci int is_hole = 0; 6185e5c12b0Sopenharmony_ci 6195e5c12b0Sopenharmony_ci if (!ei->len) 6205e5c12b0Sopenharmony_ci return; 6215e5c12b0Sopenharmony_ci 6225e5c12b0Sopenharmony_ci if (child->state & FSCK_UNMATCHED_EXTENT) 6235e5c12b0Sopenharmony_ci return; 6245e5c12b0Sopenharmony_ci 6255e5c12b0Sopenharmony_ci if ((child->state & FSCK_INLINE_INODE) && ei->len) 6265e5c12b0Sopenharmony_ci goto unmatched; 6275e5c12b0Sopenharmony_ci 6285e5c12b0Sopenharmony_ci if (last) { 6295e5c12b0Sopenharmony_ci /* hole exist in the back of extent */ 6305e5c12b0Sopenharmony_ci if (child->last_blk != ei->blk + ei->len - 1) 6315e5c12b0Sopenharmony_ci child->state |= FSCK_UNMATCHED_EXTENT; 6325e5c12b0Sopenharmony_ci return; 6335e5c12b0Sopenharmony_ci } 6345e5c12b0Sopenharmony_ci 6355e5c12b0Sopenharmony_ci if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) 6365e5c12b0Sopenharmony_ci is_hole = 1; 6375e5c12b0Sopenharmony_ci 6385e5c12b0Sopenharmony_ci if (pgofs >= ei->fofs && pgofs < ei->fofs + ei->len) { 6395e5c12b0Sopenharmony_ci /* unmatched blkaddr */ 6405e5c12b0Sopenharmony_ci if (is_hole || (blkaddr != pgofs - ei->fofs + ei->blk)) 6415e5c12b0Sopenharmony_ci goto unmatched; 6425e5c12b0Sopenharmony_ci 6435e5c12b0Sopenharmony_ci if (!child->last_blk) { 6445e5c12b0Sopenharmony_ci /* hole exists in the front of extent */ 6455e5c12b0Sopenharmony_ci if (pgofs != ei->fofs) 6465e5c12b0Sopenharmony_ci goto unmatched; 6475e5c12b0Sopenharmony_ci } else if (child->last_blk + 1 != blkaddr) { 6485e5c12b0Sopenharmony_ci /* hole exists in the middle of extent */ 6495e5c12b0Sopenharmony_ci goto unmatched; 6505e5c12b0Sopenharmony_ci } 6515e5c12b0Sopenharmony_ci child->last_blk = blkaddr; 6525e5c12b0Sopenharmony_ci return; 6535e5c12b0Sopenharmony_ci } 6545e5c12b0Sopenharmony_ci 6555e5c12b0Sopenharmony_ci if (is_hole) 6565e5c12b0Sopenharmony_ci return; 6575e5c12b0Sopenharmony_ci 6585e5c12b0Sopenharmony_ci if (blkaddr < ei->blk || blkaddr >= ei->blk + ei->len) 6595e5c12b0Sopenharmony_ci return; 6605e5c12b0Sopenharmony_ci /* unmatched file offset */ 6615e5c12b0Sopenharmony_ciunmatched: 6625e5c12b0Sopenharmony_ci child->state |= FSCK_UNMATCHED_EXTENT; 6635e5c12b0Sopenharmony_ci} 6645e5c12b0Sopenharmony_ci 6655e5c12b0Sopenharmony_civoid fsck_reada_node_block(struct f2fs_sb_info *sbi, u32 nid) 6665e5c12b0Sopenharmony_ci{ 6675e5c12b0Sopenharmony_ci struct node_info ni; 6685e5c12b0Sopenharmony_ci 6695e5c12b0Sopenharmony_ci if (nid != 0 && IS_VALID_NID(sbi, nid)) { 6705e5c12b0Sopenharmony_ci get_node_info(sbi, nid, &ni); 6715e5c12b0Sopenharmony_ci if (IS_VALID_BLK_ADDR(sbi, ni.blk_addr)) 6725e5c12b0Sopenharmony_ci dev_reada_block(ni.blk_addr); 6735e5c12b0Sopenharmony_ci } 6745e5c12b0Sopenharmony_ci} 6755e5c12b0Sopenharmony_ci 6765e5c12b0Sopenharmony_civoid fsck_reada_all_direct_node_blocks(struct f2fs_sb_info *sbi, 6775e5c12b0Sopenharmony_ci struct f2fs_node *node_blk) 6785e5c12b0Sopenharmony_ci{ 6795e5c12b0Sopenharmony_ci int i; 6805e5c12b0Sopenharmony_ci 6815e5c12b0Sopenharmony_ci for (i = 0; i < NIDS_PER_BLOCK; i++) { 6825e5c12b0Sopenharmony_ci u32 nid = le32_to_cpu(node_blk->in.nid[i]); 6835e5c12b0Sopenharmony_ci 6845e5c12b0Sopenharmony_ci fsck_reada_node_block(sbi, nid); 6855e5c12b0Sopenharmony_ci } 6865e5c12b0Sopenharmony_ci} 6875e5c12b0Sopenharmony_ci 6885e5c12b0Sopenharmony_ci/* start with valid nid and blkaddr */ 6895e5c12b0Sopenharmony_civoid fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid, 6905e5c12b0Sopenharmony_ci enum FILE_TYPE ftype, struct f2fs_node *node_blk, 6915e5c12b0Sopenharmony_ci u32 *blk_cnt, struct f2fs_compr_blk_cnt *cbc, 6925e5c12b0Sopenharmony_ci struct node_info *ni, struct child_info *child_d) 6935e5c12b0Sopenharmony_ci{ 6945e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 6955e5c12b0Sopenharmony_ci struct child_info child; 6965e5c12b0Sopenharmony_ci enum NODE_TYPE ntype; 6975e5c12b0Sopenharmony_ci u32 i_links = le32_to_cpu(node_blk->i.i_links); 6985e5c12b0Sopenharmony_ci u64 i_size = le64_to_cpu(node_blk->i.i_size); 6995e5c12b0Sopenharmony_ci u64 i_blocks = le64_to_cpu(node_blk->i.i_blocks); 7005e5c12b0Sopenharmony_ci bool compr_supported = c.feature & cpu_to_le32(F2FS_FEATURE_COMPRESSION); 7015e5c12b0Sopenharmony_ci u32 i_flags = le32_to_cpu(node_blk->i.i_flags); 7025e5c12b0Sopenharmony_ci bool compressed = i_flags & F2FS_COMPR_FL; 7035e5c12b0Sopenharmony_ci bool compr_rel = node_blk->i.i_inline & F2FS_COMPRESS_RELEASED; 7045e5c12b0Sopenharmony_ci u64 i_compr_blocks = le64_to_cpu(node_blk->i.i_compr_blocks); 7055e5c12b0Sopenharmony_ci nid_t i_xattr_nid = le32_to_cpu(node_blk->i.i_xattr_nid); 7065e5c12b0Sopenharmony_ci int ofs; 7075e5c12b0Sopenharmony_ci char *en; 7085e5c12b0Sopenharmony_ci u32 namelen; 7095e5c12b0Sopenharmony_ci unsigned int addrs, idx = 0; 7105e5c12b0Sopenharmony_ci unsigned short i_gc_failures; 7115e5c12b0Sopenharmony_ci int need_fix = 0; 7125e5c12b0Sopenharmony_ci int ret; 7135e5c12b0Sopenharmony_ci u32 cluster_size = 1 << node_blk->i.i_log_cluster_size; 7145e5c12b0Sopenharmony_ci 7155e5c12b0Sopenharmony_ci if (!compressed) 7165e5c12b0Sopenharmony_ci goto check_next; 7175e5c12b0Sopenharmony_ci 7185e5c12b0Sopenharmony_ci if (!compr_supported || (node_blk->i.i_inline & F2FS_INLINE_DATA)) { 7195e5c12b0Sopenharmony_ci /* 7205e5c12b0Sopenharmony_ci * The 'compression' flag in i_flags affects the traverse of 7215e5c12b0Sopenharmony_ci * the node tree. Thus, it must be fixed unconditionally 7225e5c12b0Sopenharmony_ci * in the memory (node_blk). 7235e5c12b0Sopenharmony_ci */ 7245e5c12b0Sopenharmony_ci node_blk->i.i_flags &= ~cpu_to_le32(F2FS_COMPR_FL); 7255e5c12b0Sopenharmony_ci compressed = false; 7265e5c12b0Sopenharmony_ci if (c.fix_on) { 7275e5c12b0Sopenharmony_ci need_fix = 1; 7285e5c12b0Sopenharmony_ci FIX_MSG("[0x%x] i_flags=0x%x -> 0x%x", 7295e5c12b0Sopenharmony_ci nid, i_flags, node_blk->i.i_flags); 7305e5c12b0Sopenharmony_ci } 7315e5c12b0Sopenharmony_ci i_flags &= ~F2FS_COMPR_FL; 7325e5c12b0Sopenharmony_ci } 7335e5c12b0Sopenharmony_cicheck_next: 7345e5c12b0Sopenharmony_ci memset(&child, 0, sizeof(child)); 7355e5c12b0Sopenharmony_ci child.links = 2; 7365e5c12b0Sopenharmony_ci child.p_ino = nid; 7375e5c12b0Sopenharmony_ci child.pp_ino = le32_to_cpu(node_blk->i.i_pino); 7385e5c12b0Sopenharmony_ci child.dir_level = node_blk->i.i_dir_level; 7395e5c12b0Sopenharmony_ci 7405e5c12b0Sopenharmony_ci if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) 7415e5c12b0Sopenharmony_ci fsck->chk.valid_inode_cnt++; 7425e5c12b0Sopenharmony_ci 7435e5c12b0Sopenharmony_ci if (ftype == F2FS_FT_DIR) { 7445e5c12b0Sopenharmony_ci f2fs_set_main_bitmap(sbi, ni->blk_addr, CURSEG_HOT_NODE); 7455e5c12b0Sopenharmony_ci namelen = le32_to_cpu(node_blk->i.i_namelen); 7465e5c12b0Sopenharmony_ci if (namelen > F2FS_NAME_LEN) 7475e5c12b0Sopenharmony_ci namelen = F2FS_NAME_LEN; 7485e5c12b0Sopenharmony_ci memcpy(child.p_name, node_blk->i.i_name, namelen); 7495e5c12b0Sopenharmony_ci } else { 7505e5c12b0Sopenharmony_ci if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) { 7515e5c12b0Sopenharmony_ci f2fs_set_main_bitmap(sbi, ni->blk_addr, 7525e5c12b0Sopenharmony_ci CURSEG_WARM_NODE); 7535e5c12b0Sopenharmony_ci if (i_links > 1 && ftype != F2FS_FT_ORPHAN && 7545e5c12b0Sopenharmony_ci !is_qf_ino(F2FS_RAW_SUPER(sbi), nid)) { 7555e5c12b0Sopenharmony_ci /* First time. Create new hard link node */ 7565e5c12b0Sopenharmony_ci add_into_hard_link_list(sbi, nid, i_links); 7575e5c12b0Sopenharmony_ci fsck->chk.multi_hard_link_files++; 7585e5c12b0Sopenharmony_ci } 7595e5c12b0Sopenharmony_ci } else { 7605e5c12b0Sopenharmony_ci DBG(3, "[0x%x] has hard links [0x%x]\n", nid, i_links); 7615e5c12b0Sopenharmony_ci if (find_and_dec_hard_link_list(sbi, nid)) { 7625e5c12b0Sopenharmony_ci ASSERT_MSG("[0x%x] needs more i_links=0x%x", 7635e5c12b0Sopenharmony_ci nid, i_links); 7645e5c12b0Sopenharmony_ci if (c.fix_on) { 7655e5c12b0Sopenharmony_ci node_blk->i.i_links = 7665e5c12b0Sopenharmony_ci cpu_to_le32(i_links + 1); 7675e5c12b0Sopenharmony_ci need_fix = 1; 7685e5c12b0Sopenharmony_ci FIX_MSG("File: 0x%x " 7695e5c12b0Sopenharmony_ci "i_links= 0x%x -> 0x%x", 7705e5c12b0Sopenharmony_ci nid, i_links, i_links + 1); 7715e5c12b0Sopenharmony_ci } 7725e5c12b0Sopenharmony_ci goto skip_blkcnt_fix; 7735e5c12b0Sopenharmony_ci } 7745e5c12b0Sopenharmony_ci /* No need to go deep into the node */ 7755e5c12b0Sopenharmony_ci return; 7765e5c12b0Sopenharmony_ci } 7775e5c12b0Sopenharmony_ci } 7785e5c12b0Sopenharmony_ci 7795e5c12b0Sopenharmony_ci /* readahead xattr node block */ 7805e5c12b0Sopenharmony_ci fsck_reada_node_block(sbi, i_xattr_nid); 7815e5c12b0Sopenharmony_ci 7825e5c12b0Sopenharmony_ci if (fsck_chk_xattr_blk(sbi, nid, i_xattr_nid, blk_cnt)) { 7835e5c12b0Sopenharmony_ci if (c.fix_on) { 7845e5c12b0Sopenharmony_ci node_blk->i.i_xattr_nid = 0; 7855e5c12b0Sopenharmony_ci need_fix = 1; 7865e5c12b0Sopenharmony_ci FIX_MSG("Remove xattr block: 0x%x, x_nid = 0x%x", 7875e5c12b0Sopenharmony_ci nid, i_xattr_nid); 7885e5c12b0Sopenharmony_ci } 7895e5c12b0Sopenharmony_ci } 7905e5c12b0Sopenharmony_ci 7915e5c12b0Sopenharmony_ci if (ftype == F2FS_FT_CHRDEV || ftype == F2FS_FT_BLKDEV || 7925e5c12b0Sopenharmony_ci ftype == F2FS_FT_FIFO || ftype == F2FS_FT_SOCK) 7935e5c12b0Sopenharmony_ci goto check; 7945e5c12b0Sopenharmony_ci 7955e5c12b0Sopenharmony_ci /* init extent info */ 7965e5c12b0Sopenharmony_ci get_extent_info(&child.ei, &node_blk->i.i_ext); 7975e5c12b0Sopenharmony_ci child.last_blk = 0; 7985e5c12b0Sopenharmony_ci 7995e5c12b0Sopenharmony_ci if (f2fs_has_extra_isize(&node_blk->i)) { 8005e5c12b0Sopenharmony_ci if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) { 8015e5c12b0Sopenharmony_ci unsigned int isize = 8025e5c12b0Sopenharmony_ci le16_to_cpu(node_blk->i.i_extra_isize); 8035e5c12b0Sopenharmony_ci if (isize > 4 * DEF_ADDRS_PER_INODE) { 8045e5c12b0Sopenharmony_ci ASSERT_MSG("[0x%x] wrong i_extra_isize=0x%x", 8055e5c12b0Sopenharmony_ci nid, isize); 8065e5c12b0Sopenharmony_ci if (c.fix_on) { 8075e5c12b0Sopenharmony_ci FIX_MSG("ino[0x%x] recover i_extra_isize " 8085e5c12b0Sopenharmony_ci "from %u to %u", 8095e5c12b0Sopenharmony_ci nid, isize, 8105e5c12b0Sopenharmony_ci calc_extra_isize()); 8115e5c12b0Sopenharmony_ci node_blk->i.i_extra_isize = 8125e5c12b0Sopenharmony_ci cpu_to_le16(calc_extra_isize()); 8135e5c12b0Sopenharmony_ci need_fix = 1; 8145e5c12b0Sopenharmony_ci } 8155e5c12b0Sopenharmony_ci } 8165e5c12b0Sopenharmony_ci } else { 8175e5c12b0Sopenharmony_ci ASSERT_MSG("[0x%x] wrong extra_attr flag", nid); 8185e5c12b0Sopenharmony_ci if (c.fix_on) { 8195e5c12b0Sopenharmony_ci FIX_MSG("ino[0x%x] remove F2FS_EXTRA_ATTR " 8205e5c12b0Sopenharmony_ci "flag in i_inline:%u", 8215e5c12b0Sopenharmony_ci nid, node_blk->i.i_inline); 8225e5c12b0Sopenharmony_ci /* we don't support tuning F2FS_FEATURE_EXTRA_ATTR now */ 8235e5c12b0Sopenharmony_ci node_blk->i.i_inline &= ~F2FS_EXTRA_ATTR; 8245e5c12b0Sopenharmony_ci need_fix = 1; 8255e5c12b0Sopenharmony_ci } 8265e5c12b0Sopenharmony_ci } 8275e5c12b0Sopenharmony_ci 8285e5c12b0Sopenharmony_ci if ((c.feature & 8295e5c12b0Sopenharmony_ci cpu_to_le32(F2FS_FEATURE_FLEXIBLE_INLINE_XATTR)) && 8305e5c12b0Sopenharmony_ci (node_blk->i.i_inline & F2FS_INLINE_XATTR)) { 8315e5c12b0Sopenharmony_ci unsigned int inline_size = 8325e5c12b0Sopenharmony_ci le16_to_cpu(node_blk->i.i_inline_xattr_size); 8335e5c12b0Sopenharmony_ci 8345e5c12b0Sopenharmony_ci if (!inline_size || 8355e5c12b0Sopenharmony_ci inline_size > MAX_INLINE_XATTR_SIZE(&node_blk->i)) { 8365e5c12b0Sopenharmony_ci ASSERT_MSG("[0x%x] wrong inline_xattr_size:%u", 8375e5c12b0Sopenharmony_ci nid, inline_size); 8385e5c12b0Sopenharmony_ci if (c.fix_on) { 8395e5c12b0Sopenharmony_ci FIX_MSG("ino[0x%x] recover inline xattr size " 8405e5c12b0Sopenharmony_ci "from %u to %u", 8415e5c12b0Sopenharmony_ci nid, inline_size, 8425e5c12b0Sopenharmony_ci DEFAULT_INLINE_XATTR_ADDRS); 8435e5c12b0Sopenharmony_ci node_blk->i.i_inline_xattr_size = 8445e5c12b0Sopenharmony_ci cpu_to_le16(DEFAULT_INLINE_XATTR_ADDRS); 8455e5c12b0Sopenharmony_ci need_fix = 1; 8465e5c12b0Sopenharmony_ci } 8475e5c12b0Sopenharmony_ci } 8485e5c12b0Sopenharmony_ci } 8495e5c12b0Sopenharmony_ci } 8505e5c12b0Sopenharmony_ci ofs = get_extra_isize(node_blk); 8515e5c12b0Sopenharmony_ci 8525e5c12b0Sopenharmony_ci if ((node_blk->i.i_flags & cpu_to_le32(F2FS_CASEFOLD_FL)) && 8535e5c12b0Sopenharmony_ci (ftype != F2FS_FT_DIR || 8545e5c12b0Sopenharmony_ci !(c.feature & cpu_to_le32(F2FS_FEATURE_CASEFOLD)))) { 8555e5c12b0Sopenharmony_ci ASSERT_MSG("[0x%x] unexpected casefold flag", nid); 8565e5c12b0Sopenharmony_ci if (c.fix_on) { 8575e5c12b0Sopenharmony_ci FIX_MSG("ino[0x%x] clear casefold flag", nid); 8585e5c12b0Sopenharmony_ci node_blk->i.i_flags &= ~cpu_to_le32(F2FS_CASEFOLD_FL); 8595e5c12b0Sopenharmony_ci need_fix = 1; 8605e5c12b0Sopenharmony_ci } 8615e5c12b0Sopenharmony_ci } 8625e5c12b0Sopenharmony_ci 8635e5c12b0Sopenharmony_ci if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) { 8645e5c12b0Sopenharmony_ci unsigned int inline_size = MAX_INLINE_DATA(node_blk); 8655e5c12b0Sopenharmony_ci if (cur_qtype != -1) 8665e5c12b0Sopenharmony_ci qf_szchk_type[cur_qtype] = QF_SZCHK_INLINE; 8675e5c12b0Sopenharmony_ci block_t blkaddr = le32_to_cpu(node_blk->i.i_addr[ofs]); 8685e5c12b0Sopenharmony_ci 8695e5c12b0Sopenharmony_ci if (blkaddr != 0) { 8705e5c12b0Sopenharmony_ci ASSERT_MSG("[0x%x] wrong inline reserve blkaddr:%u", 8715e5c12b0Sopenharmony_ci nid, blkaddr); 8725e5c12b0Sopenharmony_ci if (c.fix_on) { 8735e5c12b0Sopenharmony_ci FIX_MSG("inline_data has wrong 0'th block = %x", 8745e5c12b0Sopenharmony_ci blkaddr); 8755e5c12b0Sopenharmony_ci node_blk->i.i_addr[ofs] = 0; 8765e5c12b0Sopenharmony_ci node_blk->i.i_blocks = cpu_to_le64(*blk_cnt); 8775e5c12b0Sopenharmony_ci need_fix = 1; 8785e5c12b0Sopenharmony_ci } 8795e5c12b0Sopenharmony_ci } 8805e5c12b0Sopenharmony_ci if (i_size > inline_size) { 8815e5c12b0Sopenharmony_ci ASSERT_MSG("[0x%x] wrong inline size:%lu", 8825e5c12b0Sopenharmony_ci nid, (unsigned long)i_size); 8835e5c12b0Sopenharmony_ci if (c.fix_on) { 8845e5c12b0Sopenharmony_ci node_blk->i.i_size = cpu_to_le64(inline_size); 8855e5c12b0Sopenharmony_ci FIX_MSG("inline_data has wrong i_size %lu", 8865e5c12b0Sopenharmony_ci (unsigned long)i_size); 8875e5c12b0Sopenharmony_ci need_fix = 1; 8885e5c12b0Sopenharmony_ci } 8895e5c12b0Sopenharmony_ci } 8905e5c12b0Sopenharmony_ci if (!(node_blk->i.i_inline & F2FS_DATA_EXIST)) { 8915e5c12b0Sopenharmony_ci char buf[MAX_INLINE_DATA(node_blk)]; 8925e5c12b0Sopenharmony_ci memset(buf, 0, MAX_INLINE_DATA(node_blk)); 8935e5c12b0Sopenharmony_ci 8945e5c12b0Sopenharmony_ci if (memcmp(buf, inline_data_addr(node_blk), 8955e5c12b0Sopenharmony_ci MAX_INLINE_DATA(node_blk))) { 8965e5c12b0Sopenharmony_ci ASSERT_MSG("[0x%x] junk inline data", nid); 8975e5c12b0Sopenharmony_ci if (c.fix_on) { 8985e5c12b0Sopenharmony_ci FIX_MSG("inline_data has DATA_EXIST"); 8995e5c12b0Sopenharmony_ci node_blk->i.i_inline |= F2FS_DATA_EXIST; 9005e5c12b0Sopenharmony_ci need_fix = 1; 9015e5c12b0Sopenharmony_ci } 9025e5c12b0Sopenharmony_ci } 9035e5c12b0Sopenharmony_ci } 9045e5c12b0Sopenharmony_ci DBG(3, "ino[0x%x] has inline data!\n", nid); 9055e5c12b0Sopenharmony_ci child.state |= FSCK_INLINE_INODE; 9065e5c12b0Sopenharmony_ci goto check; 9075e5c12b0Sopenharmony_ci } 9085e5c12b0Sopenharmony_ci 9095e5c12b0Sopenharmony_ci if ((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) { 9105e5c12b0Sopenharmony_ci block_t blkaddr = le32_to_cpu(node_blk->i.i_addr[ofs]); 9115e5c12b0Sopenharmony_ci 9125e5c12b0Sopenharmony_ci DBG(3, "ino[0x%x] has inline dentry!\n", nid); 9135e5c12b0Sopenharmony_ci if (blkaddr != 0) { 9145e5c12b0Sopenharmony_ci ASSERT_MSG("[0x%x] wrong inline reserve blkaddr:%u", 9155e5c12b0Sopenharmony_ci nid, blkaddr); 9165e5c12b0Sopenharmony_ci if (c.fix_on) { 9175e5c12b0Sopenharmony_ci FIX_MSG("inline_dentry has wrong 0'th block = %x", 9185e5c12b0Sopenharmony_ci blkaddr); 9195e5c12b0Sopenharmony_ci node_blk->i.i_addr[ofs] = 0; 9205e5c12b0Sopenharmony_ci node_blk->i.i_blocks = cpu_to_le64(*blk_cnt); 9215e5c12b0Sopenharmony_ci need_fix = 1; 9225e5c12b0Sopenharmony_ci } 9235e5c12b0Sopenharmony_ci } 9245e5c12b0Sopenharmony_ci 9255e5c12b0Sopenharmony_ci ret = fsck_chk_inline_dentries(sbi, node_blk, &child); 9265e5c12b0Sopenharmony_ci if (ret < 0) { 9275e5c12b0Sopenharmony_ci if (c.fix_on) 9285e5c12b0Sopenharmony_ci need_fix = 1; 9295e5c12b0Sopenharmony_ci } 9305e5c12b0Sopenharmony_ci child.state |= FSCK_INLINE_INODE; 9315e5c12b0Sopenharmony_ci goto check; 9325e5c12b0Sopenharmony_ci } 9335e5c12b0Sopenharmony_ci 9345e5c12b0Sopenharmony_ci /* check data blocks in inode */ 9355e5c12b0Sopenharmony_ci addrs = ADDRS_PER_INODE(&node_blk->i); 9365e5c12b0Sopenharmony_ci if (cur_qtype != -1) { 9375e5c12b0Sopenharmony_ci u64 addrs_per_blk = (u64)ADDRS_PER_BLOCK(&node_blk->i); 9385e5c12b0Sopenharmony_ci qf_szchk_type[cur_qtype] = QF_SZCHK_REGFILE; 9395e5c12b0Sopenharmony_ci qf_maxsize[cur_qtype] = (u64)(addrs + 2 * addrs_per_blk + 9405e5c12b0Sopenharmony_ci 2 * addrs_per_blk * NIDS_PER_BLOCK + 9415e5c12b0Sopenharmony_ci addrs_per_blk * NIDS_PER_BLOCK * 9425e5c12b0Sopenharmony_ci NIDS_PER_BLOCK) * F2FS_BLKSIZE; 9435e5c12b0Sopenharmony_ci } 9445e5c12b0Sopenharmony_ci for (idx = 0; idx < addrs; idx++, child.pgofs++) { 9455e5c12b0Sopenharmony_ci block_t blkaddr = le32_to_cpu(node_blk->i.i_addr[ofs + idx]); 9465e5c12b0Sopenharmony_ci 9475e5c12b0Sopenharmony_ci /* check extent info */ 9485e5c12b0Sopenharmony_ci check_extent_info(&child, blkaddr, 0); 9495e5c12b0Sopenharmony_ci 9505e5c12b0Sopenharmony_ci if (blkaddr == NULL_ADDR) 9515e5c12b0Sopenharmony_ci continue; 9525e5c12b0Sopenharmony_ci if (blkaddr == COMPRESS_ADDR) { 9535e5c12b0Sopenharmony_ci if (!compressed || (child.pgofs & 9545e5c12b0Sopenharmony_ci (cluster_size - 1)) != 0) { 9555e5c12b0Sopenharmony_ci if (c.fix_on) { 9565e5c12b0Sopenharmony_ci node_blk->i.i_addr[ofs + idx] = 9575e5c12b0Sopenharmony_ci NULL_ADDR; 9585e5c12b0Sopenharmony_ci need_fix = 1; 9595e5c12b0Sopenharmony_ci FIX_MSG("[0x%x] i_addr[%d] = 0", nid, 9605e5c12b0Sopenharmony_ci ofs + idx); 9615e5c12b0Sopenharmony_ci } 9625e5c12b0Sopenharmony_ci continue; 9635e5c12b0Sopenharmony_ci } 9645e5c12b0Sopenharmony_ci if (!compr_rel) { 9655e5c12b0Sopenharmony_ci fsck->chk.valid_blk_cnt++; 9665e5c12b0Sopenharmony_ci *blk_cnt = *blk_cnt + 1; 9675e5c12b0Sopenharmony_ci cbc->cheader_pgofs = child.pgofs; 9685e5c12b0Sopenharmony_ci cbc->cnt++; 9695e5c12b0Sopenharmony_ci } 9705e5c12b0Sopenharmony_ci continue; 9715e5c12b0Sopenharmony_ci } 9725e5c12b0Sopenharmony_ci if (!compr_rel && blkaddr == NEW_ADDR && 9735e5c12b0Sopenharmony_ci child.pgofs - cbc->cheader_pgofs < cluster_size) 9745e5c12b0Sopenharmony_ci cbc->cnt++; 9755e5c12b0Sopenharmony_ci ret = fsck_chk_data_blk(sbi, 9765e5c12b0Sopenharmony_ci IS_CASEFOLDED(&node_blk->i), 9775e5c12b0Sopenharmony_ci blkaddr, 9785e5c12b0Sopenharmony_ci &child, (i_blocks == *blk_cnt), 9795e5c12b0Sopenharmony_ci ftype, nid, idx, ni->version, 9805e5c12b0Sopenharmony_ci file_is_encrypt(&node_blk->i)); 9815e5c12b0Sopenharmony_ci if (!ret) { 9825e5c12b0Sopenharmony_ci *blk_cnt = *blk_cnt + 1; 9835e5c12b0Sopenharmony_ci if (cur_qtype != -1 && blkaddr != NEW_ADDR) 9845e5c12b0Sopenharmony_ci qf_last_blkofs[cur_qtype] = child.pgofs; 9855e5c12b0Sopenharmony_ci } else if (c.fix_on) { 9865e5c12b0Sopenharmony_ci node_blk->i.i_addr[ofs + idx] = 0; 9875e5c12b0Sopenharmony_ci need_fix = 1; 9885e5c12b0Sopenharmony_ci FIX_MSG("[0x%x] i_addr[%d] = 0", nid, ofs + idx); 9895e5c12b0Sopenharmony_ci } 9905e5c12b0Sopenharmony_ci } 9915e5c12b0Sopenharmony_ci 9925e5c12b0Sopenharmony_ci /* readahead node blocks */ 9935e5c12b0Sopenharmony_ci for (idx = 0; idx < 5; idx++) { 9945e5c12b0Sopenharmony_ci u32 nid = le32_to_cpu(node_blk->i.i_nid[idx]); 9955e5c12b0Sopenharmony_ci fsck_reada_node_block(sbi, nid); 9965e5c12b0Sopenharmony_ci } 9975e5c12b0Sopenharmony_ci 9985e5c12b0Sopenharmony_ci /* check node blocks in inode */ 9995e5c12b0Sopenharmony_ci for (idx = 0; idx < 5; idx++) { 10005e5c12b0Sopenharmony_ci nid_t i_nid = le32_to_cpu(node_blk->i.i_nid[idx]); 10015e5c12b0Sopenharmony_ci 10025e5c12b0Sopenharmony_ci if (idx == 0 || idx == 1) 10035e5c12b0Sopenharmony_ci ntype = TYPE_DIRECT_NODE; 10045e5c12b0Sopenharmony_ci else if (idx == 2 || idx == 3) 10055e5c12b0Sopenharmony_ci ntype = TYPE_INDIRECT_NODE; 10065e5c12b0Sopenharmony_ci else if (idx == 4) 10075e5c12b0Sopenharmony_ci ntype = TYPE_DOUBLE_INDIRECT_NODE; 10085e5c12b0Sopenharmony_ci else 10095e5c12b0Sopenharmony_ci ASSERT(0); 10105e5c12b0Sopenharmony_ci 10115e5c12b0Sopenharmony_ci if (i_nid == 0x0) 10125e5c12b0Sopenharmony_ci goto skip; 10135e5c12b0Sopenharmony_ci 10145e5c12b0Sopenharmony_ci ret = fsck_chk_node_blk(sbi, &node_blk->i, i_nid, 10155e5c12b0Sopenharmony_ci ftype, ntype, blk_cnt, cbc, &child); 10165e5c12b0Sopenharmony_ci if (!ret) { 10175e5c12b0Sopenharmony_ci *blk_cnt = *blk_cnt + 1; 10185e5c12b0Sopenharmony_ci } else if (ret == -EINVAL) { 10195e5c12b0Sopenharmony_ci if (c.fix_on) { 10205e5c12b0Sopenharmony_ci node_blk->i.i_nid[idx] = 0; 10215e5c12b0Sopenharmony_ci need_fix = 1; 10225e5c12b0Sopenharmony_ci FIX_MSG("[0x%x] i_nid[%d] = 0", nid, idx); 10235e5c12b0Sopenharmony_ci } 10245e5c12b0Sopenharmony_ciskip: 10255e5c12b0Sopenharmony_ci if (ntype == TYPE_DIRECT_NODE) 10265e5c12b0Sopenharmony_ci child.pgofs += ADDRS_PER_BLOCK(&node_blk->i); 10275e5c12b0Sopenharmony_ci else if (ntype == TYPE_INDIRECT_NODE) 10285e5c12b0Sopenharmony_ci child.pgofs += ADDRS_PER_BLOCK(&node_blk->i) * 10295e5c12b0Sopenharmony_ci NIDS_PER_BLOCK; 10305e5c12b0Sopenharmony_ci else 10315e5c12b0Sopenharmony_ci child.pgofs += ADDRS_PER_BLOCK(&node_blk->i) * 10325e5c12b0Sopenharmony_ci NIDS_PER_BLOCK * NIDS_PER_BLOCK; 10335e5c12b0Sopenharmony_ci } 10345e5c12b0Sopenharmony_ci 10355e5c12b0Sopenharmony_ci } 10365e5c12b0Sopenharmony_ci 10375e5c12b0Sopenharmony_cicheck: 10385e5c12b0Sopenharmony_ci /* check uncovered range in the back of extent */ 10395e5c12b0Sopenharmony_ci check_extent_info(&child, 0, 1); 10405e5c12b0Sopenharmony_ci 10415e5c12b0Sopenharmony_ci if (child.state & FSCK_UNMATCHED_EXTENT) { 10425e5c12b0Sopenharmony_ci ASSERT_MSG("ino: 0x%x has wrong ext: [pgofs:%u, blk:%u, len:%u]", 10435e5c12b0Sopenharmony_ci nid, child.ei.fofs, child.ei.blk, child.ei.len); 10445e5c12b0Sopenharmony_ci if (c.fix_on) 10455e5c12b0Sopenharmony_ci need_fix = 1; 10465e5c12b0Sopenharmony_ci } 10475e5c12b0Sopenharmony_ci 10485e5c12b0Sopenharmony_ci if (i_blocks != *blk_cnt) { 10495e5c12b0Sopenharmony_ci ASSERT_MSG("ino: 0x%x has i_blocks: %08"PRIx64", " 10505e5c12b0Sopenharmony_ci "but has %u blocks", 10515e5c12b0Sopenharmony_ci nid, i_blocks, *blk_cnt); 10525e5c12b0Sopenharmony_ci if (c.fix_on) { 10535e5c12b0Sopenharmony_ci node_blk->i.i_blocks = cpu_to_le64(*blk_cnt); 10545e5c12b0Sopenharmony_ci need_fix = 1; 10555e5c12b0Sopenharmony_ci FIX_MSG("[0x%x] i_blocks=0x%08"PRIx64" -> 0x%x", 10565e5c12b0Sopenharmony_ci nid, i_blocks, *blk_cnt); 10575e5c12b0Sopenharmony_ci } 10585e5c12b0Sopenharmony_ci } 10595e5c12b0Sopenharmony_ci 10605e5c12b0Sopenharmony_ci if (compressed && i_compr_blocks != cbc->cnt) { 10615e5c12b0Sopenharmony_ci if (c.fix_on) { 10625e5c12b0Sopenharmony_ci node_blk->i.i_compr_blocks = cpu_to_le64(cbc->cnt); 10635e5c12b0Sopenharmony_ci need_fix = 1; 10645e5c12b0Sopenharmony_ci FIX_MSG("[0x%x] i_compr_blocks=0x%08"PRIx64" -> 0x%x", 10655e5c12b0Sopenharmony_ci nid, i_compr_blocks, cbc->cnt); 10665e5c12b0Sopenharmony_ci } 10675e5c12b0Sopenharmony_ci } 10685e5c12b0Sopenharmony_ci 10695e5c12b0Sopenharmony_ciskip_blkcnt_fix: 10705e5c12b0Sopenharmony_ci en = malloc(F2FS_PRINT_NAMELEN); 10715e5c12b0Sopenharmony_ci ASSERT(en); 10725e5c12b0Sopenharmony_ci 10735e5c12b0Sopenharmony_ci namelen = le32_to_cpu(node_blk->i.i_namelen); 10745e5c12b0Sopenharmony_ci if (namelen > F2FS_NAME_LEN) { 10755e5c12b0Sopenharmony_ci if (child_d && child_d->i_namelen <= F2FS_NAME_LEN) { 10765e5c12b0Sopenharmony_ci ASSERT_MSG("ino: 0x%x has i_namelen: 0x%x, " 10775e5c12b0Sopenharmony_ci "but has %d characters for name", 10785e5c12b0Sopenharmony_ci nid, namelen, child_d->i_namelen); 10795e5c12b0Sopenharmony_ci if (c.fix_on) { 10805e5c12b0Sopenharmony_ci FIX_MSG("[0x%x] i_namelen=0x%x -> 0x%x", nid, namelen, 10815e5c12b0Sopenharmony_ci child_d->i_namelen); 10825e5c12b0Sopenharmony_ci node_blk->i.i_namelen = cpu_to_le32(child_d->i_namelen); 10835e5c12b0Sopenharmony_ci need_fix = 1; 10845e5c12b0Sopenharmony_ci } 10855e5c12b0Sopenharmony_ci namelen = child_d->i_namelen; 10865e5c12b0Sopenharmony_ci } else 10875e5c12b0Sopenharmony_ci namelen = F2FS_NAME_LEN; 10885e5c12b0Sopenharmony_ci } 10895e5c12b0Sopenharmony_ci pretty_print_filename(node_blk->i.i_name, namelen, en, 10905e5c12b0Sopenharmony_ci file_enc_name(&node_blk->i)); 10915e5c12b0Sopenharmony_ci if (ftype == F2FS_FT_ORPHAN) 10925e5c12b0Sopenharmony_ci DBG(1, "Orphan Inode: 0x%x [%s] i_blocks: %u\n\n", 10935e5c12b0Sopenharmony_ci le32_to_cpu(node_blk->footer.ino), 10945e5c12b0Sopenharmony_ci en, (u32)i_blocks); 10955e5c12b0Sopenharmony_ci 10965e5c12b0Sopenharmony_ci if (is_qf_ino(F2FS_RAW_SUPER(sbi), nid)) 10975e5c12b0Sopenharmony_ci DBG(1, "Quota Inode: 0x%x [%s] i_blocks: %u\n\n", 10985e5c12b0Sopenharmony_ci le32_to_cpu(node_blk->footer.ino), 10995e5c12b0Sopenharmony_ci en, (u32)i_blocks); 11005e5c12b0Sopenharmony_ci 11015e5c12b0Sopenharmony_ci if (ftype == F2FS_FT_DIR) { 11025e5c12b0Sopenharmony_ci DBG(1, "Directory Inode: 0x%x [%s] depth: %d has %d files\n\n", 11035e5c12b0Sopenharmony_ci le32_to_cpu(node_blk->footer.ino), en, 11045e5c12b0Sopenharmony_ci le32_to_cpu(node_blk->i.i_current_depth), 11055e5c12b0Sopenharmony_ci child.files); 11065e5c12b0Sopenharmony_ci 11075e5c12b0Sopenharmony_ci if (i_links != child.links) { 11085e5c12b0Sopenharmony_ci ASSERT_MSG("ino: 0x%x i_links: %u, real links: %u", 11095e5c12b0Sopenharmony_ci nid, i_links, child.links); 11105e5c12b0Sopenharmony_ci if (c.fix_on) { 11115e5c12b0Sopenharmony_ci node_blk->i.i_links = cpu_to_le32(child.links); 11125e5c12b0Sopenharmony_ci need_fix = 1; 11135e5c12b0Sopenharmony_ci FIX_MSG("Dir: 0x%x i_links= 0x%x -> 0x%x", 11145e5c12b0Sopenharmony_ci nid, i_links, child.links); 11155e5c12b0Sopenharmony_ci } 11165e5c12b0Sopenharmony_ci } 11175e5c12b0Sopenharmony_ci if (child.dots < 2 && 11185e5c12b0Sopenharmony_ci !(node_blk->i.i_inline & F2FS_INLINE_DOTS)) { 11195e5c12b0Sopenharmony_ci ASSERT_MSG("ino: 0x%x dots: %u", 11205e5c12b0Sopenharmony_ci nid, child.dots); 11215e5c12b0Sopenharmony_ci if (c.fix_on) { 11225e5c12b0Sopenharmony_ci node_blk->i.i_inline |= F2FS_INLINE_DOTS; 11235e5c12b0Sopenharmony_ci need_fix = 1; 11245e5c12b0Sopenharmony_ci FIX_MSG("Dir: 0x%x set inline_dots", nid); 11255e5c12b0Sopenharmony_ci } 11265e5c12b0Sopenharmony_ci } 11275e5c12b0Sopenharmony_ci } 11285e5c12b0Sopenharmony_ci 11295e5c12b0Sopenharmony_ci i_gc_failures = le16_to_cpu(node_blk->i.i_gc_failures); 11305e5c12b0Sopenharmony_ci 11315e5c12b0Sopenharmony_ci /* 11325e5c12b0Sopenharmony_ci * old kernel initialized i_gc_failures as 0x01, in preen mode 2, 11335e5c12b0Sopenharmony_ci * let's skip repairing. 11345e5c12b0Sopenharmony_ci */ 11355e5c12b0Sopenharmony_ci if (ftype == F2FS_FT_REG_FILE && i_gc_failures && 11365e5c12b0Sopenharmony_ci (c.preen_mode != PREEN_MODE_2 || i_gc_failures != 0x01)) { 11375e5c12b0Sopenharmony_ci 11385e5c12b0Sopenharmony_ci DBG(1, "Regular Inode: 0x%x [%s] depth: %d\n\n", 11395e5c12b0Sopenharmony_ci le32_to_cpu(node_blk->footer.ino), en, 11405e5c12b0Sopenharmony_ci i_gc_failures); 11415e5c12b0Sopenharmony_ci 11425e5c12b0Sopenharmony_ci if (c.fix_on) { 11435e5c12b0Sopenharmony_ci node_blk->i.i_gc_failures = cpu_to_le16(0); 11445e5c12b0Sopenharmony_ci need_fix = 1; 11455e5c12b0Sopenharmony_ci FIX_MSG("Regular: 0x%x reset i_gc_failures from 0x%x to 0x00", 11465e5c12b0Sopenharmony_ci nid, i_gc_failures); 11475e5c12b0Sopenharmony_ci } 11485e5c12b0Sopenharmony_ci } 11495e5c12b0Sopenharmony_ci 11505e5c12b0Sopenharmony_ci free(en); 11515e5c12b0Sopenharmony_ci 11525e5c12b0Sopenharmony_ci if (ftype == F2FS_FT_SYMLINK && i_size == 0 && 11535e5c12b0Sopenharmony_ci i_blocks == (i_xattr_nid ? 3 : 2)) { 11545e5c12b0Sopenharmony_ci node_blk->i.i_size = cpu_to_le64(F2FS_BLKSIZE); 11555e5c12b0Sopenharmony_ci need_fix = 1; 11565e5c12b0Sopenharmony_ci FIX_MSG("Symlink: recover 0x%x with i_size=%lu", 11575e5c12b0Sopenharmony_ci nid, (unsigned long)F2FS_BLKSIZE); 11585e5c12b0Sopenharmony_ci } 11595e5c12b0Sopenharmony_ci 11605e5c12b0Sopenharmony_ci if (ftype == F2FS_FT_ORPHAN && i_links) { 11615e5c12b0Sopenharmony_ci ASSERT_MSG("ino: 0x%x is orphan inode, but has i_links: %u", 11625e5c12b0Sopenharmony_ci nid, i_links); 11635e5c12b0Sopenharmony_ci if (c.fix_on) { 11645e5c12b0Sopenharmony_ci node_blk->i.i_links = 0; 11655e5c12b0Sopenharmony_ci need_fix = 1; 11665e5c12b0Sopenharmony_ci FIX_MSG("ino: 0x%x orphan_inode, i_links= 0x%x -> 0", 11675e5c12b0Sopenharmony_ci nid, i_links); 11685e5c12b0Sopenharmony_ci } 11695e5c12b0Sopenharmony_ci } 11705e5c12b0Sopenharmony_ci 11715e5c12b0Sopenharmony_ci /* drop extent information to avoid potential wrong access */ 11725e5c12b0Sopenharmony_ci if (need_fix && f2fs_dev_is_writable()) 11735e5c12b0Sopenharmony_ci node_blk->i.i_ext.len = 0; 11745e5c12b0Sopenharmony_ci 11755e5c12b0Sopenharmony_ci if ((c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM)) && 11765e5c12b0Sopenharmony_ci f2fs_has_extra_isize(&node_blk->i)) { 11775e5c12b0Sopenharmony_ci __u32 provided, calculated; 11785e5c12b0Sopenharmony_ci 11795e5c12b0Sopenharmony_ci provided = le32_to_cpu(node_blk->i.i_inode_checksum); 11805e5c12b0Sopenharmony_ci calculated = f2fs_inode_chksum(node_blk); 11815e5c12b0Sopenharmony_ci 11825e5c12b0Sopenharmony_ci if (provided != calculated) { 11835e5c12b0Sopenharmony_ci ASSERT_MSG("ino: 0x%x chksum:0x%x, but calculated one is: 0x%x", 11845e5c12b0Sopenharmony_ci nid, provided, calculated); 11855e5c12b0Sopenharmony_ci if (c.fix_on) { 11865e5c12b0Sopenharmony_ci node_blk->i.i_inode_checksum = 11875e5c12b0Sopenharmony_ci cpu_to_le32(calculated); 11885e5c12b0Sopenharmony_ci need_fix = 1; 11895e5c12b0Sopenharmony_ci FIX_MSG("ino: 0x%x recover, i_inode_checksum= 0x%x -> 0x%x", 11905e5c12b0Sopenharmony_ci nid, provided, calculated); 11915e5c12b0Sopenharmony_ci } 11925e5c12b0Sopenharmony_ci } 11935e5c12b0Sopenharmony_ci } 11945e5c12b0Sopenharmony_ci 11955e5c12b0Sopenharmony_ci if (need_fix && f2fs_dev_is_writable()) { 11965e5c12b0Sopenharmony_ci ret = dev_write_block(node_blk, ni->blk_addr); 11975e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 11985e5c12b0Sopenharmony_ci } 11995e5c12b0Sopenharmony_ci} 12005e5c12b0Sopenharmony_ci 12015e5c12b0Sopenharmony_ciint fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, 12025e5c12b0Sopenharmony_ci u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, 12035e5c12b0Sopenharmony_ci u32 *blk_cnt, struct f2fs_compr_blk_cnt *cbc, 12045e5c12b0Sopenharmony_ci struct child_info *child, struct node_info *ni) 12055e5c12b0Sopenharmony_ci{ 12065e5c12b0Sopenharmony_ci int idx, ret; 12075e5c12b0Sopenharmony_ci int need_fix = 0; 12085e5c12b0Sopenharmony_ci child->p_ino = nid; 12095e5c12b0Sopenharmony_ci child->pp_ino = le32_to_cpu(inode->i_pino); 12105e5c12b0Sopenharmony_ci u32 i_flags = le32_to_cpu(inode->i_flags); 12115e5c12b0Sopenharmony_ci bool compressed = i_flags & F2FS_COMPR_FL; 12125e5c12b0Sopenharmony_ci bool compr_rel = inode->i_inline & F2FS_COMPRESS_RELEASED; 12135e5c12b0Sopenharmony_ci u32 cluster_size = 1 << inode->i_log_cluster_size; 12145e5c12b0Sopenharmony_ci 12155e5c12b0Sopenharmony_ci for (idx = 0; idx < ADDRS_PER_BLOCK(inode); idx++, child->pgofs++) { 12165e5c12b0Sopenharmony_ci block_t blkaddr = le32_to_cpu(node_blk->dn.addr[idx]); 12175e5c12b0Sopenharmony_ci 12185e5c12b0Sopenharmony_ci check_extent_info(child, blkaddr, 0); 12195e5c12b0Sopenharmony_ci 12205e5c12b0Sopenharmony_ci if (blkaddr == NULL_ADDR) 12215e5c12b0Sopenharmony_ci continue; 12225e5c12b0Sopenharmony_ci if (blkaddr == COMPRESS_ADDR) { 12235e5c12b0Sopenharmony_ci if (!compressed || (child->pgofs & 12245e5c12b0Sopenharmony_ci (cluster_size - 1)) != 0) { 12255e5c12b0Sopenharmony_ci if (c.fix_on) { 12265e5c12b0Sopenharmony_ci node_blk->dn.addr[idx] = NULL_ADDR; 12275e5c12b0Sopenharmony_ci need_fix = 1; 12285e5c12b0Sopenharmony_ci FIX_MSG("[0x%x] dn.addr[%d] = 0", nid, 12295e5c12b0Sopenharmony_ci idx); 12305e5c12b0Sopenharmony_ci } 12315e5c12b0Sopenharmony_ci continue; 12325e5c12b0Sopenharmony_ci } 12335e5c12b0Sopenharmony_ci if (!compr_rel) { 12345e5c12b0Sopenharmony_ci F2FS_FSCK(sbi)->chk.valid_blk_cnt++; 12355e5c12b0Sopenharmony_ci *blk_cnt = *blk_cnt + 1; 12365e5c12b0Sopenharmony_ci cbc->cheader_pgofs = child->pgofs; 12375e5c12b0Sopenharmony_ci cbc->cnt++; 12385e5c12b0Sopenharmony_ci } 12395e5c12b0Sopenharmony_ci continue; 12405e5c12b0Sopenharmony_ci } 12415e5c12b0Sopenharmony_ci if (!compr_rel && blkaddr == NEW_ADDR && child->pgofs - 12425e5c12b0Sopenharmony_ci cbc->cheader_pgofs < cluster_size) 12435e5c12b0Sopenharmony_ci cbc->cnt++; 12445e5c12b0Sopenharmony_ci ret = fsck_chk_data_blk(sbi, IS_CASEFOLDED(inode), 12455e5c12b0Sopenharmony_ci blkaddr, child, 12465e5c12b0Sopenharmony_ci le64_to_cpu(inode->i_blocks) == *blk_cnt, ftype, 12475e5c12b0Sopenharmony_ci nid, idx, ni->version, 12485e5c12b0Sopenharmony_ci file_is_encrypt(inode)); 12495e5c12b0Sopenharmony_ci if (!ret) { 12505e5c12b0Sopenharmony_ci *blk_cnt = *blk_cnt + 1; 12515e5c12b0Sopenharmony_ci if (cur_qtype != -1 && blkaddr != NEW_ADDR) 12525e5c12b0Sopenharmony_ci qf_last_blkofs[cur_qtype] = child->pgofs; 12535e5c12b0Sopenharmony_ci } else if (c.fix_on) { 12545e5c12b0Sopenharmony_ci node_blk->dn.addr[idx] = NULL_ADDR; 12555e5c12b0Sopenharmony_ci need_fix = 1; 12565e5c12b0Sopenharmony_ci FIX_MSG("[0x%x] dn.addr[%d] = 0", nid, idx); 12575e5c12b0Sopenharmony_ci } 12585e5c12b0Sopenharmony_ci } 12595e5c12b0Sopenharmony_ci if (need_fix && f2fs_dev_is_writable()) { 12605e5c12b0Sopenharmony_ci ret = dev_write_block(node_blk, ni->blk_addr); 12615e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 12625e5c12b0Sopenharmony_ci } 12635e5c12b0Sopenharmony_ci return 0; 12645e5c12b0Sopenharmony_ci} 12655e5c12b0Sopenharmony_ci 12665e5c12b0Sopenharmony_ciint fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, 12675e5c12b0Sopenharmony_ci enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt, 12685e5c12b0Sopenharmony_ci struct f2fs_compr_blk_cnt *cbc, struct child_info *child) 12695e5c12b0Sopenharmony_ci{ 12705e5c12b0Sopenharmony_ci int need_fix = 0, ret; 12715e5c12b0Sopenharmony_ci int i = 0; 12725e5c12b0Sopenharmony_ci 12735e5c12b0Sopenharmony_ci fsck_reada_all_direct_node_blocks(sbi, node_blk); 12745e5c12b0Sopenharmony_ci 12755e5c12b0Sopenharmony_ci for (i = 0; i < NIDS_PER_BLOCK; i++) { 12765e5c12b0Sopenharmony_ci if (le32_to_cpu(node_blk->in.nid[i]) == 0x0) 12775e5c12b0Sopenharmony_ci goto skip; 12785e5c12b0Sopenharmony_ci ret = fsck_chk_node_blk(sbi, inode, 12795e5c12b0Sopenharmony_ci le32_to_cpu(node_blk->in.nid[i]), 12805e5c12b0Sopenharmony_ci ftype, TYPE_DIRECT_NODE, blk_cnt, 12815e5c12b0Sopenharmony_ci cbc, child); 12825e5c12b0Sopenharmony_ci if (!ret) 12835e5c12b0Sopenharmony_ci *blk_cnt = *blk_cnt + 1; 12845e5c12b0Sopenharmony_ci else if (ret == -EINVAL) { 12855e5c12b0Sopenharmony_ci if (!c.fix_on) 12865e5c12b0Sopenharmony_ci printf("should delete in.nid[i] = 0;\n"); 12875e5c12b0Sopenharmony_ci else { 12885e5c12b0Sopenharmony_ci node_blk->in.nid[i] = 0; 12895e5c12b0Sopenharmony_ci need_fix = 1; 12905e5c12b0Sopenharmony_ci FIX_MSG("Set indirect node 0x%x -> 0", i); 12915e5c12b0Sopenharmony_ci } 12925e5c12b0Sopenharmony_ciskip: 12935e5c12b0Sopenharmony_ci child->pgofs += ADDRS_PER_BLOCK(&node_blk->i); 12945e5c12b0Sopenharmony_ci } 12955e5c12b0Sopenharmony_ci } 12965e5c12b0Sopenharmony_ci 12975e5c12b0Sopenharmony_ci if (need_fix && f2fs_dev_is_writable()) { 12985e5c12b0Sopenharmony_ci struct node_info ni; 12995e5c12b0Sopenharmony_ci nid_t nid = le32_to_cpu(node_blk->footer.nid); 13005e5c12b0Sopenharmony_ci 13015e5c12b0Sopenharmony_ci get_node_info(sbi, nid, &ni); 13025e5c12b0Sopenharmony_ci ret = dev_write_block(node_blk, ni.blk_addr); 13035e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 13045e5c12b0Sopenharmony_ci } 13055e5c12b0Sopenharmony_ci 13065e5c12b0Sopenharmony_ci return 0; 13075e5c12b0Sopenharmony_ci} 13085e5c12b0Sopenharmony_ci 13095e5c12b0Sopenharmony_ciint fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, 13105e5c12b0Sopenharmony_ci enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt, 13115e5c12b0Sopenharmony_ci struct f2fs_compr_blk_cnt *cbc, struct child_info *child) 13125e5c12b0Sopenharmony_ci{ 13135e5c12b0Sopenharmony_ci int i = 0; 13145e5c12b0Sopenharmony_ci int need_fix = 0, ret = 0; 13155e5c12b0Sopenharmony_ci 13165e5c12b0Sopenharmony_ci fsck_reada_all_direct_node_blocks(sbi, node_blk); 13175e5c12b0Sopenharmony_ci 13185e5c12b0Sopenharmony_ci for (i = 0; i < NIDS_PER_BLOCK; i++) { 13195e5c12b0Sopenharmony_ci if (le32_to_cpu(node_blk->in.nid[i]) == 0x0) 13205e5c12b0Sopenharmony_ci goto skip; 13215e5c12b0Sopenharmony_ci ret = fsck_chk_node_blk(sbi, inode, 13225e5c12b0Sopenharmony_ci le32_to_cpu(node_blk->in.nid[i]), 13235e5c12b0Sopenharmony_ci ftype, TYPE_INDIRECT_NODE, blk_cnt, cbc, child); 13245e5c12b0Sopenharmony_ci if (!ret) 13255e5c12b0Sopenharmony_ci *blk_cnt = *blk_cnt + 1; 13265e5c12b0Sopenharmony_ci else if (ret == -EINVAL) { 13275e5c12b0Sopenharmony_ci if (!c.fix_on) 13285e5c12b0Sopenharmony_ci printf("should delete in.nid[i] = 0;\n"); 13295e5c12b0Sopenharmony_ci else { 13305e5c12b0Sopenharmony_ci node_blk->in.nid[i] = 0; 13315e5c12b0Sopenharmony_ci need_fix = 1; 13325e5c12b0Sopenharmony_ci FIX_MSG("Set double indirect node 0x%x -> 0", i); 13335e5c12b0Sopenharmony_ci } 13345e5c12b0Sopenharmony_ciskip: 13355e5c12b0Sopenharmony_ci child->pgofs += ADDRS_PER_BLOCK(&node_blk->i) * 13365e5c12b0Sopenharmony_ci NIDS_PER_BLOCK; 13375e5c12b0Sopenharmony_ci } 13385e5c12b0Sopenharmony_ci } 13395e5c12b0Sopenharmony_ci 13405e5c12b0Sopenharmony_ci if (need_fix && f2fs_dev_is_writable()) { 13415e5c12b0Sopenharmony_ci struct node_info ni; 13425e5c12b0Sopenharmony_ci nid_t nid = le32_to_cpu(node_blk->footer.nid); 13435e5c12b0Sopenharmony_ci 13445e5c12b0Sopenharmony_ci get_node_info(sbi, nid, &ni); 13455e5c12b0Sopenharmony_ci ret = dev_write_block(node_blk, ni.blk_addr); 13465e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 13475e5c12b0Sopenharmony_ci } 13485e5c12b0Sopenharmony_ci 13495e5c12b0Sopenharmony_ci return 0; 13505e5c12b0Sopenharmony_ci} 13515e5c12b0Sopenharmony_ci 13525e5c12b0Sopenharmony_cistatic const char *lookup_table = 13535e5c12b0Sopenharmony_ci "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; 13545e5c12b0Sopenharmony_ci 13555e5c12b0Sopenharmony_ci/** 13565e5c12b0Sopenharmony_ci * base64_encode() - 13575e5c12b0Sopenharmony_ci * 13585e5c12b0Sopenharmony_ci * Encodes the input string using characters from the set [A-Za-z0-9+,]. 13595e5c12b0Sopenharmony_ci * The encoded string is roughly 4/3 times the size of the input string. 13605e5c12b0Sopenharmony_ci */ 13615e5c12b0Sopenharmony_cistatic int base64_encode(const u8 *src, int len, char *dst) 13625e5c12b0Sopenharmony_ci{ 13635e5c12b0Sopenharmony_ci int i, bits = 0, ac = 0; 13645e5c12b0Sopenharmony_ci char *cp = dst; 13655e5c12b0Sopenharmony_ci 13665e5c12b0Sopenharmony_ci for (i = 0; i < len; i++) { 13675e5c12b0Sopenharmony_ci ac += src[i] << bits; 13685e5c12b0Sopenharmony_ci bits += 8; 13695e5c12b0Sopenharmony_ci do { 13705e5c12b0Sopenharmony_ci *cp++ = lookup_table[ac & 0x3f]; 13715e5c12b0Sopenharmony_ci ac >>= 6; 13725e5c12b0Sopenharmony_ci bits -= 6; 13735e5c12b0Sopenharmony_ci } while (bits >= 6); 13745e5c12b0Sopenharmony_ci } 13755e5c12b0Sopenharmony_ci if (bits) 13765e5c12b0Sopenharmony_ci *cp++ = lookup_table[ac & 0x3f]; 13775e5c12b0Sopenharmony_ci return cp - dst; 13785e5c12b0Sopenharmony_ci} 13795e5c12b0Sopenharmony_ci 13805e5c12b0Sopenharmony_civoid pretty_print_filename(const u8 *raw_name, u32 len, 13815e5c12b0Sopenharmony_ci char out[F2FS_PRINT_NAMELEN], int enc_name) 13825e5c12b0Sopenharmony_ci{ 13835e5c12b0Sopenharmony_ci len = min(len, (u32)F2FS_NAME_LEN); 13845e5c12b0Sopenharmony_ci 13855e5c12b0Sopenharmony_ci if (enc_name) 13865e5c12b0Sopenharmony_ci len = base64_encode(raw_name, len, out); 13875e5c12b0Sopenharmony_ci else 13885e5c12b0Sopenharmony_ci memcpy(out, raw_name, len); 13895e5c12b0Sopenharmony_ci out[len] = 0; 13905e5c12b0Sopenharmony_ci} 13915e5c12b0Sopenharmony_ci 13925e5c12b0Sopenharmony_cistatic void print_dentry(struct f2fs_sb_info *sbi, __u8 *name, 13935e5c12b0Sopenharmony_ci u8 *bitmap, struct f2fs_dir_entry *dentry, 13945e5c12b0Sopenharmony_ci int max, int idx, int last_blk, int enc_name) 13955e5c12b0Sopenharmony_ci{ 13965e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 13975e5c12b0Sopenharmony_ci u32 depth = fsck->dentry_depth; 13985e5c12b0Sopenharmony_ci int last_de = 0; 13995e5c12b0Sopenharmony_ci int next_idx = 0; 14005e5c12b0Sopenharmony_ci u32 name_len; 14015e5c12b0Sopenharmony_ci unsigned int i; 14025e5c12b0Sopenharmony_ci int bit_offset; 14035e5c12b0Sopenharmony_ci char new[F2FS_PRINT_NAMELEN]; 14045e5c12b0Sopenharmony_ci 14055e5c12b0Sopenharmony_ci if (!c.show_dentry && !c.show_file_map) 14065e5c12b0Sopenharmony_ci return; 14075e5c12b0Sopenharmony_ci 14085e5c12b0Sopenharmony_ci name_len = le16_to_cpu(dentry[idx].name_len); 14095e5c12b0Sopenharmony_ci next_idx = idx + (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN; 14105e5c12b0Sopenharmony_ci 14115e5c12b0Sopenharmony_ci bit_offset = find_next_bit_le(bitmap, max, next_idx); 14125e5c12b0Sopenharmony_ci if (bit_offset >= max && last_blk) 14135e5c12b0Sopenharmony_ci last_de = 1; 14145e5c12b0Sopenharmony_ci 14155e5c12b0Sopenharmony_ci if (tree_mark_size <= depth) { 14165e5c12b0Sopenharmony_ci tree_mark_size *= 2; 14175e5c12b0Sopenharmony_ci ASSERT(tree_mark_size != 0); 14185e5c12b0Sopenharmony_ci tree_mark = realloc(tree_mark, tree_mark_size); 14195e5c12b0Sopenharmony_ci ASSERT(tree_mark != NULL); 14205e5c12b0Sopenharmony_ci } 14215e5c12b0Sopenharmony_ci 14225e5c12b0Sopenharmony_ci if (last_de) 14235e5c12b0Sopenharmony_ci tree_mark[depth] = '`'; 14245e5c12b0Sopenharmony_ci else 14255e5c12b0Sopenharmony_ci tree_mark[depth] = '|'; 14265e5c12b0Sopenharmony_ci 14275e5c12b0Sopenharmony_ci if (tree_mark[depth - 1] == '`') 14285e5c12b0Sopenharmony_ci tree_mark[depth - 1] = ' '; 14295e5c12b0Sopenharmony_ci 14305e5c12b0Sopenharmony_ci pretty_print_filename(name, name_len, new, enc_name); 14315e5c12b0Sopenharmony_ci 14325e5c12b0Sopenharmony_ci if (c.show_file_map) { 14335e5c12b0Sopenharmony_ci struct f2fs_dentry *d = fsck->dentry; 14345e5c12b0Sopenharmony_ci 14355e5c12b0Sopenharmony_ci if (dentry[idx].file_type != F2FS_FT_REG_FILE) 14365e5c12b0Sopenharmony_ci return; 14375e5c12b0Sopenharmony_ci 14385e5c12b0Sopenharmony_ci while (d) { 14395e5c12b0Sopenharmony_ci if (d->depth > 1) 14405e5c12b0Sopenharmony_ci printf("/%s", d->name); 14415e5c12b0Sopenharmony_ci d = d->next; 14425e5c12b0Sopenharmony_ci } 14435e5c12b0Sopenharmony_ci printf("/%s", new); 14445e5c12b0Sopenharmony_ci if (dump_node(sbi, le32_to_cpu(dentry[idx].ino), 0)) 14455e5c12b0Sopenharmony_ci printf("\33[2K\r"); 14465e5c12b0Sopenharmony_ci } else { 14475e5c12b0Sopenharmony_ci for (i = 1; i < depth; i++) 14485e5c12b0Sopenharmony_ci printf("%c ", tree_mark[i]); 14495e5c12b0Sopenharmony_ci 14505e5c12b0Sopenharmony_ci printf("%c-- %s <ino = 0x%x>, <encrypted (%d)>\n", 14515e5c12b0Sopenharmony_ci last_de ? '`' : '|', 14525e5c12b0Sopenharmony_ci new, le32_to_cpu(dentry[idx].ino), 14535e5c12b0Sopenharmony_ci enc_name); 14545e5c12b0Sopenharmony_ci } 14555e5c12b0Sopenharmony_ci} 14565e5c12b0Sopenharmony_ci 14575e5c12b0Sopenharmony_cistatic int f2fs_check_hash_code(int encoding, int casefolded, 14585e5c12b0Sopenharmony_ci struct f2fs_dir_entry *dentry, 14595e5c12b0Sopenharmony_ci const unsigned char *name, u32 len, int enc_name) 14605e5c12b0Sopenharmony_ci{ 14615e5c12b0Sopenharmony_ci /* Casefolded Encrypted names require a key to compute siphash */ 14625e5c12b0Sopenharmony_ci if (enc_name && casefolded) 14635e5c12b0Sopenharmony_ci return 0; 14645e5c12b0Sopenharmony_ci 14655e5c12b0Sopenharmony_ci f2fs_hash_t hash_code = f2fs_dentry_hash(encoding, casefolded, name, len); 14665e5c12b0Sopenharmony_ci /* fix hash_code made by old buggy code */ 14675e5c12b0Sopenharmony_ci if (dentry->hash_code != hash_code) { 14685e5c12b0Sopenharmony_ci char new[F2FS_PRINT_NAMELEN]; 14695e5c12b0Sopenharmony_ci 14705e5c12b0Sopenharmony_ci pretty_print_filename(name, len, new, enc_name); 14715e5c12b0Sopenharmony_ci FIX_MSG("Mismatch hash_code for \"%s\" [%x:%x]", 14725e5c12b0Sopenharmony_ci new, le32_to_cpu(dentry->hash_code), 14735e5c12b0Sopenharmony_ci hash_code); 14745e5c12b0Sopenharmony_ci dentry->hash_code = cpu_to_le32(hash_code); 14755e5c12b0Sopenharmony_ci return 1; 14765e5c12b0Sopenharmony_ci } 14775e5c12b0Sopenharmony_ci return 0; 14785e5c12b0Sopenharmony_ci} 14795e5c12b0Sopenharmony_ci 14805e5c12b0Sopenharmony_ci 14815e5c12b0Sopenharmony_cistatic int __get_current_level(int dir_level, u32 pgofs) 14825e5c12b0Sopenharmony_ci{ 14835e5c12b0Sopenharmony_ci unsigned int bidx = 0; 14845e5c12b0Sopenharmony_ci int i; 14855e5c12b0Sopenharmony_ci 14865e5c12b0Sopenharmony_ci for (i = 0; i < MAX_DIR_HASH_DEPTH; i++) { 14875e5c12b0Sopenharmony_ci bidx += dir_buckets(i, dir_level) * bucket_blocks(i); 14885e5c12b0Sopenharmony_ci if (bidx > pgofs) 14895e5c12b0Sopenharmony_ci break; 14905e5c12b0Sopenharmony_ci } 14915e5c12b0Sopenharmony_ci return i; 14925e5c12b0Sopenharmony_ci} 14935e5c12b0Sopenharmony_ci 14945e5c12b0Sopenharmony_cistatic int f2fs_check_dirent_position(const struct f2fs_dir_entry *dentry, 14955e5c12b0Sopenharmony_ci const char *printable_name, 14965e5c12b0Sopenharmony_ci u32 pgofs, u8 dir_level, u32 pino) 14975e5c12b0Sopenharmony_ci{ 14985e5c12b0Sopenharmony_ci unsigned int nbucket, nblock; 14995e5c12b0Sopenharmony_ci unsigned int bidx, end_block; 15005e5c12b0Sopenharmony_ci int level; 15015e5c12b0Sopenharmony_ci 15025e5c12b0Sopenharmony_ci level = __get_current_level(dir_level, pgofs); 15035e5c12b0Sopenharmony_ci 15045e5c12b0Sopenharmony_ci nbucket = dir_buckets(level, dir_level); 15055e5c12b0Sopenharmony_ci nblock = bucket_blocks(level); 15065e5c12b0Sopenharmony_ci 15075e5c12b0Sopenharmony_ci bidx = dir_block_index(level, dir_level, 15085e5c12b0Sopenharmony_ci le32_to_cpu(dentry->hash_code) % nbucket); 15095e5c12b0Sopenharmony_ci end_block = bidx + nblock; 15105e5c12b0Sopenharmony_ci 15115e5c12b0Sopenharmony_ci if (pgofs >= bidx && pgofs < end_block) 15125e5c12b0Sopenharmony_ci return 0; 15135e5c12b0Sopenharmony_ci 15145e5c12b0Sopenharmony_ci ASSERT_MSG("Wrong position of dirent pino:%u, name:%s, level:%d, " 15155e5c12b0Sopenharmony_ci "dir_level:%d, pgofs:%u, correct range:[%u, %u]\n", 15165e5c12b0Sopenharmony_ci pino, printable_name, level, dir_level, pgofs, bidx, 15175e5c12b0Sopenharmony_ci end_block - 1); 15185e5c12b0Sopenharmony_ci return 1; 15195e5c12b0Sopenharmony_ci} 15205e5c12b0Sopenharmony_ci 15215e5c12b0Sopenharmony_cistatic int __chk_dots_dentries(struct f2fs_sb_info *sbi, 15225e5c12b0Sopenharmony_ci int casefolded, 15235e5c12b0Sopenharmony_ci struct f2fs_dir_entry *dentry, 15245e5c12b0Sopenharmony_ci struct child_info *child, 15255e5c12b0Sopenharmony_ci u8 *name, int len, 15265e5c12b0Sopenharmony_ci __u8 (*filename)[F2FS_SLOT_LEN], 15275e5c12b0Sopenharmony_ci int enc_name) 15285e5c12b0Sopenharmony_ci{ 15295e5c12b0Sopenharmony_ci int fixed = 0; 15305e5c12b0Sopenharmony_ci 15315e5c12b0Sopenharmony_ci if ((name[0] == '.' && len == 1)) { 15325e5c12b0Sopenharmony_ci if (le32_to_cpu(dentry->ino) != child->p_ino) { 15335e5c12b0Sopenharmony_ci ASSERT_MSG("Bad inode number[0x%x] for '.', parent_ino is [0x%x]\n", 15345e5c12b0Sopenharmony_ci le32_to_cpu(dentry->ino), child->p_ino); 15355e5c12b0Sopenharmony_ci dentry->ino = cpu_to_le32(child->p_ino); 15365e5c12b0Sopenharmony_ci fixed = 1; 15375e5c12b0Sopenharmony_ci } 15385e5c12b0Sopenharmony_ci } 15395e5c12b0Sopenharmony_ci 15405e5c12b0Sopenharmony_ci if (name[0] == '.' && name[1] == '.' && len == 2) { 15415e5c12b0Sopenharmony_ci if (child->p_ino == F2FS_ROOT_INO(sbi)) { 15425e5c12b0Sopenharmony_ci if (le32_to_cpu(dentry->ino) != F2FS_ROOT_INO(sbi)) { 15435e5c12b0Sopenharmony_ci ASSERT_MSG("Bad inode number[0x%x] for '..'\n", 15445e5c12b0Sopenharmony_ci le32_to_cpu(dentry->ino)); 15455e5c12b0Sopenharmony_ci dentry->ino = cpu_to_le32(F2FS_ROOT_INO(sbi)); 15465e5c12b0Sopenharmony_ci fixed = 1; 15475e5c12b0Sopenharmony_ci } 15485e5c12b0Sopenharmony_ci } else if (le32_to_cpu(dentry->ino) != child->pp_ino) { 15495e5c12b0Sopenharmony_ci ASSERT_MSG("Bad inode number[0x%x] for '..', parent parent ino is [0x%x]\n", 15505e5c12b0Sopenharmony_ci le32_to_cpu(dentry->ino), child->pp_ino); 15515e5c12b0Sopenharmony_ci dentry->ino = cpu_to_le32(child->pp_ino); 15525e5c12b0Sopenharmony_ci fixed = 1; 15535e5c12b0Sopenharmony_ci } 15545e5c12b0Sopenharmony_ci } 15555e5c12b0Sopenharmony_ci 15565e5c12b0Sopenharmony_ci if (f2fs_check_hash_code(get_encoding(sbi), casefolded, dentry, name, len, enc_name)) 15575e5c12b0Sopenharmony_ci fixed = 1; 15585e5c12b0Sopenharmony_ci 15595e5c12b0Sopenharmony_ci if (name[len] != '\0') { 15605e5c12b0Sopenharmony_ci ASSERT_MSG("'.' is not NULL terminated\n"); 15615e5c12b0Sopenharmony_ci name[len] = '\0'; 15625e5c12b0Sopenharmony_ci memcpy(*filename, name, len); 15635e5c12b0Sopenharmony_ci fixed = 1; 15645e5c12b0Sopenharmony_ci } 15655e5c12b0Sopenharmony_ci return fixed; 15665e5c12b0Sopenharmony_ci} 15675e5c12b0Sopenharmony_ci 15685e5c12b0Sopenharmony_cistatic void nullify_dentry(struct f2fs_dir_entry *dentry, int offs, 15695e5c12b0Sopenharmony_ci __u8 (*filename)[F2FS_SLOT_LEN], u8 **bitmap) 15705e5c12b0Sopenharmony_ci{ 15715e5c12b0Sopenharmony_ci memset(dentry, 0, sizeof(struct f2fs_dir_entry)); 15725e5c12b0Sopenharmony_ci test_and_clear_bit_le(offs, *bitmap); 15735e5c12b0Sopenharmony_ci memset(*filename, 0, F2FS_SLOT_LEN); 15745e5c12b0Sopenharmony_ci} 15755e5c12b0Sopenharmony_ci 15765e5c12b0Sopenharmony_cistatic int __chk_dentries(struct f2fs_sb_info *sbi, int casefolded, 15775e5c12b0Sopenharmony_ci struct child_info *child, 15785e5c12b0Sopenharmony_ci u8 *bitmap, struct f2fs_dir_entry *dentry, 15795e5c12b0Sopenharmony_ci __u8 (*filenames)[F2FS_SLOT_LEN], 15805e5c12b0Sopenharmony_ci int max, int last_blk, int enc_name) 15815e5c12b0Sopenharmony_ci{ 15825e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 15835e5c12b0Sopenharmony_ci enum FILE_TYPE ftype; 15845e5c12b0Sopenharmony_ci int dentries = 0; 15855e5c12b0Sopenharmony_ci u32 blk_cnt; 15865e5c12b0Sopenharmony_ci struct f2fs_compr_blk_cnt cbc; 15875e5c12b0Sopenharmony_ci u8 *name; 15885e5c12b0Sopenharmony_ci char en[F2FS_PRINT_NAMELEN]; 15895e5c12b0Sopenharmony_ci u16 name_len; 15905e5c12b0Sopenharmony_ci int ret = 0; 15915e5c12b0Sopenharmony_ci int fixed = 0; 15925e5c12b0Sopenharmony_ci int i, slots; 15935e5c12b0Sopenharmony_ci 15945e5c12b0Sopenharmony_ci /* readahead inode blocks */ 15955e5c12b0Sopenharmony_ci for (i = 0; i < max; i++) { 15965e5c12b0Sopenharmony_ci u32 ino; 15975e5c12b0Sopenharmony_ci 15985e5c12b0Sopenharmony_ci if (test_bit_le(i, bitmap) == 0) 15995e5c12b0Sopenharmony_ci continue; 16005e5c12b0Sopenharmony_ci 16015e5c12b0Sopenharmony_ci ino = le32_to_cpu(dentry[i].ino); 16025e5c12b0Sopenharmony_ci 16035e5c12b0Sopenharmony_ci if (IS_VALID_NID(sbi, ino)) { 16045e5c12b0Sopenharmony_ci struct node_info ni; 16055e5c12b0Sopenharmony_ci 16065e5c12b0Sopenharmony_ci get_node_info(sbi, ino, &ni); 16075e5c12b0Sopenharmony_ci if (IS_VALID_BLK_ADDR(sbi, ni.blk_addr)) { 16085e5c12b0Sopenharmony_ci dev_reada_block(ni.blk_addr); 16095e5c12b0Sopenharmony_ci name_len = le16_to_cpu(dentry[i].name_len); 16105e5c12b0Sopenharmony_ci if (name_len > 0) 16115e5c12b0Sopenharmony_ci i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN - 1; 16125e5c12b0Sopenharmony_ci } 16135e5c12b0Sopenharmony_ci } 16145e5c12b0Sopenharmony_ci } 16155e5c12b0Sopenharmony_ci 16165e5c12b0Sopenharmony_ci for (i = 0; i < max;) { 16175e5c12b0Sopenharmony_ci if (test_bit_le(i, bitmap) == 0) { 16185e5c12b0Sopenharmony_ci i++; 16195e5c12b0Sopenharmony_ci continue; 16205e5c12b0Sopenharmony_ci } 16215e5c12b0Sopenharmony_ci if (!IS_VALID_NID(sbi, le32_to_cpu(dentry[i].ino))) { 16225e5c12b0Sopenharmony_ci ASSERT_MSG("Bad dentry 0x%x with invalid NID/ino 0x%x", 16235e5c12b0Sopenharmony_ci i, le32_to_cpu(dentry[i].ino)); 16245e5c12b0Sopenharmony_ci if (c.fix_on) { 16255e5c12b0Sopenharmony_ci FIX_MSG("Clear bad dentry 0x%x with bad ino 0x%x", 16265e5c12b0Sopenharmony_ci i, le32_to_cpu(dentry[i].ino)); 16275e5c12b0Sopenharmony_ci test_and_clear_bit_le(i, bitmap); 16285e5c12b0Sopenharmony_ci fixed = 1; 16295e5c12b0Sopenharmony_ci } 16305e5c12b0Sopenharmony_ci i++; 16315e5c12b0Sopenharmony_ci continue; 16325e5c12b0Sopenharmony_ci } 16335e5c12b0Sopenharmony_ci 16345e5c12b0Sopenharmony_ci ftype = dentry[i].file_type; 16355e5c12b0Sopenharmony_ci if ((ftype <= F2FS_FT_UNKNOWN || ftype > F2FS_FT_LAST_FILE_TYPE)) { 16365e5c12b0Sopenharmony_ci ASSERT_MSG("Bad dentry 0x%x with unexpected ftype 0x%x", 16375e5c12b0Sopenharmony_ci le32_to_cpu(dentry[i].ino), ftype); 16385e5c12b0Sopenharmony_ci if (c.fix_on) { 16395e5c12b0Sopenharmony_ci FIX_MSG("Clear bad dentry 0x%x with bad ftype 0x%x", 16405e5c12b0Sopenharmony_ci i, ftype); 16415e5c12b0Sopenharmony_ci test_and_clear_bit_le(i, bitmap); 16425e5c12b0Sopenharmony_ci fixed = 1; 16435e5c12b0Sopenharmony_ci } 16445e5c12b0Sopenharmony_ci i++; 16455e5c12b0Sopenharmony_ci continue; 16465e5c12b0Sopenharmony_ci } 16475e5c12b0Sopenharmony_ci 16485e5c12b0Sopenharmony_ci name_len = le16_to_cpu(dentry[i].name_len); 16495e5c12b0Sopenharmony_ci 16505e5c12b0Sopenharmony_ci if (name_len == 0 || name_len > F2FS_NAME_LEN) { 16515e5c12b0Sopenharmony_ci ASSERT_MSG("Bad dentry 0x%x with invalid name_len", i); 16525e5c12b0Sopenharmony_ci if (c.fix_on) { 16535e5c12b0Sopenharmony_ci FIX_MSG("Clear bad dentry 0x%x", i); 16545e5c12b0Sopenharmony_ci test_and_clear_bit_le(i, bitmap); 16555e5c12b0Sopenharmony_ci fixed = 1; 16565e5c12b0Sopenharmony_ci } 16575e5c12b0Sopenharmony_ci i++; 16585e5c12b0Sopenharmony_ci continue; 16595e5c12b0Sopenharmony_ci } 16605e5c12b0Sopenharmony_ci name = calloc(name_len + 1, 1); 16615e5c12b0Sopenharmony_ci ASSERT(name); 16625e5c12b0Sopenharmony_ci 16635e5c12b0Sopenharmony_ci memcpy(name, filenames[i], name_len); 16645e5c12b0Sopenharmony_ci slots = (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN; 16655e5c12b0Sopenharmony_ci 16665e5c12b0Sopenharmony_ci /* Becareful. 'dentry.file_type' is not imode. */ 16675e5c12b0Sopenharmony_ci if (ftype == F2FS_FT_DIR) { 16685e5c12b0Sopenharmony_ci if ((name[0] == '.' && name_len == 1) || 16695e5c12b0Sopenharmony_ci (name[0] == '.' && name[1] == '.' && 16705e5c12b0Sopenharmony_ci name_len == 2)) { 16715e5c12b0Sopenharmony_ci ret = __chk_dots_dentries(sbi, casefolded, &dentry[i], 16725e5c12b0Sopenharmony_ci child, name, name_len, &filenames[i], 16735e5c12b0Sopenharmony_ci enc_name); 16745e5c12b0Sopenharmony_ci switch (ret) { 16755e5c12b0Sopenharmony_ci case 1: 16765e5c12b0Sopenharmony_ci fixed = 1; 16775e5c12b0Sopenharmony_ci fallthrough; 16785e5c12b0Sopenharmony_ci case 0: 16795e5c12b0Sopenharmony_ci child->dots++; 16805e5c12b0Sopenharmony_ci break; 16815e5c12b0Sopenharmony_ci } 16825e5c12b0Sopenharmony_ci 16835e5c12b0Sopenharmony_ci if (child->dots > 2) { 16845e5c12b0Sopenharmony_ci ASSERT_MSG("More than one '.' or '..', should delete the extra one\n"); 16855e5c12b0Sopenharmony_ci nullify_dentry(&dentry[i], i, 16865e5c12b0Sopenharmony_ci &filenames[i], &bitmap); 16875e5c12b0Sopenharmony_ci child->dots--; 16885e5c12b0Sopenharmony_ci fixed = 1; 16895e5c12b0Sopenharmony_ci } 16905e5c12b0Sopenharmony_ci 16915e5c12b0Sopenharmony_ci i++; 16925e5c12b0Sopenharmony_ci free(name); 16935e5c12b0Sopenharmony_ci continue; 16945e5c12b0Sopenharmony_ci } 16955e5c12b0Sopenharmony_ci } 16965e5c12b0Sopenharmony_ci 16975e5c12b0Sopenharmony_ci if (f2fs_check_hash_code(get_encoding(sbi), casefolded, dentry + i, name, name_len, enc_name)) 16985e5c12b0Sopenharmony_ci fixed = 1; 16995e5c12b0Sopenharmony_ci 17005e5c12b0Sopenharmony_ci pretty_print_filename(name, name_len, en, enc_name); 17015e5c12b0Sopenharmony_ci 17025e5c12b0Sopenharmony_ci if (max == NR_DENTRY_IN_BLOCK) { 17035e5c12b0Sopenharmony_ci ret = f2fs_check_dirent_position(dentry + i, en, 17045e5c12b0Sopenharmony_ci child->pgofs, child->dir_level, 17055e5c12b0Sopenharmony_ci child->p_ino); 17065e5c12b0Sopenharmony_ci if (ret) { 17075e5c12b0Sopenharmony_ci if (c.fix_on) { 17085e5c12b0Sopenharmony_ci FIX_MSG("Clear bad dentry 0x%x", i); 17095e5c12b0Sopenharmony_ci test_and_clear_bit_le(i, bitmap); 17105e5c12b0Sopenharmony_ci fixed = 1; 17115e5c12b0Sopenharmony_ci } 17125e5c12b0Sopenharmony_ci i++; 17135e5c12b0Sopenharmony_ci free(name); 17145e5c12b0Sopenharmony_ci continue; 17155e5c12b0Sopenharmony_ci } 17165e5c12b0Sopenharmony_ci } 17175e5c12b0Sopenharmony_ci 17185e5c12b0Sopenharmony_ci DBG(1, "[%3u]-[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n", 17195e5c12b0Sopenharmony_ci fsck->dentry_depth, i, en, name_len, 17205e5c12b0Sopenharmony_ci le32_to_cpu(dentry[i].ino), 17215e5c12b0Sopenharmony_ci dentry[i].file_type); 17225e5c12b0Sopenharmony_ci 17235e5c12b0Sopenharmony_ci print_dentry(sbi, name, bitmap, 17245e5c12b0Sopenharmony_ci dentry, max, i, last_blk, enc_name); 17255e5c12b0Sopenharmony_ci 17265e5c12b0Sopenharmony_ci blk_cnt = 1; 17275e5c12b0Sopenharmony_ci cbc.cnt = 0; 17285e5c12b0Sopenharmony_ci cbc.cheader_pgofs = CHEADER_PGOFS_NONE; 17295e5c12b0Sopenharmony_ci child->i_namelen = name_len; 17305e5c12b0Sopenharmony_ci ret = fsck_chk_node_blk(sbi, 17315e5c12b0Sopenharmony_ci NULL, le32_to_cpu(dentry[i].ino), 17325e5c12b0Sopenharmony_ci ftype, TYPE_INODE, &blk_cnt, &cbc, child); 17335e5c12b0Sopenharmony_ci 17345e5c12b0Sopenharmony_ci if (ret && c.fix_on) { 17355e5c12b0Sopenharmony_ci int j; 17365e5c12b0Sopenharmony_ci 17375e5c12b0Sopenharmony_ci for (j = 0; j < slots; j++) 17385e5c12b0Sopenharmony_ci test_and_clear_bit_le(i + j, bitmap); 17395e5c12b0Sopenharmony_ci FIX_MSG("Unlink [0x%x] - %s len[0x%x], type[0x%x]", 17405e5c12b0Sopenharmony_ci le32_to_cpu(dentry[i].ino), 17415e5c12b0Sopenharmony_ci en, name_len, 17425e5c12b0Sopenharmony_ci dentry[i].file_type); 17435e5c12b0Sopenharmony_ci fixed = 1; 17445e5c12b0Sopenharmony_ci } else if (ret == 0) { 17455e5c12b0Sopenharmony_ci if (ftype == F2FS_FT_DIR) 17465e5c12b0Sopenharmony_ci child->links++; 17475e5c12b0Sopenharmony_ci dentries++; 17485e5c12b0Sopenharmony_ci child->files++; 17495e5c12b0Sopenharmony_ci } 17505e5c12b0Sopenharmony_ci 17515e5c12b0Sopenharmony_ci i += slots; 17525e5c12b0Sopenharmony_ci free(name); 17535e5c12b0Sopenharmony_ci } 17545e5c12b0Sopenharmony_ci return fixed ? -1 : dentries; 17555e5c12b0Sopenharmony_ci} 17565e5c12b0Sopenharmony_ci 17575e5c12b0Sopenharmony_ciint fsck_chk_inline_dentries(struct f2fs_sb_info *sbi, 17585e5c12b0Sopenharmony_ci struct f2fs_node *node_blk, struct child_info *child) 17595e5c12b0Sopenharmony_ci{ 17605e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 17615e5c12b0Sopenharmony_ci struct f2fs_dentry *cur_dentry = fsck->dentry_end; 17625e5c12b0Sopenharmony_ci struct f2fs_dentry *new_dentry; 17635e5c12b0Sopenharmony_ci struct f2fs_dentry_ptr d; 17645e5c12b0Sopenharmony_ci void *inline_dentry; 17655e5c12b0Sopenharmony_ci int dentries; 17665e5c12b0Sopenharmony_ci 17675e5c12b0Sopenharmony_ci inline_dentry = inline_data_addr(node_blk); 17685e5c12b0Sopenharmony_ci ASSERT(inline_dentry != NULL); 17695e5c12b0Sopenharmony_ci 17705e5c12b0Sopenharmony_ci make_dentry_ptr(&d, node_blk, inline_dentry, 2); 17715e5c12b0Sopenharmony_ci 17725e5c12b0Sopenharmony_ci fsck->dentry_depth++; 17735e5c12b0Sopenharmony_ci new_dentry = calloc(sizeof(struct f2fs_dentry), 1); 17745e5c12b0Sopenharmony_ci ASSERT(new_dentry != NULL); 17755e5c12b0Sopenharmony_ci 17765e5c12b0Sopenharmony_ci new_dentry->depth = fsck->dentry_depth; 17775e5c12b0Sopenharmony_ci memcpy(new_dentry->name, child->p_name, F2FS_NAME_LEN); 17785e5c12b0Sopenharmony_ci cur_dentry->next = new_dentry; 17795e5c12b0Sopenharmony_ci fsck->dentry_end = new_dentry; 17805e5c12b0Sopenharmony_ci 17815e5c12b0Sopenharmony_ci dentries = __chk_dentries(sbi, IS_CASEFOLDED(&node_blk->i), child, 17825e5c12b0Sopenharmony_ci d.bitmap, d.dentry, d.filename, d.max, 1, 17835e5c12b0Sopenharmony_ci file_is_encrypt(&node_blk->i));// pass through 17845e5c12b0Sopenharmony_ci if (dentries < 0) { 17855e5c12b0Sopenharmony_ci DBG(1, "[%3d] Inline Dentry Block Fixed hash_codes\n\n", 17865e5c12b0Sopenharmony_ci fsck->dentry_depth); 17875e5c12b0Sopenharmony_ci } else { 17885e5c12b0Sopenharmony_ci DBG(1, "[%3d] Inline Dentry Block Done : " 17895e5c12b0Sopenharmony_ci "dentries:%d in %d slots (len:%d)\n\n", 17905e5c12b0Sopenharmony_ci fsck->dentry_depth, dentries, 17915e5c12b0Sopenharmony_ci d.max, F2FS_NAME_LEN); 17925e5c12b0Sopenharmony_ci } 17935e5c12b0Sopenharmony_ci fsck->dentry = cur_dentry; 17945e5c12b0Sopenharmony_ci fsck->dentry_end = cur_dentry; 17955e5c12b0Sopenharmony_ci cur_dentry->next = NULL; 17965e5c12b0Sopenharmony_ci free(new_dentry); 17975e5c12b0Sopenharmony_ci fsck->dentry_depth--; 17985e5c12b0Sopenharmony_ci return dentries; 17995e5c12b0Sopenharmony_ci} 18005e5c12b0Sopenharmony_ci 18015e5c12b0Sopenharmony_ciint fsck_chk_dentry_blk(struct f2fs_sb_info *sbi, int casefolded, u32 blk_addr, 18025e5c12b0Sopenharmony_ci struct child_info *child, int last_blk, int enc_name) 18035e5c12b0Sopenharmony_ci{ 18045e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 18055e5c12b0Sopenharmony_ci struct f2fs_dentry_block *de_blk; 18065e5c12b0Sopenharmony_ci struct f2fs_dentry *cur_dentry = fsck->dentry_end; 18075e5c12b0Sopenharmony_ci struct f2fs_dentry *new_dentry; 18085e5c12b0Sopenharmony_ci int dentries, ret; 18095e5c12b0Sopenharmony_ci 18105e5c12b0Sopenharmony_ci de_blk = (struct f2fs_dentry_block *)calloc(BLOCK_SZ, 1); 18115e5c12b0Sopenharmony_ci ASSERT(de_blk != NULL); 18125e5c12b0Sopenharmony_ci 18135e5c12b0Sopenharmony_ci ret = dev_read_block(de_blk, blk_addr); 18145e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 18155e5c12b0Sopenharmony_ci 18165e5c12b0Sopenharmony_ci fsck->dentry_depth++; 18175e5c12b0Sopenharmony_ci new_dentry = calloc(sizeof(struct f2fs_dentry), 1); 18185e5c12b0Sopenharmony_ci ASSERT(new_dentry != NULL); 18195e5c12b0Sopenharmony_ci new_dentry->depth = fsck->dentry_depth; 18205e5c12b0Sopenharmony_ci memcpy(new_dentry->name, child->p_name, F2FS_NAME_LEN); 18215e5c12b0Sopenharmony_ci cur_dentry->next = new_dentry; 18225e5c12b0Sopenharmony_ci fsck->dentry_end = new_dentry; 18235e5c12b0Sopenharmony_ci 18245e5c12b0Sopenharmony_ci dentries = __chk_dentries(sbi, casefolded, child, 18255e5c12b0Sopenharmony_ci de_blk->dentry_bitmap, 18265e5c12b0Sopenharmony_ci de_blk->dentry, de_blk->filename, 18275e5c12b0Sopenharmony_ci NR_DENTRY_IN_BLOCK, last_blk, enc_name); 18285e5c12b0Sopenharmony_ci 18295e5c12b0Sopenharmony_ci if (dentries < 0 && f2fs_dev_is_writable()) { 18305e5c12b0Sopenharmony_ci ret = dev_write_block(de_blk, blk_addr); 18315e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 18325e5c12b0Sopenharmony_ci DBG(1, "[%3d] Dentry Block [0x%x] Fixed hash_codes\n\n", 18335e5c12b0Sopenharmony_ci fsck->dentry_depth, blk_addr); 18345e5c12b0Sopenharmony_ci } else { 18355e5c12b0Sopenharmony_ci DBG(1, "[%3d] Dentry Block [0x%x] Done : " 18365e5c12b0Sopenharmony_ci "dentries:%d in %d slots (len:%d)\n\n", 18375e5c12b0Sopenharmony_ci fsck->dentry_depth, blk_addr, dentries, 18385e5c12b0Sopenharmony_ci NR_DENTRY_IN_BLOCK, F2FS_NAME_LEN); 18395e5c12b0Sopenharmony_ci } 18405e5c12b0Sopenharmony_ci fsck->dentry = cur_dentry; 18415e5c12b0Sopenharmony_ci fsck->dentry_end = cur_dentry; 18425e5c12b0Sopenharmony_ci cur_dentry->next = NULL; 18435e5c12b0Sopenharmony_ci free(new_dentry); 18445e5c12b0Sopenharmony_ci fsck->dentry_depth--; 18455e5c12b0Sopenharmony_ci free(de_blk); 18465e5c12b0Sopenharmony_ci return 0; 18475e5c12b0Sopenharmony_ci} 18485e5c12b0Sopenharmony_ci 18495e5c12b0Sopenharmony_ciint fsck_chk_data_blk(struct f2fs_sb_info *sbi, int casefolded, 18505e5c12b0Sopenharmony_ci u32 blk_addr, struct child_info *child, int last_blk, 18515e5c12b0Sopenharmony_ci enum FILE_TYPE ftype, u32 parent_nid, u16 idx_in_node, u8 ver, 18525e5c12b0Sopenharmony_ci int enc_name) 18535e5c12b0Sopenharmony_ci{ 18545e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 18555e5c12b0Sopenharmony_ci 18565e5c12b0Sopenharmony_ci /* Is it reserved block? */ 18575e5c12b0Sopenharmony_ci if (blk_addr == NEW_ADDR) { 18585e5c12b0Sopenharmony_ci fsck->chk.valid_blk_cnt++; 18595e5c12b0Sopenharmony_ci return 0; 18605e5c12b0Sopenharmony_ci } 18615e5c12b0Sopenharmony_ci 18625e5c12b0Sopenharmony_ci if (!IS_VALID_BLK_ADDR(sbi, blk_addr)) { 18635e5c12b0Sopenharmony_ci ASSERT_MSG("blkaddress is not valid. [0x%x]", blk_addr); 18645e5c12b0Sopenharmony_ci return -EINVAL; 18655e5c12b0Sopenharmony_ci } 18665e5c12b0Sopenharmony_ci 18675e5c12b0Sopenharmony_ci if (is_valid_ssa_data_blk(sbi, blk_addr, parent_nid, 18685e5c12b0Sopenharmony_ci idx_in_node, ver)) { 18695e5c12b0Sopenharmony_ci ASSERT_MSG("summary data block is not valid. [0x%x]", 18705e5c12b0Sopenharmony_ci parent_nid); 18715e5c12b0Sopenharmony_ci return -EINVAL; 18725e5c12b0Sopenharmony_ci } 18735e5c12b0Sopenharmony_ci 18745e5c12b0Sopenharmony_ci if (f2fs_test_sit_bitmap(sbi, blk_addr) == 0) 18755e5c12b0Sopenharmony_ci ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]", blk_addr); 18765e5c12b0Sopenharmony_ci 18775e5c12b0Sopenharmony_ci if (f2fs_test_main_bitmap(sbi, blk_addr) != 0) 18785e5c12b0Sopenharmony_ci ASSERT_MSG("Duplicated data [0x%x]. pnid[0x%x] idx[0x%x]", 18795e5c12b0Sopenharmony_ci blk_addr, parent_nid, idx_in_node); 18805e5c12b0Sopenharmony_ci 18815e5c12b0Sopenharmony_ci fsck->chk.valid_blk_cnt++; 18825e5c12b0Sopenharmony_ci 18835e5c12b0Sopenharmony_ci if (ftype == F2FS_FT_DIR) { 18845e5c12b0Sopenharmony_ci f2fs_set_main_bitmap(sbi, blk_addr, CURSEG_HOT_DATA); 18855e5c12b0Sopenharmony_ci return fsck_chk_dentry_blk(sbi, casefolded, blk_addr, child, 18865e5c12b0Sopenharmony_ci last_blk, enc_name); 18875e5c12b0Sopenharmony_ci } else { 18885e5c12b0Sopenharmony_ci f2fs_set_main_bitmap(sbi, blk_addr, CURSEG_WARM_DATA); 18895e5c12b0Sopenharmony_ci } 18905e5c12b0Sopenharmony_ci return 0; 18915e5c12b0Sopenharmony_ci} 18925e5c12b0Sopenharmony_ci 18935e5c12b0Sopenharmony_ciint fsck_chk_orphan_node(struct f2fs_sb_info *sbi) 18945e5c12b0Sopenharmony_ci{ 18955e5c12b0Sopenharmony_ci u32 blk_cnt = 0; 18965e5c12b0Sopenharmony_ci struct f2fs_compr_blk_cnt cbc = {0, CHEADER_PGOFS_NONE}; 18975e5c12b0Sopenharmony_ci block_t start_blk, orphan_blkaddr, i, j; 18985e5c12b0Sopenharmony_ci struct f2fs_orphan_block *orphan_blk, *new_blk; 18995e5c12b0Sopenharmony_ci struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 19005e5c12b0Sopenharmony_ci u32 entry_count; 19015e5c12b0Sopenharmony_ci 19025e5c12b0Sopenharmony_ci if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG)) 19035e5c12b0Sopenharmony_ci return 0; 19045e5c12b0Sopenharmony_ci 19055e5c12b0Sopenharmony_ci start_blk = __start_cp_addr(sbi) + 1 + get_sb(cp_payload); 19065e5c12b0Sopenharmony_ci orphan_blkaddr = __start_sum_addr(sbi) - 1 - get_sb(cp_payload); 19075e5c12b0Sopenharmony_ci 19085e5c12b0Sopenharmony_ci f2fs_ra_meta_pages(sbi, start_blk, orphan_blkaddr, META_CP); 19095e5c12b0Sopenharmony_ci 19105e5c12b0Sopenharmony_ci orphan_blk = calloc(BLOCK_SZ, 1); 19115e5c12b0Sopenharmony_ci ASSERT(orphan_blk); 19125e5c12b0Sopenharmony_ci 19135e5c12b0Sopenharmony_ci new_blk = calloc(BLOCK_SZ, 1); 19145e5c12b0Sopenharmony_ci ASSERT(new_blk); 19155e5c12b0Sopenharmony_ci 19165e5c12b0Sopenharmony_ci for (i = 0; i < orphan_blkaddr; i++) { 19175e5c12b0Sopenharmony_ci int ret = dev_read_block(orphan_blk, start_blk + i); 19185e5c12b0Sopenharmony_ci u32 new_entry_count = 0; 19195e5c12b0Sopenharmony_ci 19205e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 19215e5c12b0Sopenharmony_ci entry_count = le32_to_cpu(orphan_blk->entry_count); 19225e5c12b0Sopenharmony_ci 19235e5c12b0Sopenharmony_ci for (j = 0; j < entry_count; j++) { 19245e5c12b0Sopenharmony_ci nid_t ino = le32_to_cpu(orphan_blk->ino[j]); 19255e5c12b0Sopenharmony_ci DBG(1, "[%3d] ino [0x%x]\n", i, ino); 19265e5c12b0Sopenharmony_ci struct node_info ni; 19275e5c12b0Sopenharmony_ci blk_cnt = 1; 19285e5c12b0Sopenharmony_ci cbc.cnt = 0; 19295e5c12b0Sopenharmony_ci cbc.cheader_pgofs = CHEADER_PGOFS_NONE; 19305e5c12b0Sopenharmony_ci 19315e5c12b0Sopenharmony_ci if (c.preen_mode == PREEN_MODE_1 && !c.fix_on) { 19325e5c12b0Sopenharmony_ci get_node_info(sbi, ino, &ni); 19335e5c12b0Sopenharmony_ci if (!IS_VALID_NID(sbi, ino) || 19345e5c12b0Sopenharmony_ci !IS_VALID_BLK_ADDR(sbi, ni.blk_addr)) { 19355e5c12b0Sopenharmony_ci free(orphan_blk); 19365e5c12b0Sopenharmony_ci free(new_blk); 19375e5c12b0Sopenharmony_ci return -EINVAL; 19385e5c12b0Sopenharmony_ci } 19395e5c12b0Sopenharmony_ci 19405e5c12b0Sopenharmony_ci continue; 19415e5c12b0Sopenharmony_ci } 19425e5c12b0Sopenharmony_ci 19435e5c12b0Sopenharmony_ci ret = fsck_chk_node_blk(sbi, NULL, ino, 19445e5c12b0Sopenharmony_ci F2FS_FT_ORPHAN, TYPE_INODE, &blk_cnt, 19455e5c12b0Sopenharmony_ci &cbc, NULL); 19465e5c12b0Sopenharmony_ci if (!ret) 19475e5c12b0Sopenharmony_ci new_blk->ino[new_entry_count++] = 19485e5c12b0Sopenharmony_ci orphan_blk->ino[j]; 19495e5c12b0Sopenharmony_ci else if (ret && c.fix_on) 19505e5c12b0Sopenharmony_ci FIX_MSG("[0x%x] remove from orphan list", ino); 19515e5c12b0Sopenharmony_ci else if (ret) 19525e5c12b0Sopenharmony_ci ASSERT_MSG("[0x%x] wrong orphan inode", ino); 19535e5c12b0Sopenharmony_ci } 19545e5c12b0Sopenharmony_ci if (f2fs_dev_is_writable() && c.fix_on && 19555e5c12b0Sopenharmony_ci entry_count != new_entry_count) { 19565e5c12b0Sopenharmony_ci new_blk->entry_count = cpu_to_le32(new_entry_count); 19575e5c12b0Sopenharmony_ci ret = dev_write_block(new_blk, start_blk + i); 19585e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 19595e5c12b0Sopenharmony_ci } 19605e5c12b0Sopenharmony_ci memset(orphan_blk, 0, BLOCK_SZ); 19615e5c12b0Sopenharmony_ci memset(new_blk, 0, BLOCK_SZ); 19625e5c12b0Sopenharmony_ci } 19635e5c12b0Sopenharmony_ci free(orphan_blk); 19645e5c12b0Sopenharmony_ci free(new_blk); 19655e5c12b0Sopenharmony_ci 19665e5c12b0Sopenharmony_ci return 0; 19675e5c12b0Sopenharmony_ci} 19685e5c12b0Sopenharmony_ci 19695e5c12b0Sopenharmony_ciint fsck_chk_quota_node(struct f2fs_sb_info *sbi) 19705e5c12b0Sopenharmony_ci{ 19715e5c12b0Sopenharmony_ci struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 19725e5c12b0Sopenharmony_ci enum quota_type qtype; 19735e5c12b0Sopenharmony_ci int ret = 0; 19745e5c12b0Sopenharmony_ci u32 blk_cnt = 0; 19755e5c12b0Sopenharmony_ci struct f2fs_compr_blk_cnt cbc = {0, CHEADER_PGOFS_NONE}; 19765e5c12b0Sopenharmony_ci 19775e5c12b0Sopenharmony_ci for (qtype = 0; qtype < F2FS_MAX_QUOTAS; qtype++) { 19785e5c12b0Sopenharmony_ci cur_qtype = qtype; 19795e5c12b0Sopenharmony_ci if (sb->qf_ino[qtype] == 0) 19805e5c12b0Sopenharmony_ci continue; 19815e5c12b0Sopenharmony_ci nid_t ino = QUOTA_INO(sb, qtype); 19825e5c12b0Sopenharmony_ci struct node_info ni; 19835e5c12b0Sopenharmony_ci 19845e5c12b0Sopenharmony_ci DBG(1, "qtype [%d] ino [0x%x]\n", qtype, ino); 19855e5c12b0Sopenharmony_ci blk_cnt = 1; 19865e5c12b0Sopenharmony_ci cbc.cnt = 0; 19875e5c12b0Sopenharmony_ci cbc.cheader_pgofs = CHEADER_PGOFS_NONE; 19885e5c12b0Sopenharmony_ci 19895e5c12b0Sopenharmony_ci if (c.preen_mode == PREEN_MODE_1 && !c.fix_on) { 19905e5c12b0Sopenharmony_ci get_node_info(sbi, ino, &ni); 19915e5c12b0Sopenharmony_ci if (!IS_VALID_NID(sbi, ino) || 19925e5c12b0Sopenharmony_ci !IS_VALID_BLK_ADDR(sbi, ni.blk_addr)) 19935e5c12b0Sopenharmony_ci return -EINVAL; 19945e5c12b0Sopenharmony_ci continue; 19955e5c12b0Sopenharmony_ci } 19965e5c12b0Sopenharmony_ci ret = fsck_chk_node_blk(sbi, NULL, ino, 19975e5c12b0Sopenharmony_ci F2FS_FT_REG_FILE, TYPE_INODE, &blk_cnt, 19985e5c12b0Sopenharmony_ci &cbc, NULL); 19995e5c12b0Sopenharmony_ci if (ret) { 20005e5c12b0Sopenharmony_ci ASSERT_MSG("wrong quota inode, qtype [%d] ino [0x%x]", 20015e5c12b0Sopenharmony_ci qtype, ino); 20025e5c12b0Sopenharmony_ci qf_szchk_type[qtype] = QF_SZCHK_ERR; 20035e5c12b0Sopenharmony_ci if (c.fix_on) 20045e5c12b0Sopenharmony_ci f2fs_rebuild_qf_inode(sbi, qtype); 20055e5c12b0Sopenharmony_ci } 20065e5c12b0Sopenharmony_ci } 20075e5c12b0Sopenharmony_ci cur_qtype = -1; 20085e5c12b0Sopenharmony_ci return ret; 20095e5c12b0Sopenharmony_ci} 20105e5c12b0Sopenharmony_ci 20115e5c12b0Sopenharmony_ciint fsck_chk_quota_files(struct f2fs_sb_info *sbi) 20125e5c12b0Sopenharmony_ci{ 20135e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 20145e5c12b0Sopenharmony_ci struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 20155e5c12b0Sopenharmony_ci enum quota_type qtype; 20165e5c12b0Sopenharmony_ci f2fs_ino_t ino; 20175e5c12b0Sopenharmony_ci int ret = 0; 20185e5c12b0Sopenharmony_ci int needs_writeout; 20195e5c12b0Sopenharmony_ci 20205e5c12b0Sopenharmony_ci /* Return if quota feature is disabled */ 20215e5c12b0Sopenharmony_ci if (!fsck->qctx) 20225e5c12b0Sopenharmony_ci return 0; 20235e5c12b0Sopenharmony_ci 20245e5c12b0Sopenharmony_ci for (qtype = 0; qtype < F2FS_MAX_QUOTAS; qtype++) { 20255e5c12b0Sopenharmony_ci ino = sb->qf_ino[qtype]; 20265e5c12b0Sopenharmony_ci if (!ino) 20275e5c12b0Sopenharmony_ci continue; 20285e5c12b0Sopenharmony_ci 20295e5c12b0Sopenharmony_ci DBG(1, "Checking Quota file ([%3d] ino [0x%x])\n", qtype, ino); 20305e5c12b0Sopenharmony_ci needs_writeout = 0; 20315e5c12b0Sopenharmony_ci ret = quota_compare_and_update(sbi, qtype, &needs_writeout, 20325e5c12b0Sopenharmony_ci c.preserve_limits); 20335e5c12b0Sopenharmony_ci if (ret == 0 && needs_writeout == 0) { 20345e5c12b0Sopenharmony_ci DBG(1, "OK\n"); 20355e5c12b0Sopenharmony_ci continue; 20365e5c12b0Sopenharmony_ci } 20375e5c12b0Sopenharmony_ci 20385e5c12b0Sopenharmony_ci /* Something is wrong */ 20395e5c12b0Sopenharmony_ci if (c.fix_on) { 20405e5c12b0Sopenharmony_ci DBG(0, "Fixing Quota file ([%3d] ino [0x%x])\n", 20415e5c12b0Sopenharmony_ci qtype, ino); 20425e5c12b0Sopenharmony_ci f2fs_filesize_update(sbi, ino, 0); 20435e5c12b0Sopenharmony_ci ret = quota_write_inode(sbi, qtype); 20445e5c12b0Sopenharmony_ci if (!ret) { 20455e5c12b0Sopenharmony_ci c.quota_fixed = true; 20465e5c12b0Sopenharmony_ci DBG(1, "OK\n"); 20475e5c12b0Sopenharmony_ci } else { 20485e5c12b0Sopenharmony_ci ASSERT_MSG("Unable to write quota file"); 20495e5c12b0Sopenharmony_ci } 20505e5c12b0Sopenharmony_ci } else { 20515e5c12b0Sopenharmony_ci ASSERT_MSG("Quota file is missing or invalid" 20525e5c12b0Sopenharmony_ci " quota file content found."); 20535e5c12b0Sopenharmony_ci } 20545e5c12b0Sopenharmony_ci } 20555e5c12b0Sopenharmony_ci return ret; 20565e5c12b0Sopenharmony_ci} 20575e5c12b0Sopenharmony_ci 20585e5c12b0Sopenharmony_ciint fsck_chk_meta(struct f2fs_sb_info *sbi) 20595e5c12b0Sopenharmony_ci{ 20605e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 20615e5c12b0Sopenharmony_ci struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); 20625e5c12b0Sopenharmony_ci struct seg_entry *se; 20635e5c12b0Sopenharmony_ci unsigned int sit_valid_segs = 0, sit_node_blks = 0; 20645e5c12b0Sopenharmony_ci unsigned int i; 20655e5c12b0Sopenharmony_ci 20665e5c12b0Sopenharmony_ci /* 1. check sit usage with CP: curseg is lost? */ 20675e5c12b0Sopenharmony_ci for (i = 0; i < MAIN_SEGS(sbi); i++) { 20685e5c12b0Sopenharmony_ci se = get_seg_entry(sbi, i); 20695e5c12b0Sopenharmony_ci if (se->valid_blocks != 0) 20705e5c12b0Sopenharmony_ci sit_valid_segs++; 20715e5c12b0Sopenharmony_ci else if (IS_CUR_SEGNO(sbi, i)) { 20725e5c12b0Sopenharmony_ci /* curseg has not been written back to device */ 20735e5c12b0Sopenharmony_ci MSG(1, "\tInfo: curseg %u is counted in valid segs\n", i); 20745e5c12b0Sopenharmony_ci sit_valid_segs++; 20755e5c12b0Sopenharmony_ci } 20765e5c12b0Sopenharmony_ci if (IS_NODESEG(se->type)) 20775e5c12b0Sopenharmony_ci sit_node_blks += se->valid_blocks; 20785e5c12b0Sopenharmony_ci } 20795e5c12b0Sopenharmony_ci if (fsck->chk.sit_free_segs + sit_valid_segs != 20805e5c12b0Sopenharmony_ci get_usable_seg_count(sbi)) { 20815e5c12b0Sopenharmony_ci ASSERT_MSG("SIT usage does not match: sit_free_segs %u, " 20825e5c12b0Sopenharmony_ci "sit_valid_segs %u, total_segs %u", 20835e5c12b0Sopenharmony_ci fsck->chk.sit_free_segs, sit_valid_segs, 20845e5c12b0Sopenharmony_ci get_usable_seg_count(sbi)); 20855e5c12b0Sopenharmony_ci return -EINVAL; 20865e5c12b0Sopenharmony_ci } 20875e5c12b0Sopenharmony_ci 20885e5c12b0Sopenharmony_ci /* 2. check node count */ 20895e5c12b0Sopenharmony_ci if (fsck->chk.valid_nat_entry_cnt != sit_node_blks) { 20905e5c12b0Sopenharmony_ci ASSERT_MSG("node count does not match: valid_nat_entry_cnt %u," 20915e5c12b0Sopenharmony_ci " sit_node_blks %u", 20925e5c12b0Sopenharmony_ci fsck->chk.valid_nat_entry_cnt, sit_node_blks); 20935e5c12b0Sopenharmony_ci return -EINVAL; 20945e5c12b0Sopenharmony_ci } 20955e5c12b0Sopenharmony_ci 20965e5c12b0Sopenharmony_ci /* 3. check SIT with CP */ 20975e5c12b0Sopenharmony_ci if (fsck->chk.sit_free_segs != le32_to_cpu(cp->free_segment_count)) { 20985e5c12b0Sopenharmony_ci ASSERT_MSG("free segs does not match: sit_free_segs %u, " 20995e5c12b0Sopenharmony_ci "free_segment_count %u", 21005e5c12b0Sopenharmony_ci fsck->chk.sit_free_segs, 21015e5c12b0Sopenharmony_ci le32_to_cpu(cp->free_segment_count)); 21025e5c12b0Sopenharmony_ci return -EINVAL; 21035e5c12b0Sopenharmony_ci } 21045e5c12b0Sopenharmony_ci 21055e5c12b0Sopenharmony_ci /* 4. check NAT with CP */ 21065e5c12b0Sopenharmony_ci if (fsck->chk.valid_nat_entry_cnt != 21075e5c12b0Sopenharmony_ci le32_to_cpu(cp->valid_node_count)) { 21085e5c12b0Sopenharmony_ci ASSERT_MSG("valid node does not match: valid_nat_entry_cnt %u," 21095e5c12b0Sopenharmony_ci " valid_node_count %u", 21105e5c12b0Sopenharmony_ci fsck->chk.valid_nat_entry_cnt, 21115e5c12b0Sopenharmony_ci le32_to_cpu(cp->valid_node_count)); 21125e5c12b0Sopenharmony_ci return -EINVAL; 21135e5c12b0Sopenharmony_ci } 21145e5c12b0Sopenharmony_ci 21155e5c12b0Sopenharmony_ci /* 4. check orphan inode simply */ 21165e5c12b0Sopenharmony_ci if (fsck_chk_orphan_node(sbi)) 21175e5c12b0Sopenharmony_ci return -EINVAL; 21185e5c12b0Sopenharmony_ci 21195e5c12b0Sopenharmony_ci /* 5. check nat entry -- must be done before quota check */ 21205e5c12b0Sopenharmony_ci for (i = 0; i < fsck->nr_nat_entries; i++) { 21215e5c12b0Sopenharmony_ci u32 blk = le32_to_cpu(fsck->entries[i].block_addr); 21225e5c12b0Sopenharmony_ci nid_t ino = le32_to_cpu(fsck->entries[i].ino); 21235e5c12b0Sopenharmony_ci 21245e5c12b0Sopenharmony_ci if (!blk) 21255e5c12b0Sopenharmony_ci /* 21265e5c12b0Sopenharmony_ci * skip entry whose ino is 0, otherwise, we will 21275e5c12b0Sopenharmony_ci * get a negative number by BLKOFF_FROM_MAIN(sbi, blk) 21285e5c12b0Sopenharmony_ci */ 21295e5c12b0Sopenharmony_ci continue; 21305e5c12b0Sopenharmony_ci 21315e5c12b0Sopenharmony_ci if (!IS_VALID_BLK_ADDR(sbi, blk)) { 21325e5c12b0Sopenharmony_ci MSG(0, "\tError: nat entry[ino %u block_addr 0x%x]" 21335e5c12b0Sopenharmony_ci " is in valid\n", 21345e5c12b0Sopenharmony_ci ino, blk); 21355e5c12b0Sopenharmony_ci return -EINVAL; 21365e5c12b0Sopenharmony_ci } 21375e5c12b0Sopenharmony_ci 21385e5c12b0Sopenharmony_ci if (!f2fs_test_sit_bitmap(sbi, blk)) { 21395e5c12b0Sopenharmony_ci MSG(0, "\tError: nat entry[ino %u block_addr 0x%x]" 21405e5c12b0Sopenharmony_ci " not find it in sit_area_bitmap\n", 21415e5c12b0Sopenharmony_ci ino, blk); 21425e5c12b0Sopenharmony_ci return -EINVAL; 21435e5c12b0Sopenharmony_ci } 21445e5c12b0Sopenharmony_ci 21455e5c12b0Sopenharmony_ci if (!IS_VALID_NID(sbi, ino)) { 21465e5c12b0Sopenharmony_ci MSG(0, "\tError: nat_entry->ino %u exceeds the range" 21475e5c12b0Sopenharmony_ci " of nat entries %u\n", 21485e5c12b0Sopenharmony_ci ino, fsck->nr_nat_entries); 21495e5c12b0Sopenharmony_ci return -EINVAL; 21505e5c12b0Sopenharmony_ci } 21515e5c12b0Sopenharmony_ci 21525e5c12b0Sopenharmony_ci if (!f2fs_test_bit(ino, fsck->nat_area_bitmap)) { 21535e5c12b0Sopenharmony_ci MSG(0, "\tError: nat_entry->ino %u is not set in" 21545e5c12b0Sopenharmony_ci " nat_area_bitmap\n", ino); 21555e5c12b0Sopenharmony_ci return -EINVAL; 21565e5c12b0Sopenharmony_ci } 21575e5c12b0Sopenharmony_ci } 21585e5c12b0Sopenharmony_ci 21595e5c12b0Sopenharmony_ci /* 6. check quota inode simply */ 21605e5c12b0Sopenharmony_ci if (fsck_chk_quota_node(sbi)) 21615e5c12b0Sopenharmony_ci return -EINVAL; 21625e5c12b0Sopenharmony_ci 21635e5c12b0Sopenharmony_ci if (fsck->nat_valid_inode_cnt != le32_to_cpu(cp->valid_inode_count)) { 21645e5c12b0Sopenharmony_ci ASSERT_MSG("valid inode does not match: nat_valid_inode_cnt %u," 21655e5c12b0Sopenharmony_ci " valid_inode_count %u", 21665e5c12b0Sopenharmony_ci fsck->nat_valid_inode_cnt, 21675e5c12b0Sopenharmony_ci le32_to_cpu(cp->valid_inode_count)); 21685e5c12b0Sopenharmony_ci return -EINVAL; 21695e5c12b0Sopenharmony_ci } 21705e5c12b0Sopenharmony_ci 21715e5c12b0Sopenharmony_ci return 0; 21725e5c12b0Sopenharmony_ci} 21735e5c12b0Sopenharmony_ci 21745e5c12b0Sopenharmony_civoid fsck_chk_checkpoint(struct f2fs_sb_info *sbi) 21755e5c12b0Sopenharmony_ci{ 21765e5c12b0Sopenharmony_ci struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); 21775e5c12b0Sopenharmony_ci 21785e5c12b0Sopenharmony_ci if (get_cp(ckpt_flags) & CP_LARGE_NAT_BITMAP_FLAG) { 21795e5c12b0Sopenharmony_ci if (get_cp(checksum_offset) != CP_MIN_CHKSUM_OFFSET) { 21805e5c12b0Sopenharmony_ci ASSERT_MSG("Deprecated layout of large_nat_bitmap, " 21815e5c12b0Sopenharmony_ci "chksum_offset:%u", get_cp(checksum_offset)); 21825e5c12b0Sopenharmony_ci c.fix_chksum = 1; 21835e5c12b0Sopenharmony_ci } 21845e5c12b0Sopenharmony_ci } 21855e5c12b0Sopenharmony_ci} 21865e5c12b0Sopenharmony_ci 21875e5c12b0Sopenharmony_civoid fsck_init(struct f2fs_sb_info *sbi) 21885e5c12b0Sopenharmony_ci{ 21895e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 21905e5c12b0Sopenharmony_ci struct f2fs_sm_info *sm_i = SM_I(sbi); 21915e5c12b0Sopenharmony_ci 21925e5c12b0Sopenharmony_ci /* 21935e5c12b0Sopenharmony_ci * We build three bitmap for main/sit/nat so that may check consistency 21945e5c12b0Sopenharmony_ci * of filesystem. 21955e5c12b0Sopenharmony_ci * 1. main_area_bitmap will be used to check whether all blocks of main 21965e5c12b0Sopenharmony_ci * area is used or not. 21975e5c12b0Sopenharmony_ci * 2. nat_area_bitmap has bitmap information of used nid in NAT. 21985e5c12b0Sopenharmony_ci * 3. sit_area_bitmap has bitmap information of used main block. 21995e5c12b0Sopenharmony_ci * At Last sequence, we compare main_area_bitmap with sit_area_bitmap. 22005e5c12b0Sopenharmony_ci */ 22015e5c12b0Sopenharmony_ci fsck->nr_main_blks = sm_i->main_segments << sbi->log_blocks_per_seg; 22025e5c12b0Sopenharmony_ci fsck->main_area_bitmap_sz = (fsck->nr_main_blks + 7) / 8; 22035e5c12b0Sopenharmony_ci fsck->main_area_bitmap = calloc(fsck->main_area_bitmap_sz, 1); 22045e5c12b0Sopenharmony_ci ASSERT(fsck->main_area_bitmap != NULL); 22055e5c12b0Sopenharmony_ci 22065e5c12b0Sopenharmony_ci build_nat_area_bitmap(sbi); 22075e5c12b0Sopenharmony_ci 22085e5c12b0Sopenharmony_ci build_sit_area_bitmap(sbi); 22095e5c12b0Sopenharmony_ci 22105e5c12b0Sopenharmony_ci ASSERT(tree_mark_size != 0); 22115e5c12b0Sopenharmony_ci tree_mark = calloc(tree_mark_size, 1); 22125e5c12b0Sopenharmony_ci ASSERT(tree_mark != NULL); 22135e5c12b0Sopenharmony_ci fsck->dentry = calloc(sizeof(struct f2fs_dentry), 1); 22145e5c12b0Sopenharmony_ci ASSERT(fsck->dentry != NULL); 22155e5c12b0Sopenharmony_ci memcpy(fsck->dentry->name, "/", 1); 22165e5c12b0Sopenharmony_ci fsck->dentry_end = fsck->dentry; 22175e5c12b0Sopenharmony_ci 22185e5c12b0Sopenharmony_ci c.quota_fixed = false; 22195e5c12b0Sopenharmony_ci} 22205e5c12b0Sopenharmony_ci 22215e5c12b0Sopenharmony_cistatic void fix_hard_links(struct f2fs_sb_info *sbi) 22225e5c12b0Sopenharmony_ci{ 22235e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 22245e5c12b0Sopenharmony_ci struct hard_link_node *tmp, *node; 22255e5c12b0Sopenharmony_ci struct f2fs_node *node_blk = NULL; 22265e5c12b0Sopenharmony_ci struct node_info ni; 22275e5c12b0Sopenharmony_ci int ret; 22285e5c12b0Sopenharmony_ci 22295e5c12b0Sopenharmony_ci if (fsck->hard_link_list_head == NULL) 22305e5c12b0Sopenharmony_ci return; 22315e5c12b0Sopenharmony_ci 22325e5c12b0Sopenharmony_ci node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1); 22335e5c12b0Sopenharmony_ci ASSERT(node_blk != NULL); 22345e5c12b0Sopenharmony_ci 22355e5c12b0Sopenharmony_ci node = fsck->hard_link_list_head; 22365e5c12b0Sopenharmony_ci while (node) { 22375e5c12b0Sopenharmony_ci /* Sanity check */ 22385e5c12b0Sopenharmony_ci if (sanity_check_nid(sbi, node->nid, node_blk, 22395e5c12b0Sopenharmony_ci F2FS_FT_MAX, TYPE_INODE, &ni)) 22405e5c12b0Sopenharmony_ci FIX_MSG("Failed to fix, rerun fsck.f2fs"); 22415e5c12b0Sopenharmony_ci 22425e5c12b0Sopenharmony_ci node_blk->i.i_links = cpu_to_le32(node->actual_links); 22435e5c12b0Sopenharmony_ci 22445e5c12b0Sopenharmony_ci FIX_MSG("File: 0x%x i_links= 0x%x -> 0x%x", 22455e5c12b0Sopenharmony_ci node->nid, node->links, node->actual_links); 22465e5c12b0Sopenharmony_ci 22475e5c12b0Sopenharmony_ci ret = dev_write_block(node_blk, ni.blk_addr); 22485e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 22495e5c12b0Sopenharmony_ci tmp = node; 22505e5c12b0Sopenharmony_ci node = node->next; 22515e5c12b0Sopenharmony_ci free(tmp); 22525e5c12b0Sopenharmony_ci } 22535e5c12b0Sopenharmony_ci free(node_blk); 22545e5c12b0Sopenharmony_ci} 22555e5c12b0Sopenharmony_ci 22565e5c12b0Sopenharmony_cistatic void fix_nat_entries(struct f2fs_sb_info *sbi) 22575e5c12b0Sopenharmony_ci{ 22585e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 22595e5c12b0Sopenharmony_ci u32 i; 22605e5c12b0Sopenharmony_ci 22615e5c12b0Sopenharmony_ci for (i = 0; i < fsck->nr_nat_entries; i++) 22625e5c12b0Sopenharmony_ci if (f2fs_test_bit(i, fsck->nat_area_bitmap) != 0) 22635e5c12b0Sopenharmony_ci nullify_nat_entry(sbi, i); 22645e5c12b0Sopenharmony_ci} 22655e5c12b0Sopenharmony_ci 22665e5c12b0Sopenharmony_cistatic void flush_curseg_sit_entries(struct f2fs_sb_info *sbi) 22675e5c12b0Sopenharmony_ci{ 22685e5c12b0Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 22695e5c12b0Sopenharmony_ci struct f2fs_sit_block *sit_blk; 22705e5c12b0Sopenharmony_ci int i; 22715e5c12b0Sopenharmony_ci 22725e5c12b0Sopenharmony_ci sit_blk = calloc(BLOCK_SZ, 1); 22735e5c12b0Sopenharmony_ci ASSERT(sit_blk); 22745e5c12b0Sopenharmony_ci /* update curseg sit entries, since we may change 22755e5c12b0Sopenharmony_ci * a segment type in move_curseg_info 22765e5c12b0Sopenharmony_ci */ 22775e5c12b0Sopenharmony_ci for (i = 0; i < NO_CHECK_TYPE; i++) { 22785e5c12b0Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, i); 22795e5c12b0Sopenharmony_ci struct f2fs_sit_entry *sit; 22805e5c12b0Sopenharmony_ci struct seg_entry *se; 22815e5c12b0Sopenharmony_ci 22825e5c12b0Sopenharmony_ci se = get_seg_entry(sbi, curseg->segno); 22835e5c12b0Sopenharmony_ci get_current_sit_page(sbi, curseg->segno, sit_blk); 22845e5c12b0Sopenharmony_ci sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, curseg->segno)]; 22855e5c12b0Sopenharmony_ci sit->vblocks = cpu_to_le16((se->type << SIT_VBLOCKS_SHIFT) | 22865e5c12b0Sopenharmony_ci se->valid_blocks); 22875e5c12b0Sopenharmony_ci rewrite_current_sit_page(sbi, curseg->segno, sit_blk); 22885e5c12b0Sopenharmony_ci } 22895e5c12b0Sopenharmony_ci 22905e5c12b0Sopenharmony_ci free(sit_blk); 22915e5c12b0Sopenharmony_ci} 22925e5c12b0Sopenharmony_ci 22935e5c12b0Sopenharmony_cistatic void fix_checksum(struct f2fs_sb_info *sbi) 22945e5c12b0Sopenharmony_ci{ 22955e5c12b0Sopenharmony_ci struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); 22965e5c12b0Sopenharmony_ci struct f2fs_nm_info *nm_i = NM_I(sbi); 22975e5c12b0Sopenharmony_ci struct sit_info *sit_i = SIT_I(sbi); 22985e5c12b0Sopenharmony_ci void *bitmap_offset; 22995e5c12b0Sopenharmony_ci 23005e5c12b0Sopenharmony_ci if (!c.fix_chksum) 23015e5c12b0Sopenharmony_ci return; 23025e5c12b0Sopenharmony_ci 23035e5c12b0Sopenharmony_ci bitmap_offset = cp->sit_nat_version_bitmap + sizeof(__le32); 23045e5c12b0Sopenharmony_ci 23055e5c12b0Sopenharmony_ci memcpy(bitmap_offset, nm_i->nat_bitmap, nm_i->bitmap_size); 23065e5c12b0Sopenharmony_ci memcpy(bitmap_offset + nm_i->bitmap_size, 23075e5c12b0Sopenharmony_ci sit_i->sit_bitmap, sit_i->bitmap_size); 23085e5c12b0Sopenharmony_ci} 23095e5c12b0Sopenharmony_ci 23105e5c12b0Sopenharmony_cistatic void fix_checkpoint(struct f2fs_sb_info *sbi) 23115e5c12b0Sopenharmony_ci{ 23125e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 23135e5c12b0Sopenharmony_ci struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 23145e5c12b0Sopenharmony_ci struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); 23155e5c12b0Sopenharmony_ci unsigned long long cp_blk_no; 23165e5c12b0Sopenharmony_ci u32 flags = c.alloc_failed ? CP_FSCK_FLAG: CP_UMOUNT_FLAG; 23175e5c12b0Sopenharmony_ci block_t orphan_blks = 0; 23185e5c12b0Sopenharmony_ci block_t cp_blocks; 23195e5c12b0Sopenharmony_ci u32 i; 23205e5c12b0Sopenharmony_ci int ret; 23215e5c12b0Sopenharmony_ci uint32_t crc = 0; 23225e5c12b0Sopenharmony_ci 23235e5c12b0Sopenharmony_ci /* should call from fsck */ 23245e5c12b0Sopenharmony_ci ASSERT(c.func == FSCK); 23255e5c12b0Sopenharmony_ci 23265e5c12b0Sopenharmony_ci if (is_set_ckpt_flags(cp, CP_ORPHAN_PRESENT_FLAG)) { 23275e5c12b0Sopenharmony_ci orphan_blks = __start_sum_addr(sbi) - 1; 23285e5c12b0Sopenharmony_ci flags |= CP_ORPHAN_PRESENT_FLAG; 23295e5c12b0Sopenharmony_ci } 23305e5c12b0Sopenharmony_ci if (is_set_ckpt_flags(cp, CP_TRIMMED_FLAG)) 23315e5c12b0Sopenharmony_ci flags |= CP_TRIMMED_FLAG; 23325e5c12b0Sopenharmony_ci if (is_set_ckpt_flags(cp, CP_DISABLED_FLAG)) 23335e5c12b0Sopenharmony_ci flags |= CP_DISABLED_FLAG; 23345e5c12b0Sopenharmony_ci if (is_set_ckpt_flags(cp, CP_LARGE_NAT_BITMAP_FLAG)) { 23355e5c12b0Sopenharmony_ci flags |= CP_LARGE_NAT_BITMAP_FLAG; 23365e5c12b0Sopenharmony_ci set_cp(checksum_offset, CP_MIN_CHKSUM_OFFSET); 23375e5c12b0Sopenharmony_ci } else { 23385e5c12b0Sopenharmony_ci set_cp(checksum_offset, CP_CHKSUM_OFFSET); 23395e5c12b0Sopenharmony_ci } 23405e5c12b0Sopenharmony_ci 23415e5c12b0Sopenharmony_ci if (flags & CP_UMOUNT_FLAG) 23425e5c12b0Sopenharmony_ci cp_blocks = 8; 23435e5c12b0Sopenharmony_ci else 23445e5c12b0Sopenharmony_ci cp_blocks = 5; 23455e5c12b0Sopenharmony_ci 23465e5c12b0Sopenharmony_ci set_cp(cp_pack_total_block_count, cp_blocks + 23475e5c12b0Sopenharmony_ci orphan_blks + get_sb(cp_payload)); 23485e5c12b0Sopenharmony_ci 23495e5c12b0Sopenharmony_ci flags = update_nat_bits_flags(sb, cp, flags); 23505e5c12b0Sopenharmony_ci flags |= CP_NOCRC_RECOVERY_FLAG; 23515e5c12b0Sopenharmony_ci set_cp(ckpt_flags, flags); 23525e5c12b0Sopenharmony_ci 23535e5c12b0Sopenharmony_ci set_cp(free_segment_count, get_free_segments(sbi)); 23545e5c12b0Sopenharmony_ci set_cp(valid_block_count, fsck->chk.valid_blk_cnt); 23555e5c12b0Sopenharmony_ci set_cp(valid_node_count, fsck->chk.valid_node_cnt); 23565e5c12b0Sopenharmony_ci set_cp(valid_inode_count, fsck->chk.valid_inode_cnt); 23575e5c12b0Sopenharmony_ci 23585e5c12b0Sopenharmony_ci crc = f2fs_checkpoint_chksum(cp); 23595e5c12b0Sopenharmony_ci *((__le32 *)((unsigned char *)cp + get_cp(checksum_offset))) = 23605e5c12b0Sopenharmony_ci cpu_to_le32(crc); 23615e5c12b0Sopenharmony_ci 23625e5c12b0Sopenharmony_ci cp_blk_no = get_sb(cp_blkaddr); 23635e5c12b0Sopenharmony_ci if (sbi->cur_cp == 2) 23645e5c12b0Sopenharmony_ci cp_blk_no += 1 << get_sb(log_blocks_per_seg); 23655e5c12b0Sopenharmony_ci 23665e5c12b0Sopenharmony_ci ret = dev_write_block(cp, cp_blk_no++); 23675e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 23685e5c12b0Sopenharmony_ci 23695e5c12b0Sopenharmony_ci for (i = 0; i < get_sb(cp_payload); i++) { 23705e5c12b0Sopenharmony_ci ret = dev_write_block(((unsigned char *)cp) + 23715e5c12b0Sopenharmony_ci (i + 1) * F2FS_BLKSIZE, cp_blk_no++); 23725e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 23735e5c12b0Sopenharmony_ci } 23745e5c12b0Sopenharmony_ci 23755e5c12b0Sopenharmony_ci cp_blk_no += orphan_blks; 23765e5c12b0Sopenharmony_ci 23775e5c12b0Sopenharmony_ci for (i = 0; i < NO_CHECK_TYPE; i++) { 23785e5c12b0Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, i); 23795e5c12b0Sopenharmony_ci 23805e5c12b0Sopenharmony_ci if (!(flags & CP_UMOUNT_FLAG) && IS_NODESEG(i)) 23815e5c12b0Sopenharmony_ci continue; 23825e5c12b0Sopenharmony_ci 23835e5c12b0Sopenharmony_ci ret = dev_write_block(curseg->sum_blk, cp_blk_no++); 23845e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 23855e5c12b0Sopenharmony_ci } 23865e5c12b0Sopenharmony_ci 23875e5c12b0Sopenharmony_ci /* Write nat bits */ 23885e5c12b0Sopenharmony_ci if (flags & CP_NAT_BITS_FLAG) 23895e5c12b0Sopenharmony_ci write_nat_bits(sbi, sb, cp, sbi->cur_cp); 23905e5c12b0Sopenharmony_ci 23915e5c12b0Sopenharmony_ci ret = f2fs_fsync_device(); 23925e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 23935e5c12b0Sopenharmony_ci 23945e5c12b0Sopenharmony_ci ret = dev_write_block(cp, cp_blk_no++); 23955e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 23965e5c12b0Sopenharmony_ci 23975e5c12b0Sopenharmony_ci ret = f2fs_fsync_device(); 23985e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 23995e5c12b0Sopenharmony_ci} 24005e5c12b0Sopenharmony_ci 24015e5c12b0Sopenharmony_cistatic void fix_checkpoints(struct f2fs_sb_info *sbi) 24025e5c12b0Sopenharmony_ci{ 24035e5c12b0Sopenharmony_ci /* copy valid checkpoint to its mirror position */ 24045e5c12b0Sopenharmony_ci duplicate_checkpoint(sbi); 24055e5c12b0Sopenharmony_ci 24065e5c12b0Sopenharmony_ci /* repair checkpoint at CP #0 position */ 24075e5c12b0Sopenharmony_ci sbi->cur_cp = 1; 24085e5c12b0Sopenharmony_ci fix_checkpoint(sbi); 24095e5c12b0Sopenharmony_ci} 24105e5c12b0Sopenharmony_ci 24115e5c12b0Sopenharmony_ci#ifdef HAVE_LINUX_BLKZONED_H 24125e5c12b0Sopenharmony_ci 24135e5c12b0Sopenharmony_ci/* 24145e5c12b0Sopenharmony_ci * Refer valid block map and return offset of the last valid block in the zone. 24155e5c12b0Sopenharmony_ci * Obtain valid block map from SIT and fsync data. 24165e5c12b0Sopenharmony_ci * If there is no valid block in the zone, return -1. 24175e5c12b0Sopenharmony_ci */ 24185e5c12b0Sopenharmony_cistatic int last_vblk_off_in_zone(struct f2fs_sb_info *sbi, 24195e5c12b0Sopenharmony_ci unsigned int zone_segno) 24205e5c12b0Sopenharmony_ci{ 24215e5c12b0Sopenharmony_ci int s, b; 24225e5c12b0Sopenharmony_ci unsigned int segs_per_zone = sbi->segs_per_sec * sbi->secs_per_zone; 24235e5c12b0Sopenharmony_ci struct seg_entry *se; 24245e5c12b0Sopenharmony_ci 24255e5c12b0Sopenharmony_ci for (s = segs_per_zone - 1; s >= 0; s--) { 24265e5c12b0Sopenharmony_ci se = get_seg_entry(sbi, zone_segno + s); 24275e5c12b0Sopenharmony_ci 24285e5c12b0Sopenharmony_ci /* 24295e5c12b0Sopenharmony_ci * Refer not cur_valid_map but ckpt_valid_map which reflects 24305e5c12b0Sopenharmony_ci * fsync data. 24315e5c12b0Sopenharmony_ci */ 24325e5c12b0Sopenharmony_ci ASSERT(se->ckpt_valid_map); 24335e5c12b0Sopenharmony_ci for (b = sbi->blocks_per_seg - 1; b >= 0; b--) 24345e5c12b0Sopenharmony_ci if (f2fs_test_bit(b, (const char*)se->ckpt_valid_map)) 24355e5c12b0Sopenharmony_ci return b + (s << sbi->log_blocks_per_seg); 24365e5c12b0Sopenharmony_ci } 24375e5c12b0Sopenharmony_ci 24385e5c12b0Sopenharmony_ci return -1; 24395e5c12b0Sopenharmony_ci} 24405e5c12b0Sopenharmony_ci 24415e5c12b0Sopenharmony_cistatic int check_curseg_write_pointer(struct f2fs_sb_info *sbi, int type) 24425e5c12b0Sopenharmony_ci{ 24435e5c12b0Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 24445e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 24455e5c12b0Sopenharmony_ci struct blk_zone blkz; 24465e5c12b0Sopenharmony_ci block_t cs_block, wp_block, zone_last_vblock; 24475e5c12b0Sopenharmony_ci uint64_t cs_sector, wp_sector; 24485e5c12b0Sopenharmony_ci int i, ret; 24495e5c12b0Sopenharmony_ci unsigned int zone_segno; 24505e5c12b0Sopenharmony_ci int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT; 24515e5c12b0Sopenharmony_ci 24525e5c12b0Sopenharmony_ci /* get the device the curseg points to */ 24535e5c12b0Sopenharmony_ci cs_block = START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff; 24545e5c12b0Sopenharmony_ci for (i = 0; i < MAX_DEVICES; i++) { 24555e5c12b0Sopenharmony_ci if (!c.devices[i].path) 24565e5c12b0Sopenharmony_ci break; 24575e5c12b0Sopenharmony_ci if (c.devices[i].start_blkaddr <= cs_block && 24585e5c12b0Sopenharmony_ci cs_block <= c.devices[i].end_blkaddr) 24595e5c12b0Sopenharmony_ci break; 24605e5c12b0Sopenharmony_ci } 24615e5c12b0Sopenharmony_ci 24625e5c12b0Sopenharmony_ci if (i >= MAX_DEVICES) 24635e5c12b0Sopenharmony_ci return -EINVAL; 24645e5c12b0Sopenharmony_ci 24655e5c12b0Sopenharmony_ci if (c.devices[i].zoned_model != F2FS_ZONED_HM) 24665e5c12b0Sopenharmony_ci return 0; 24675e5c12b0Sopenharmony_ci 24685e5c12b0Sopenharmony_ci /* get write pointer position of the zone the curseg points to */ 24695e5c12b0Sopenharmony_ci cs_sector = (cs_block - c.devices[i].start_blkaddr) 24705e5c12b0Sopenharmony_ci << log_sectors_per_block; 24715e5c12b0Sopenharmony_ci ret = f2fs_report_zone(i, cs_sector, &blkz); 24725e5c12b0Sopenharmony_ci if (ret) 24735e5c12b0Sopenharmony_ci return ret; 24745e5c12b0Sopenharmony_ci 24755e5c12b0Sopenharmony_ci if (blk_zone_type(&blkz) != BLK_ZONE_TYPE_SEQWRITE_REQ) 24765e5c12b0Sopenharmony_ci return 0; 24775e5c12b0Sopenharmony_ci 24785e5c12b0Sopenharmony_ci /* check consistency between the curseg and the write pointer */ 24795e5c12b0Sopenharmony_ci wp_block = c.devices[i].start_blkaddr + 24805e5c12b0Sopenharmony_ci (blk_zone_wp_sector(&blkz) >> log_sectors_per_block); 24815e5c12b0Sopenharmony_ci wp_sector = blk_zone_wp_sector(&blkz); 24825e5c12b0Sopenharmony_ci 24835e5c12b0Sopenharmony_ci if (cs_sector == wp_sector) 24845e5c12b0Sopenharmony_ci return 0; 24855e5c12b0Sopenharmony_ci 24865e5c12b0Sopenharmony_ci if (cs_sector > wp_sector) { 24875e5c12b0Sopenharmony_ci MSG(0, "Inconsistent write pointer with curseg %d: " 24885e5c12b0Sopenharmony_ci "curseg %d[0x%x,0x%x] > wp[0x%x,0x%x]\n", 24895e5c12b0Sopenharmony_ci type, type, curseg->segno, curseg->next_blkoff, 24905e5c12b0Sopenharmony_ci GET_SEGNO(sbi, wp_block), OFFSET_IN_SEG(sbi, wp_block)); 24915e5c12b0Sopenharmony_ci fsck->chk.wp_inconsistent_zones++; 24925e5c12b0Sopenharmony_ci return -EINVAL; 24935e5c12b0Sopenharmony_ci } 24945e5c12b0Sopenharmony_ci 24955e5c12b0Sopenharmony_ci MSG(0, "Write pointer goes advance from curseg %d: " 24965e5c12b0Sopenharmony_ci "curseg %d[0x%x,0x%x] wp[0x%x,0x%x]\n", 24975e5c12b0Sopenharmony_ci type, type, curseg->segno, curseg->next_blkoff, 24985e5c12b0Sopenharmony_ci GET_SEGNO(sbi, wp_block), OFFSET_IN_SEG(sbi, wp_block)); 24995e5c12b0Sopenharmony_ci 25005e5c12b0Sopenharmony_ci zone_segno = GET_SEG_FROM_SEC(sbi, 25015e5c12b0Sopenharmony_ci GET_SEC_FROM_SEG(sbi, curseg->segno)); 25025e5c12b0Sopenharmony_ci zone_last_vblock = START_BLOCK(sbi, zone_segno) + 25035e5c12b0Sopenharmony_ci last_vblk_off_in_zone(sbi, zone_segno); 25045e5c12b0Sopenharmony_ci 25055e5c12b0Sopenharmony_ci /* 25065e5c12b0Sopenharmony_ci * If valid blocks exist between the curseg position and the write 25075e5c12b0Sopenharmony_ci * pointer, they are fsync data. This is not an error to fix. Leave it 25085e5c12b0Sopenharmony_ci * for kernel to recover later. 25095e5c12b0Sopenharmony_ci * If valid blocks exist between the curseg's zone start and the curseg 25105e5c12b0Sopenharmony_ci * position, or if there is no valid block in the curseg's zone, fix 25115e5c12b0Sopenharmony_ci * the inconsistency between the curseg and the writ pointer. 25125e5c12b0Sopenharmony_ci * Of Note is that if there is no valid block in the curseg's zone, 25135e5c12b0Sopenharmony_ci * last_vblk_off_in_zone() returns -1 and zone_last_vblock is always 25145e5c12b0Sopenharmony_ci * smaller than cs_block. 25155e5c12b0Sopenharmony_ci */ 25165e5c12b0Sopenharmony_ci if (cs_block <= zone_last_vblock && zone_last_vblock < wp_block) { 25175e5c12b0Sopenharmony_ci MSG(0, "Curseg has fsync data: curseg %d[0x%x,0x%x] " 25185e5c12b0Sopenharmony_ci "last valid block in zone[0x%x,0x%x]\n", 25195e5c12b0Sopenharmony_ci type, curseg->segno, curseg->next_blkoff, 25205e5c12b0Sopenharmony_ci GET_SEGNO(sbi, zone_last_vblock), 25215e5c12b0Sopenharmony_ci OFFSET_IN_SEG(sbi, zone_last_vblock)); 25225e5c12b0Sopenharmony_ci return 0; 25235e5c12b0Sopenharmony_ci } 25245e5c12b0Sopenharmony_ci 25255e5c12b0Sopenharmony_ci fsck->chk.wp_inconsistent_zones++; 25265e5c12b0Sopenharmony_ci return -EINVAL; 25275e5c12b0Sopenharmony_ci} 25285e5c12b0Sopenharmony_ci 25295e5c12b0Sopenharmony_ci#else 25305e5c12b0Sopenharmony_ci 25315e5c12b0Sopenharmony_cistatic int check_curseg_write_pointer(struct f2fs_sb_info *UNUSED(sbi), 25325e5c12b0Sopenharmony_ci int UNUSED(type)) 25335e5c12b0Sopenharmony_ci{ 25345e5c12b0Sopenharmony_ci return 0; 25355e5c12b0Sopenharmony_ci} 25365e5c12b0Sopenharmony_ci 25375e5c12b0Sopenharmony_ci#endif 25385e5c12b0Sopenharmony_ci 25395e5c12b0Sopenharmony_ciint check_curseg_offset(struct f2fs_sb_info *sbi, int type) 25405e5c12b0Sopenharmony_ci{ 25415e5c12b0Sopenharmony_ci struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 25425e5c12b0Sopenharmony_ci struct curseg_info *curseg = CURSEG_I(sbi, type); 25435e5c12b0Sopenharmony_ci struct seg_entry *se; 25445e5c12b0Sopenharmony_ci int j, nblocks; 25455e5c12b0Sopenharmony_ci 25465e5c12b0Sopenharmony_ci if (get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO) && 25475e5c12b0Sopenharmony_ci type != CURSEG_HOT_DATA && type != CURSEG_HOT_NODE) 25485e5c12b0Sopenharmony_ci return 0; 25495e5c12b0Sopenharmony_ci 25505e5c12b0Sopenharmony_ci if ((curseg->next_blkoff >> 3) >= SIT_VBLOCK_MAP_SIZE) { 25515e5c12b0Sopenharmony_ci ASSERT_MSG("Next block offset:%u is invalid, type:%d", 25525e5c12b0Sopenharmony_ci curseg->next_blkoff, type); 25535e5c12b0Sopenharmony_ci return -EINVAL; 25545e5c12b0Sopenharmony_ci } 25555e5c12b0Sopenharmony_ci se = get_seg_entry(sbi, curseg->segno); 25565e5c12b0Sopenharmony_ci if (f2fs_test_bit(curseg->next_blkoff, 25575e5c12b0Sopenharmony_ci (const char *)se->cur_valid_map)) { 25585e5c12b0Sopenharmony_ci ASSERT_MSG("Next block offset is not free, type:%d", type); 25595e5c12b0Sopenharmony_ci return -EINVAL; 25605e5c12b0Sopenharmony_ci } 25615e5c12b0Sopenharmony_ci if (curseg->alloc_type == SSR) 25625e5c12b0Sopenharmony_ci return 0; 25635e5c12b0Sopenharmony_ci 25645e5c12b0Sopenharmony_ci nblocks = sbi->blocks_per_seg; 25655e5c12b0Sopenharmony_ci for (j = curseg->next_blkoff + 1; j < nblocks; j++) { 25665e5c12b0Sopenharmony_ci if (f2fs_test_bit(j, (const char *)se->cur_valid_map)) { 25675e5c12b0Sopenharmony_ci ASSERT_MSG("For LFS curseg, space after .next_blkoff " 25685e5c12b0Sopenharmony_ci "should be unused, type:%d", type); 25695e5c12b0Sopenharmony_ci return -EINVAL; 25705e5c12b0Sopenharmony_ci } 25715e5c12b0Sopenharmony_ci } 25725e5c12b0Sopenharmony_ci 25735e5c12b0Sopenharmony_ci if (c.zoned_model == F2FS_ZONED_HM) 25745e5c12b0Sopenharmony_ci return check_curseg_write_pointer(sbi, type); 25755e5c12b0Sopenharmony_ci 25765e5c12b0Sopenharmony_ci return 0; 25775e5c12b0Sopenharmony_ci} 25785e5c12b0Sopenharmony_ci 25795e5c12b0Sopenharmony_ciint check_curseg_offsets(struct f2fs_sb_info *sbi) 25805e5c12b0Sopenharmony_ci{ 25815e5c12b0Sopenharmony_ci int i, ret; 25825e5c12b0Sopenharmony_ci 25835e5c12b0Sopenharmony_ci for (i = 0; i < NO_CHECK_TYPE; i++) { 25845e5c12b0Sopenharmony_ci ret = check_curseg_offset(sbi, i); 25855e5c12b0Sopenharmony_ci if (ret) 25865e5c12b0Sopenharmony_ci return ret; 25875e5c12b0Sopenharmony_ci } 25885e5c12b0Sopenharmony_ci return 0; 25895e5c12b0Sopenharmony_ci} 25905e5c12b0Sopenharmony_ci 25915e5c12b0Sopenharmony_cistatic void fix_curseg_info(struct f2fs_sb_info *sbi) 25925e5c12b0Sopenharmony_ci{ 25935e5c12b0Sopenharmony_ci int i, need_update = 0; 25945e5c12b0Sopenharmony_ci 25955e5c12b0Sopenharmony_ci for (i = 0; i < NO_CHECK_TYPE; i++) { 25965e5c12b0Sopenharmony_ci if (check_curseg_offset(sbi, i)) { 25975e5c12b0Sopenharmony_ci update_curseg_info(sbi, i); 25985e5c12b0Sopenharmony_ci need_update = 1; 25995e5c12b0Sopenharmony_ci } 26005e5c12b0Sopenharmony_ci } 26015e5c12b0Sopenharmony_ci 26025e5c12b0Sopenharmony_ci if (need_update) { 26035e5c12b0Sopenharmony_ci write_curseg_info(sbi); 26045e5c12b0Sopenharmony_ci flush_curseg_sit_entries(sbi); 26055e5c12b0Sopenharmony_ci } 26065e5c12b0Sopenharmony_ci} 26075e5c12b0Sopenharmony_ci 26085e5c12b0Sopenharmony_ciint check_sit_types(struct f2fs_sb_info *sbi) 26095e5c12b0Sopenharmony_ci{ 26105e5c12b0Sopenharmony_ci unsigned int i; 26115e5c12b0Sopenharmony_ci int err = 0; 26125e5c12b0Sopenharmony_ci 26135e5c12b0Sopenharmony_ci for (i = 0; i < MAIN_SEGS(sbi); i++) { 26145e5c12b0Sopenharmony_ci struct seg_entry *se; 26155e5c12b0Sopenharmony_ci 26165e5c12b0Sopenharmony_ci se = get_seg_entry(sbi, i); 26175e5c12b0Sopenharmony_ci if (se->orig_type != se->type) { 26185e5c12b0Sopenharmony_ci if (se->orig_type == CURSEG_COLD_DATA && 26195e5c12b0Sopenharmony_ci se->type <= CURSEG_COLD_DATA) { 26205e5c12b0Sopenharmony_ci se->type = se->orig_type; 26215e5c12b0Sopenharmony_ci } else { 26225e5c12b0Sopenharmony_ci FIX_MSG("Wrong segment type [0x%x] %x -> %x", 26235e5c12b0Sopenharmony_ci i, se->orig_type, se->type); 26245e5c12b0Sopenharmony_ci err = -EINVAL; 26255e5c12b0Sopenharmony_ci } 26265e5c12b0Sopenharmony_ci } 26275e5c12b0Sopenharmony_ci } 26285e5c12b0Sopenharmony_ci return err; 26295e5c12b0Sopenharmony_ci} 26305e5c12b0Sopenharmony_ci 26315e5c12b0Sopenharmony_cistatic struct f2fs_node *fsck_get_lpf(struct f2fs_sb_info *sbi) 26325e5c12b0Sopenharmony_ci{ 26335e5c12b0Sopenharmony_ci struct f2fs_node *node; 26345e5c12b0Sopenharmony_ci struct node_info ni; 26355e5c12b0Sopenharmony_ci nid_t lpf_ino; 26365e5c12b0Sopenharmony_ci int err; 26375e5c12b0Sopenharmony_ci 26385e5c12b0Sopenharmony_ci /* read root inode first */ 26395e5c12b0Sopenharmony_ci node = calloc(F2FS_BLKSIZE, 1); 26405e5c12b0Sopenharmony_ci ASSERT(node); 26415e5c12b0Sopenharmony_ci get_node_info(sbi, F2FS_ROOT_INO(sbi), &ni); 26425e5c12b0Sopenharmony_ci err = dev_read_block(node, ni.blk_addr); 26435e5c12b0Sopenharmony_ci ASSERT(err >= 0); 26445e5c12b0Sopenharmony_ci 26455e5c12b0Sopenharmony_ci /* lookup lost+found in root directory */ 26465e5c12b0Sopenharmony_ci lpf_ino = f2fs_lookup(sbi, node, (u8 *)LPF, strlen(LPF)); 26475e5c12b0Sopenharmony_ci if (lpf_ino) { /* found */ 26485e5c12b0Sopenharmony_ci get_node_info(sbi, lpf_ino, &ni); 26495e5c12b0Sopenharmony_ci err = dev_read_block(node, ni.blk_addr); 26505e5c12b0Sopenharmony_ci ASSERT(err >= 0); 26515e5c12b0Sopenharmony_ci DBG(1, "Found lost+found 0x%x at blkaddr [0x%x]\n", 26525e5c12b0Sopenharmony_ci lpf_ino, ni.blk_addr); 26535e5c12b0Sopenharmony_ci if (!S_ISDIR(le16_to_cpu(node->i.i_mode))) { 26545e5c12b0Sopenharmony_ci ASSERT_MSG("lost+found is not directory [0%o]\n", 26555e5c12b0Sopenharmony_ci le16_to_cpu(node->i.i_mode)); 26565e5c12b0Sopenharmony_ci /* FIXME: give up? */ 26575e5c12b0Sopenharmony_ci goto out; 26585e5c12b0Sopenharmony_ci } 26595e5c12b0Sopenharmony_ci } else { /* not found, create it */ 26605e5c12b0Sopenharmony_ci struct dentry de; 26615e5c12b0Sopenharmony_ci 26625e5c12b0Sopenharmony_ci memset(&de, 0, sizeof(de)); 26635e5c12b0Sopenharmony_ci de.name = (u8 *) LPF; 26645e5c12b0Sopenharmony_ci de.len = strlen(LPF); 26655e5c12b0Sopenharmony_ci de.mode = 0x41c0; 26665e5c12b0Sopenharmony_ci de.pino = F2FS_ROOT_INO(sbi), 26675e5c12b0Sopenharmony_ci de.file_type = F2FS_FT_DIR, 26685e5c12b0Sopenharmony_ci de.uid = getuid(); 26695e5c12b0Sopenharmony_ci de.gid = getgid(); 26705e5c12b0Sopenharmony_ci de.mtime = time(NULL); 26715e5c12b0Sopenharmony_ci 26725e5c12b0Sopenharmony_ci err = f2fs_mkdir(sbi, &de); 26735e5c12b0Sopenharmony_ci if (err) { 26745e5c12b0Sopenharmony_ci ASSERT_MSG("Failed create lost+found"); 26755e5c12b0Sopenharmony_ci goto out; 26765e5c12b0Sopenharmony_ci } 26775e5c12b0Sopenharmony_ci 26785e5c12b0Sopenharmony_ci get_node_info(sbi, de.ino, &ni); 26795e5c12b0Sopenharmony_ci err = dev_read_block(node, ni.blk_addr); 26805e5c12b0Sopenharmony_ci ASSERT(err >= 0); 26815e5c12b0Sopenharmony_ci DBG(1, "Create lost+found 0x%x at blkaddr [0x%x]\n", 26825e5c12b0Sopenharmony_ci de.ino, ni.blk_addr); 26835e5c12b0Sopenharmony_ci } 26845e5c12b0Sopenharmony_ci 26855e5c12b0Sopenharmony_ci c.lpf_ino = le32_to_cpu(node->footer.ino); 26865e5c12b0Sopenharmony_ci return node; 26875e5c12b0Sopenharmony_ciout: 26885e5c12b0Sopenharmony_ci free(node); 26895e5c12b0Sopenharmony_ci return NULL; 26905e5c12b0Sopenharmony_ci} 26915e5c12b0Sopenharmony_ci 26925e5c12b0Sopenharmony_cistatic int fsck_do_reconnect_file(struct f2fs_sb_info *sbi, 26935e5c12b0Sopenharmony_ci struct f2fs_node *lpf, 26945e5c12b0Sopenharmony_ci struct f2fs_node *fnode) 26955e5c12b0Sopenharmony_ci{ 26965e5c12b0Sopenharmony_ci char name[80]; 26975e5c12b0Sopenharmony_ci size_t namelen; 26985e5c12b0Sopenharmony_ci nid_t ino = le32_to_cpu(fnode->footer.ino); 26995e5c12b0Sopenharmony_ci struct node_info ni; 27005e5c12b0Sopenharmony_ci int ftype, ret; 27015e5c12b0Sopenharmony_ci 27025e5c12b0Sopenharmony_ci namelen = snprintf(name, 80, "%u", ino); 27035e5c12b0Sopenharmony_ci if (namelen >= 80) 27045e5c12b0Sopenharmony_ci /* ignore terminating '\0', should never happen */ 27055e5c12b0Sopenharmony_ci namelen = 79; 27065e5c12b0Sopenharmony_ci 27075e5c12b0Sopenharmony_ci if (f2fs_lookup(sbi, lpf, (u8 *)name, namelen)) { 27085e5c12b0Sopenharmony_ci ASSERT_MSG("Name %s already exist in lost+found", name); 27095e5c12b0Sopenharmony_ci return -EEXIST; 27105e5c12b0Sopenharmony_ci } 27115e5c12b0Sopenharmony_ci 27125e5c12b0Sopenharmony_ci get_node_info(sbi, le32_to_cpu(lpf->footer.ino), &ni); 27135e5c12b0Sopenharmony_ci ftype = map_de_type(le16_to_cpu(fnode->i.i_mode)); 27145e5c12b0Sopenharmony_ci ret = f2fs_add_link(sbi, lpf, (unsigned char *)name, namelen, 27155e5c12b0Sopenharmony_ci ino, ftype, ni.blk_addr, 0); 27165e5c12b0Sopenharmony_ci if (ret) { 27175e5c12b0Sopenharmony_ci ASSERT_MSG("Failed to add inode [0x%x] to lost+found", ino); 27185e5c12b0Sopenharmony_ci return -EINVAL; 27195e5c12b0Sopenharmony_ci } 27205e5c12b0Sopenharmony_ci 27215e5c12b0Sopenharmony_ci /* update fnode */ 27225e5c12b0Sopenharmony_ci memcpy(fnode->i.i_name, name, namelen); 27235e5c12b0Sopenharmony_ci fnode->i.i_namelen = cpu_to_le32(namelen); 27245e5c12b0Sopenharmony_ci fnode->i.i_pino = c.lpf_ino; 27255e5c12b0Sopenharmony_ci get_node_info(sbi, le32_to_cpu(fnode->footer.ino), &ni); 27265e5c12b0Sopenharmony_ci ret = dev_write_block(fnode, ni.blk_addr); 27275e5c12b0Sopenharmony_ci ASSERT(ret >= 0); 27285e5c12b0Sopenharmony_ci 27295e5c12b0Sopenharmony_ci DBG(1, "Reconnect inode [0x%x] to lost+found\n", ino); 27305e5c12b0Sopenharmony_ci return 0; 27315e5c12b0Sopenharmony_ci} 27325e5c12b0Sopenharmony_ci 27335e5c12b0Sopenharmony_cistatic void fsck_failed_reconnect_file_dnode(struct f2fs_sb_info *sbi, 27345e5c12b0Sopenharmony_ci nid_t nid) 27355e5c12b0Sopenharmony_ci{ 27365e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 27375e5c12b0Sopenharmony_ci struct f2fs_node *node; 27385e5c12b0Sopenharmony_ci struct node_info ni; 27395e5c12b0Sopenharmony_ci u32 addr; 27405e5c12b0Sopenharmony_ci int i, err; 27415e5c12b0Sopenharmony_ci 27425e5c12b0Sopenharmony_ci node = calloc(F2FS_BLKSIZE, 1); 27435e5c12b0Sopenharmony_ci ASSERT(node); 27445e5c12b0Sopenharmony_ci 27455e5c12b0Sopenharmony_ci get_node_info(sbi, nid, &ni); 27465e5c12b0Sopenharmony_ci err = dev_read_block(node, ni.blk_addr); 27475e5c12b0Sopenharmony_ci ASSERT(err >= 0); 27485e5c12b0Sopenharmony_ci 27495e5c12b0Sopenharmony_ci fsck->chk.valid_node_cnt--; 27505e5c12b0Sopenharmony_ci fsck->chk.valid_blk_cnt--; 27515e5c12b0Sopenharmony_ci f2fs_clear_main_bitmap(sbi, ni.blk_addr); 27525e5c12b0Sopenharmony_ci 27535e5c12b0Sopenharmony_ci for (i = 0; i < ADDRS_PER_BLOCK(&node->i); i++) { 27545e5c12b0Sopenharmony_ci addr = le32_to_cpu(node->dn.addr[i]); 27555e5c12b0Sopenharmony_ci if (!addr) 27565e5c12b0Sopenharmony_ci continue; 27575e5c12b0Sopenharmony_ci fsck->chk.valid_blk_cnt--; 27585e5c12b0Sopenharmony_ci if (addr == NEW_ADDR) 27595e5c12b0Sopenharmony_ci continue; 27605e5c12b0Sopenharmony_ci f2fs_clear_main_bitmap(sbi, addr); 27615e5c12b0Sopenharmony_ci } 27625e5c12b0Sopenharmony_ci 27635e5c12b0Sopenharmony_ci free(node); 27645e5c12b0Sopenharmony_ci} 27655e5c12b0Sopenharmony_ci 27665e5c12b0Sopenharmony_cistatic void fsck_failed_reconnect_file_idnode(struct f2fs_sb_info *sbi, 27675e5c12b0Sopenharmony_ci nid_t nid) 27685e5c12b0Sopenharmony_ci{ 27695e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 27705e5c12b0Sopenharmony_ci struct f2fs_node *node; 27715e5c12b0Sopenharmony_ci struct node_info ni; 27725e5c12b0Sopenharmony_ci nid_t tmp; 27735e5c12b0Sopenharmony_ci int i, err; 27745e5c12b0Sopenharmony_ci 27755e5c12b0Sopenharmony_ci node = calloc(F2FS_BLKSIZE, 1); 27765e5c12b0Sopenharmony_ci ASSERT(node); 27775e5c12b0Sopenharmony_ci 27785e5c12b0Sopenharmony_ci get_node_info(sbi, nid, &ni); 27795e5c12b0Sopenharmony_ci err = dev_read_block(node, ni.blk_addr); 27805e5c12b0Sopenharmony_ci ASSERT(err >= 0); 27815e5c12b0Sopenharmony_ci 27825e5c12b0Sopenharmony_ci fsck->chk.valid_node_cnt--; 27835e5c12b0Sopenharmony_ci fsck->chk.valid_blk_cnt--; 27845e5c12b0Sopenharmony_ci f2fs_clear_main_bitmap(sbi, ni.blk_addr); 27855e5c12b0Sopenharmony_ci 27865e5c12b0Sopenharmony_ci for (i = 0; i < NIDS_PER_BLOCK; i++) { 27875e5c12b0Sopenharmony_ci tmp = le32_to_cpu(node->in.nid[i]); 27885e5c12b0Sopenharmony_ci if (!tmp) 27895e5c12b0Sopenharmony_ci continue; 27905e5c12b0Sopenharmony_ci fsck_failed_reconnect_file_dnode(sbi, tmp); 27915e5c12b0Sopenharmony_ci } 27925e5c12b0Sopenharmony_ci 27935e5c12b0Sopenharmony_ci free(node); 27945e5c12b0Sopenharmony_ci} 27955e5c12b0Sopenharmony_ci 27965e5c12b0Sopenharmony_cistatic void fsck_failed_reconnect_file_didnode(struct f2fs_sb_info *sbi, 27975e5c12b0Sopenharmony_ci nid_t nid) 27985e5c12b0Sopenharmony_ci{ 27995e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 28005e5c12b0Sopenharmony_ci struct f2fs_node *node; 28015e5c12b0Sopenharmony_ci struct node_info ni; 28025e5c12b0Sopenharmony_ci nid_t tmp; 28035e5c12b0Sopenharmony_ci int i, err; 28045e5c12b0Sopenharmony_ci 28055e5c12b0Sopenharmony_ci node = calloc(F2FS_BLKSIZE, 1); 28065e5c12b0Sopenharmony_ci ASSERT(node); 28075e5c12b0Sopenharmony_ci 28085e5c12b0Sopenharmony_ci get_node_info(sbi, nid, &ni); 28095e5c12b0Sopenharmony_ci err = dev_read_block(node, ni.blk_addr); 28105e5c12b0Sopenharmony_ci ASSERT(err >= 0); 28115e5c12b0Sopenharmony_ci 28125e5c12b0Sopenharmony_ci fsck->chk.valid_node_cnt--; 28135e5c12b0Sopenharmony_ci fsck->chk.valid_blk_cnt--; 28145e5c12b0Sopenharmony_ci f2fs_clear_main_bitmap(sbi, ni.blk_addr); 28155e5c12b0Sopenharmony_ci 28165e5c12b0Sopenharmony_ci for (i = 0; i < NIDS_PER_BLOCK; i++) { 28175e5c12b0Sopenharmony_ci tmp = le32_to_cpu(node->in.nid[i]); 28185e5c12b0Sopenharmony_ci if (!tmp) 28195e5c12b0Sopenharmony_ci continue; 28205e5c12b0Sopenharmony_ci fsck_failed_reconnect_file_idnode(sbi, tmp); 28215e5c12b0Sopenharmony_ci } 28225e5c12b0Sopenharmony_ci 28235e5c12b0Sopenharmony_ci free(node); 28245e5c12b0Sopenharmony_ci} 28255e5c12b0Sopenharmony_ci 28265e5c12b0Sopenharmony_ci/* 28275e5c12b0Sopenharmony_ci * Counters and main_area_bitmap are already changed during checking 28285e5c12b0Sopenharmony_ci * inode block, so clear them. There is no need to clear new blocks 28295e5c12b0Sopenharmony_ci * allocted to lost+found. 28305e5c12b0Sopenharmony_ci */ 28315e5c12b0Sopenharmony_cistatic void fsck_failed_reconnect_file(struct f2fs_sb_info *sbi, nid_t ino) 28325e5c12b0Sopenharmony_ci{ 28335e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 28345e5c12b0Sopenharmony_ci struct f2fs_node *node; 28355e5c12b0Sopenharmony_ci struct node_info ni; 28365e5c12b0Sopenharmony_ci nid_t nid; 28375e5c12b0Sopenharmony_ci int ofs, i, err; 28385e5c12b0Sopenharmony_ci 28395e5c12b0Sopenharmony_ci node = calloc(F2FS_BLKSIZE, 1); 28405e5c12b0Sopenharmony_ci ASSERT(node); 28415e5c12b0Sopenharmony_ci 28425e5c12b0Sopenharmony_ci get_node_info(sbi, ino, &ni); 28435e5c12b0Sopenharmony_ci err = dev_read_block(node, ni.blk_addr); 28445e5c12b0Sopenharmony_ci ASSERT(err >= 0); 28455e5c12b0Sopenharmony_ci 28465e5c12b0Sopenharmony_ci /* clear inode counters */ 28475e5c12b0Sopenharmony_ci fsck->chk.valid_inode_cnt--; 28485e5c12b0Sopenharmony_ci fsck->chk.valid_node_cnt--; 28495e5c12b0Sopenharmony_ci fsck->chk.valid_blk_cnt--; 28505e5c12b0Sopenharmony_ci f2fs_clear_main_bitmap(sbi, ni.blk_addr); 28515e5c12b0Sopenharmony_ci 28525e5c12b0Sopenharmony_ci /* clear xnid counters */ 28535e5c12b0Sopenharmony_ci if (node->i.i_xattr_nid) { 28545e5c12b0Sopenharmony_ci nid = le32_to_cpu(node->i.i_xattr_nid); 28555e5c12b0Sopenharmony_ci fsck->chk.valid_node_cnt--; 28565e5c12b0Sopenharmony_ci fsck->chk.valid_blk_cnt--; 28575e5c12b0Sopenharmony_ci get_node_info(sbi, nid, &ni); 28585e5c12b0Sopenharmony_ci f2fs_clear_main_bitmap(sbi, ni.blk_addr); 28595e5c12b0Sopenharmony_ci } 28605e5c12b0Sopenharmony_ci 28615e5c12b0Sopenharmony_ci /* clear data counters */ 28625e5c12b0Sopenharmony_ci if(!(node->i.i_inline & F2FS_INLINE_DATA)) { 28635e5c12b0Sopenharmony_ci ofs = get_extra_isize(node); 28645e5c12b0Sopenharmony_ci for (i = 0; i < ADDRS_PER_INODE(&node->i); i++) { 28655e5c12b0Sopenharmony_ci block_t addr = le32_to_cpu(node->i.i_addr[ofs + i]); 28665e5c12b0Sopenharmony_ci if (!addr) 28675e5c12b0Sopenharmony_ci continue; 28685e5c12b0Sopenharmony_ci fsck->chk.valid_blk_cnt--; 28695e5c12b0Sopenharmony_ci if (addr == NEW_ADDR) 28705e5c12b0Sopenharmony_ci continue; 28715e5c12b0Sopenharmony_ci f2fs_clear_main_bitmap(sbi, addr); 28725e5c12b0Sopenharmony_ci } 28735e5c12b0Sopenharmony_ci } 28745e5c12b0Sopenharmony_ci 28755e5c12b0Sopenharmony_ci for (i = 0; i < 5; i++) { 28765e5c12b0Sopenharmony_ci nid = le32_to_cpu(node->i.i_nid[i]); 28775e5c12b0Sopenharmony_ci if (!nid) 28785e5c12b0Sopenharmony_ci continue; 28795e5c12b0Sopenharmony_ci 28805e5c12b0Sopenharmony_ci switch (i) { 28815e5c12b0Sopenharmony_ci case 0: /* direct node */ 28825e5c12b0Sopenharmony_ci case 1: 28835e5c12b0Sopenharmony_ci fsck_failed_reconnect_file_dnode(sbi, nid); 28845e5c12b0Sopenharmony_ci break; 28855e5c12b0Sopenharmony_ci case 2: /* indirect node */ 28865e5c12b0Sopenharmony_ci case 3: 28875e5c12b0Sopenharmony_ci fsck_failed_reconnect_file_idnode(sbi, nid); 28885e5c12b0Sopenharmony_ci break; 28895e5c12b0Sopenharmony_ci case 4: /* double indirect node */ 28905e5c12b0Sopenharmony_ci fsck_failed_reconnect_file_didnode(sbi, nid); 28915e5c12b0Sopenharmony_ci break; 28925e5c12b0Sopenharmony_ci } 28935e5c12b0Sopenharmony_ci } 28945e5c12b0Sopenharmony_ci 28955e5c12b0Sopenharmony_ci free(node); 28965e5c12b0Sopenharmony_ci} 28975e5c12b0Sopenharmony_ci 28985e5c12b0Sopenharmony_ci/* 28995e5c12b0Sopenharmony_ci * Scan unreachable nids and find only regular file inodes. If these files 29005e5c12b0Sopenharmony_ci * are not corrupted, reconnect them to lost+found. 29015e5c12b0Sopenharmony_ci * 29025e5c12b0Sopenharmony_ci * Since all unreachable nodes are already checked, we can allocate new 29035e5c12b0Sopenharmony_ci * blocks safely. 29045e5c12b0Sopenharmony_ci * 29055e5c12b0Sopenharmony_ci * This function returns the number of files been reconnected. 29065e5c12b0Sopenharmony_ci */ 29075e5c12b0Sopenharmony_cistatic int fsck_reconnect_file(struct f2fs_sb_info *sbi) 29085e5c12b0Sopenharmony_ci{ 29095e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 29105e5c12b0Sopenharmony_ci struct f2fs_node *lpf_node, *node; 29115e5c12b0Sopenharmony_ci struct node_info ni; 29125e5c12b0Sopenharmony_ci char *reconnect_bitmap; 29135e5c12b0Sopenharmony_ci u32 blk_cnt; 29145e5c12b0Sopenharmony_ci struct f2fs_compr_blk_cnt cbc; 29155e5c12b0Sopenharmony_ci nid_t nid; 29165e5c12b0Sopenharmony_ci int err, cnt = 0, ftype; 29175e5c12b0Sopenharmony_ci 29185e5c12b0Sopenharmony_ci node = calloc(F2FS_BLKSIZE, 1); 29195e5c12b0Sopenharmony_ci ASSERT(node); 29205e5c12b0Sopenharmony_ci 29215e5c12b0Sopenharmony_ci reconnect_bitmap = calloc(fsck->nat_area_bitmap_sz, 1); 29225e5c12b0Sopenharmony_ci ASSERT(reconnect_bitmap); 29235e5c12b0Sopenharmony_ci 29245e5c12b0Sopenharmony_ci for (nid = 0; nid < fsck->nr_nat_entries; nid++) { 29255e5c12b0Sopenharmony_ci if (f2fs_test_bit(nid, fsck->nat_area_bitmap)) { 29265e5c12b0Sopenharmony_ci if (is_qf_ino(F2FS_RAW_SUPER(sbi), nid)) { 29275e5c12b0Sopenharmony_ci DBG(1, "Not support quota inode [0x%x]\n", 29285e5c12b0Sopenharmony_ci nid); 29295e5c12b0Sopenharmony_ci continue; 29305e5c12b0Sopenharmony_ci } 29315e5c12b0Sopenharmony_ci 29325e5c12b0Sopenharmony_ci get_node_info(sbi, nid, &ni); 29335e5c12b0Sopenharmony_ci err = dev_read_block(node, ni.blk_addr); 29345e5c12b0Sopenharmony_ci ASSERT(err >= 0); 29355e5c12b0Sopenharmony_ci 29365e5c12b0Sopenharmony_ci /* reconnection will restore these nodes if needed */ 29375e5c12b0Sopenharmony_ci if (node->footer.ino != node->footer.nid) { 29385e5c12b0Sopenharmony_ci DBG(1, "Not support non-inode node [0x%x]\n", 29395e5c12b0Sopenharmony_ci nid); 29405e5c12b0Sopenharmony_ci continue; 29415e5c12b0Sopenharmony_ci } 29425e5c12b0Sopenharmony_ci 29435e5c12b0Sopenharmony_ci if (S_ISDIR(le16_to_cpu(node->i.i_mode))) { 29445e5c12b0Sopenharmony_ci DBG(1, "Not support directory inode [0x%x]\n", 29455e5c12b0Sopenharmony_ci nid); 29465e5c12b0Sopenharmony_ci continue; 29475e5c12b0Sopenharmony_ci } 29485e5c12b0Sopenharmony_ci 29495e5c12b0Sopenharmony_ci ftype = map_de_type(le16_to_cpu(node->i.i_mode)); 29505e5c12b0Sopenharmony_ci if (sanity_check_nid(sbi, nid, node, ftype, 29515e5c12b0Sopenharmony_ci TYPE_INODE, &ni)) { 29525e5c12b0Sopenharmony_ci ASSERT_MSG("Invalid nid [0x%x]\n", nid); 29535e5c12b0Sopenharmony_ci continue; 29545e5c12b0Sopenharmony_ci } 29555e5c12b0Sopenharmony_ci 29565e5c12b0Sopenharmony_ci DBG(1, "Check inode 0x%x\n", nid); 29575e5c12b0Sopenharmony_ci blk_cnt = 1; 29585e5c12b0Sopenharmony_ci cbc.cnt = 0; 29595e5c12b0Sopenharmony_ci cbc.cheader_pgofs = CHEADER_PGOFS_NONE; 29605e5c12b0Sopenharmony_ci fsck_chk_inode_blk(sbi, nid, ftype, node, 29615e5c12b0Sopenharmony_ci &blk_cnt, &cbc, &ni, NULL); 29625e5c12b0Sopenharmony_ci 29635e5c12b0Sopenharmony_ci f2fs_set_bit(nid, reconnect_bitmap); 29645e5c12b0Sopenharmony_ci } 29655e5c12b0Sopenharmony_ci } 29665e5c12b0Sopenharmony_ci 29675e5c12b0Sopenharmony_ci lpf_node = fsck_get_lpf(sbi); 29685e5c12b0Sopenharmony_ci if (!lpf_node) 29695e5c12b0Sopenharmony_ci goto out; 29705e5c12b0Sopenharmony_ci 29715e5c12b0Sopenharmony_ci for (nid = 0; nid < fsck->nr_nat_entries; nid++) { 29725e5c12b0Sopenharmony_ci if (f2fs_test_bit(nid, reconnect_bitmap)) { 29735e5c12b0Sopenharmony_ci get_node_info(sbi, nid, &ni); 29745e5c12b0Sopenharmony_ci err = dev_read_block(node, ni.blk_addr); 29755e5c12b0Sopenharmony_ci ASSERT(err >= 0); 29765e5c12b0Sopenharmony_ci 29775e5c12b0Sopenharmony_ci if (fsck_do_reconnect_file(sbi, lpf_node, node)) { 29785e5c12b0Sopenharmony_ci DBG(1, "Failed to reconnect inode [0x%x]\n", 29795e5c12b0Sopenharmony_ci nid); 29805e5c12b0Sopenharmony_ci fsck_failed_reconnect_file(sbi, nid); 29815e5c12b0Sopenharmony_ci continue; 29825e5c12b0Sopenharmony_ci } 29835e5c12b0Sopenharmony_ci 29845e5c12b0Sopenharmony_ci quota_add_inode_usage(fsck->qctx, nid, &node->i); 29855e5c12b0Sopenharmony_ci 29865e5c12b0Sopenharmony_ci DBG(1, "Reconnected inode [0x%x] to lost+found\n", nid); 29875e5c12b0Sopenharmony_ci cnt++; 29885e5c12b0Sopenharmony_ci } 29895e5c12b0Sopenharmony_ci } 29905e5c12b0Sopenharmony_ci 29915e5c12b0Sopenharmony_ciout: 29925e5c12b0Sopenharmony_ci free(node); 29935e5c12b0Sopenharmony_ci free(lpf_node); 29945e5c12b0Sopenharmony_ci free(reconnect_bitmap); 29955e5c12b0Sopenharmony_ci return cnt; 29965e5c12b0Sopenharmony_ci} 29975e5c12b0Sopenharmony_ci 29985e5c12b0Sopenharmony_ci#ifdef HAVE_LINUX_BLKZONED_H 29995e5c12b0Sopenharmony_ci 30005e5c12b0Sopenharmony_cistruct write_pointer_check_data { 30015e5c12b0Sopenharmony_ci struct f2fs_sb_info *sbi; 30025e5c12b0Sopenharmony_ci int dev_index; 30035e5c12b0Sopenharmony_ci}; 30045e5c12b0Sopenharmony_ci 30055e5c12b0Sopenharmony_cistatic int chk_and_fix_wp_with_sit(int UNUSED(i), void *blkzone, void *opaque) 30065e5c12b0Sopenharmony_ci{ 30075e5c12b0Sopenharmony_ci struct blk_zone *blkz = (struct blk_zone *)blkzone; 30085e5c12b0Sopenharmony_ci struct write_pointer_check_data *wpd = opaque; 30095e5c12b0Sopenharmony_ci struct f2fs_sb_info *sbi = wpd->sbi; 30105e5c12b0Sopenharmony_ci struct device_info *dev = c.devices + wpd->dev_index; 30115e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 30125e5c12b0Sopenharmony_ci block_t zone_block, wp_block, wp_blkoff; 30135e5c12b0Sopenharmony_ci unsigned int zone_segno, wp_segno; 30145e5c12b0Sopenharmony_ci struct curseg_info *cs; 30155e5c12b0Sopenharmony_ci int cs_index, ret, last_valid_blkoff; 30165e5c12b0Sopenharmony_ci int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT; 30175e5c12b0Sopenharmony_ci unsigned int segs_per_zone = sbi->segs_per_sec * sbi->secs_per_zone; 30185e5c12b0Sopenharmony_ci 30195e5c12b0Sopenharmony_ci if (blk_zone_conv(blkz)) 30205e5c12b0Sopenharmony_ci return 0; 30215e5c12b0Sopenharmony_ci 30225e5c12b0Sopenharmony_ci zone_block = dev->start_blkaddr 30235e5c12b0Sopenharmony_ci + (blk_zone_sector(blkz) >> log_sectors_per_block); 30245e5c12b0Sopenharmony_ci zone_segno = GET_SEGNO(sbi, zone_block); 30255e5c12b0Sopenharmony_ci if (zone_segno >= MAIN_SEGS(sbi)) 30265e5c12b0Sopenharmony_ci return 0; 30275e5c12b0Sopenharmony_ci 30285e5c12b0Sopenharmony_ci wp_block = dev->start_blkaddr 30295e5c12b0Sopenharmony_ci + (blk_zone_wp_sector(blkz) >> log_sectors_per_block); 30305e5c12b0Sopenharmony_ci wp_segno = GET_SEGNO(sbi, wp_block); 30315e5c12b0Sopenharmony_ci wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno); 30325e5c12b0Sopenharmony_ci 30335e5c12b0Sopenharmony_ci /* if a curseg points to the zone, skip the check */ 30345e5c12b0Sopenharmony_ci for (cs_index = 0; cs_index < NO_CHECK_TYPE; cs_index++) { 30355e5c12b0Sopenharmony_ci cs = &SM_I(sbi)->curseg_array[cs_index]; 30365e5c12b0Sopenharmony_ci if (zone_segno <= cs->segno && 30375e5c12b0Sopenharmony_ci cs->segno < zone_segno + segs_per_zone) 30385e5c12b0Sopenharmony_ci return 0; 30395e5c12b0Sopenharmony_ci } 30405e5c12b0Sopenharmony_ci 30415e5c12b0Sopenharmony_ci last_valid_blkoff = last_vblk_off_in_zone(sbi, zone_segno); 30425e5c12b0Sopenharmony_ci 30435e5c12b0Sopenharmony_ci /* 30445e5c12b0Sopenharmony_ci * When there is no valid block in the zone, check write pointer is 30455e5c12b0Sopenharmony_ci * at zone start. If not, reset the write pointer. 30465e5c12b0Sopenharmony_ci */ 30475e5c12b0Sopenharmony_ci if (last_valid_blkoff < 0 && 30485e5c12b0Sopenharmony_ci blk_zone_wp_sector(blkz) != blk_zone_sector(blkz)) { 30495e5c12b0Sopenharmony_ci if (!c.fix_on) { 30505e5c12b0Sopenharmony_ci MSG(0, "Inconsistent write pointer: wp[0x%x,0x%x]\n", 30515e5c12b0Sopenharmony_ci wp_segno, wp_blkoff); 30525e5c12b0Sopenharmony_ci fsck->chk.wp_inconsistent_zones++; 30535e5c12b0Sopenharmony_ci return 0; 30545e5c12b0Sopenharmony_ci } 30555e5c12b0Sopenharmony_ci 30565e5c12b0Sopenharmony_ci FIX_MSG("Reset write pointer of zone at segment 0x%x", 30575e5c12b0Sopenharmony_ci zone_segno); 30585e5c12b0Sopenharmony_ci ret = f2fs_reset_zone(wpd->dev_index, blkz); 30595e5c12b0Sopenharmony_ci if (ret) { 30605e5c12b0Sopenharmony_ci printf("[FSCK] Write pointer reset failed: %s\n", 30615e5c12b0Sopenharmony_ci dev->path); 30625e5c12b0Sopenharmony_ci return ret; 30635e5c12b0Sopenharmony_ci } 30645e5c12b0Sopenharmony_ci fsck->chk.wp_fixed = 1; 30655e5c12b0Sopenharmony_ci return 0; 30665e5c12b0Sopenharmony_ci } 30675e5c12b0Sopenharmony_ci 30685e5c12b0Sopenharmony_ci /* 30695e5c12b0Sopenharmony_ci * If valid blocks exist in the zone beyond the write pointer, it 30705e5c12b0Sopenharmony_ci * is a bug. No need to fix because the zone is not selected for the 30715e5c12b0Sopenharmony_ci * write. Just report it. 30725e5c12b0Sopenharmony_ci */ 30735e5c12b0Sopenharmony_ci if (last_valid_blkoff + zone_block > wp_block) { 30745e5c12b0Sopenharmony_ci MSG(0, "Unexpected invalid write pointer: wp[0x%x,0x%x]\n", 30755e5c12b0Sopenharmony_ci wp_segno, wp_blkoff); 30765e5c12b0Sopenharmony_ci return 0; 30775e5c12b0Sopenharmony_ci } 30785e5c12b0Sopenharmony_ci 30795e5c12b0Sopenharmony_ci return 0; 30805e5c12b0Sopenharmony_ci} 30815e5c12b0Sopenharmony_ci 30825e5c12b0Sopenharmony_cistatic void fix_wp_sit_alignment(struct f2fs_sb_info *sbi) 30835e5c12b0Sopenharmony_ci{ 30845e5c12b0Sopenharmony_ci unsigned int i; 30855e5c12b0Sopenharmony_ci struct write_pointer_check_data wpd = { sbi, 0 }; 30865e5c12b0Sopenharmony_ci 30875e5c12b0Sopenharmony_ci if (c.zoned_model != F2FS_ZONED_HM) 30885e5c12b0Sopenharmony_ci return; 30895e5c12b0Sopenharmony_ci 30905e5c12b0Sopenharmony_ci for (i = 0; i < MAX_DEVICES; i++) { 30915e5c12b0Sopenharmony_ci if (!c.devices[i].path) 30925e5c12b0Sopenharmony_ci break; 30935e5c12b0Sopenharmony_ci if (c.devices[i].zoned_model != F2FS_ZONED_HM) 30945e5c12b0Sopenharmony_ci break; 30955e5c12b0Sopenharmony_ci 30965e5c12b0Sopenharmony_ci wpd.dev_index = i; 30975e5c12b0Sopenharmony_ci if (f2fs_report_zones(i, chk_and_fix_wp_with_sit, &wpd)) { 30985e5c12b0Sopenharmony_ci printf("[FSCK] Write pointer check failed: %s\n", 30995e5c12b0Sopenharmony_ci c.devices[i].path); 31005e5c12b0Sopenharmony_ci return; 31015e5c12b0Sopenharmony_ci } 31025e5c12b0Sopenharmony_ci } 31035e5c12b0Sopenharmony_ci} 31045e5c12b0Sopenharmony_ci 31055e5c12b0Sopenharmony_ci#else 31065e5c12b0Sopenharmony_ci 31075e5c12b0Sopenharmony_cistatic void fix_wp_sit_alignment(struct f2fs_sb_info *UNUSED(sbi)) 31085e5c12b0Sopenharmony_ci{ 31095e5c12b0Sopenharmony_ci return; 31105e5c12b0Sopenharmony_ci} 31115e5c12b0Sopenharmony_ci 31125e5c12b0Sopenharmony_ci#endif 31135e5c12b0Sopenharmony_ci 31145e5c12b0Sopenharmony_ci/* 31155e5c12b0Sopenharmony_ci * Check and fix consistency with write pointers at the beginning of 31165e5c12b0Sopenharmony_ci * fsck so that following writes by fsck do not fail. 31175e5c12b0Sopenharmony_ci */ 31185e5c12b0Sopenharmony_civoid fsck_chk_and_fix_write_pointers(struct f2fs_sb_info *sbi) 31195e5c12b0Sopenharmony_ci{ 31205e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 31215e5c12b0Sopenharmony_ci 31225e5c12b0Sopenharmony_ci if (c.zoned_model != F2FS_ZONED_HM) 31235e5c12b0Sopenharmony_ci return; 31245e5c12b0Sopenharmony_ci 31255e5c12b0Sopenharmony_ci if (check_curseg_offsets(sbi) && c.fix_on) { 31265e5c12b0Sopenharmony_ci fix_curseg_info(sbi); 31275e5c12b0Sopenharmony_ci fsck->chk.wp_fixed = 1; 31285e5c12b0Sopenharmony_ci } 31295e5c12b0Sopenharmony_ci 31305e5c12b0Sopenharmony_ci fix_wp_sit_alignment(sbi); 31315e5c12b0Sopenharmony_ci} 31325e5c12b0Sopenharmony_ci 31335e5c12b0Sopenharmony_ciint fsck_chk_curseg_info(struct f2fs_sb_info *sbi) 31345e5c12b0Sopenharmony_ci{ 31355e5c12b0Sopenharmony_ci struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 31365e5c12b0Sopenharmony_ci struct curseg_info *curseg; 31375e5c12b0Sopenharmony_ci struct seg_entry *se; 31385e5c12b0Sopenharmony_ci struct f2fs_summary_block *sum_blk; 31395e5c12b0Sopenharmony_ci int i, ret = 0; 31405e5c12b0Sopenharmony_ci 31415e5c12b0Sopenharmony_ci for (i = 0; i < NO_CHECK_TYPE; i++) { 31425e5c12b0Sopenharmony_ci curseg = CURSEG_I(sbi, i); 31435e5c12b0Sopenharmony_ci se = get_seg_entry(sbi, curseg->segno); 31445e5c12b0Sopenharmony_ci sum_blk = curseg->sum_blk; 31455e5c12b0Sopenharmony_ci 31465e5c12b0Sopenharmony_ci if ((get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) && 31475e5c12b0Sopenharmony_ci (i != CURSEG_HOT_DATA && i != CURSEG_HOT_NODE)) 31485e5c12b0Sopenharmony_ci continue; 31495e5c12b0Sopenharmony_ci 31505e5c12b0Sopenharmony_ci if (se->type != i) { 31515e5c12b0Sopenharmony_ci ASSERT_MSG("Incorrect curseg [%d]: segno [0x%x] " 31525e5c12b0Sopenharmony_ci "type(SIT) [%d]", i, curseg->segno, 31535e5c12b0Sopenharmony_ci se->type); 31545e5c12b0Sopenharmony_ci if (c.fix_on || c.preen_mode) 31555e5c12b0Sopenharmony_ci se->type = i; 31565e5c12b0Sopenharmony_ci ret = -1; 31575e5c12b0Sopenharmony_ci } 31585e5c12b0Sopenharmony_ci if (i <= CURSEG_COLD_DATA && IS_SUM_DATA_SEG(sum_blk->footer)) { 31595e5c12b0Sopenharmony_ci continue; 31605e5c12b0Sopenharmony_ci } else if (i > CURSEG_COLD_DATA && IS_SUM_NODE_SEG(sum_blk->footer)) { 31615e5c12b0Sopenharmony_ci continue; 31625e5c12b0Sopenharmony_ci } else { 31635e5c12b0Sopenharmony_ci ASSERT_MSG("Incorrect curseg [%d]: segno [0x%x] " 31645e5c12b0Sopenharmony_ci "type(SSA) [%d]", i, curseg->segno, 31655e5c12b0Sopenharmony_ci sum_blk->footer.entry_type); 31665e5c12b0Sopenharmony_ci if (c.fix_on || c.preen_mode) 31675e5c12b0Sopenharmony_ci sum_blk->footer.entry_type = 31685e5c12b0Sopenharmony_ci i <= CURSEG_COLD_DATA ? 31695e5c12b0Sopenharmony_ci SUM_TYPE_DATA : SUM_TYPE_NODE; 31705e5c12b0Sopenharmony_ci ret = -1; 31715e5c12b0Sopenharmony_ci } 31725e5c12b0Sopenharmony_ci } 31735e5c12b0Sopenharmony_ci 31745e5c12b0Sopenharmony_ci return ret; 31755e5c12b0Sopenharmony_ci} 31765e5c12b0Sopenharmony_ci 31775e5c12b0Sopenharmony_ciint fsck_verify(struct f2fs_sb_info *sbi) 31785e5c12b0Sopenharmony_ci{ 31795e5c12b0Sopenharmony_ci unsigned int i = 0; 31805e5c12b0Sopenharmony_ci int ret = 0; 31815e5c12b0Sopenharmony_ci int force = 0; 31825e5c12b0Sopenharmony_ci u32 nr_unref_nid = 0; 31835e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 31845e5c12b0Sopenharmony_ci struct hard_link_node *node = NULL; 31855e5c12b0Sopenharmony_ci bool verify_failed = false; 31865e5c12b0Sopenharmony_ci uint64_t max_blks, data_secs, node_secs, free_blks; 31875e5c12b0Sopenharmony_ci 31885e5c12b0Sopenharmony_ci if (c.show_file_map) 31895e5c12b0Sopenharmony_ci return 0; 31905e5c12b0Sopenharmony_ci 31915e5c12b0Sopenharmony_ci printf("\n"); 31925e5c12b0Sopenharmony_ci 31935e5c12b0Sopenharmony_ci if (c.zoned_model == F2FS_ZONED_HM) { 31945e5c12b0Sopenharmony_ci printf("[FSCK] Write pointers consistency "); 31955e5c12b0Sopenharmony_ci if (fsck->chk.wp_inconsistent_zones == 0x0) { 31965e5c12b0Sopenharmony_ci printf(" [Ok..]\n"); 31975e5c12b0Sopenharmony_ci } else { 31985e5c12b0Sopenharmony_ci printf(" [Fail] [0x%x]\n", 31995e5c12b0Sopenharmony_ci fsck->chk.wp_inconsistent_zones); 32005e5c12b0Sopenharmony_ci verify_failed = true; 32015e5c12b0Sopenharmony_ci } 32025e5c12b0Sopenharmony_ci 32035e5c12b0Sopenharmony_ci if (fsck->chk.wp_fixed && c.fix_on) 32045e5c12b0Sopenharmony_ci force = 1; 32055e5c12b0Sopenharmony_ci } 32065e5c12b0Sopenharmony_ci 32075e5c12b0Sopenharmony_ci if (c.feature & cpu_to_le32(F2FS_FEATURE_LOST_FOUND)) { 32085e5c12b0Sopenharmony_ci for (i = 0; i < fsck->nr_nat_entries; i++) 32095e5c12b0Sopenharmony_ci if (f2fs_test_bit(i, fsck->nat_area_bitmap) != 0) 32105e5c12b0Sopenharmony_ci break; 32115e5c12b0Sopenharmony_ci if (i < fsck->nr_nat_entries) { 32125e5c12b0Sopenharmony_ci i = fsck_reconnect_file(sbi); 32135e5c12b0Sopenharmony_ci printf("[FSCK] Reconnect %u files to lost+found\n", i); 32145e5c12b0Sopenharmony_ci } 32155e5c12b0Sopenharmony_ci } 32165e5c12b0Sopenharmony_ci 32175e5c12b0Sopenharmony_ci for (i = 0; i < fsck->nr_nat_entries; i++) { 32185e5c12b0Sopenharmony_ci if (f2fs_test_bit(i, fsck->nat_area_bitmap) != 0) { 32195e5c12b0Sopenharmony_ci struct node_info ni; 32205e5c12b0Sopenharmony_ci 32215e5c12b0Sopenharmony_ci get_node_info(sbi, i, &ni); 32225e5c12b0Sopenharmony_ci printf("NID[0x%x] is unreachable, blkaddr:0x%x\n", 32235e5c12b0Sopenharmony_ci i, ni.blk_addr); 32245e5c12b0Sopenharmony_ci nr_unref_nid++; 32255e5c12b0Sopenharmony_ci } 32265e5c12b0Sopenharmony_ci } 32275e5c12b0Sopenharmony_ci 32285e5c12b0Sopenharmony_ci if (fsck->hard_link_list_head != NULL) { 32295e5c12b0Sopenharmony_ci node = fsck->hard_link_list_head; 32305e5c12b0Sopenharmony_ci while (node) { 32315e5c12b0Sopenharmony_ci printf("NID[0x%x] has [0x%x] more unreachable links\n", 32325e5c12b0Sopenharmony_ci node->nid, node->links); 32335e5c12b0Sopenharmony_ci node = node->next; 32345e5c12b0Sopenharmony_ci } 32355e5c12b0Sopenharmony_ci c.bug_on = 1; 32365e5c12b0Sopenharmony_ci } 32375e5c12b0Sopenharmony_ci 32385e5c12b0Sopenharmony_ci data_secs = round_up(sbi->total_valid_node_count, BLKS_PER_SEC(sbi)); 32395e5c12b0Sopenharmony_ci node_secs = round_up(sbi->total_valid_block_count - 32405e5c12b0Sopenharmony_ci sbi->total_valid_node_count, BLKS_PER_SEC(sbi)); 32415e5c12b0Sopenharmony_ci free_blks = (sbi->total_sections - data_secs - node_secs) * 32425e5c12b0Sopenharmony_ci BLKS_PER_SEC(sbi); 32435e5c12b0Sopenharmony_ci max_blks = SM_I(sbi)->main_blkaddr + (data_secs + node_secs) * 32445e5c12b0Sopenharmony_ci BLKS_PER_SEC(sbi); 32455e5c12b0Sopenharmony_ci printf("[FSCK] Max image size: %"PRIu64" MB, Free space: %"PRIu64" MB\n", 32465e5c12b0Sopenharmony_ci max_blks >> 8, free_blks >> 8); 32475e5c12b0Sopenharmony_ci printf("[FSCK] Unreachable nat entries "); 32485e5c12b0Sopenharmony_ci if (nr_unref_nid == 0x0) { 32495e5c12b0Sopenharmony_ci printf(" [Ok..] [0x%x]\n", nr_unref_nid); 32505e5c12b0Sopenharmony_ci } else { 32515e5c12b0Sopenharmony_ci printf(" [Fail] [0x%x]\n", nr_unref_nid); 32525e5c12b0Sopenharmony_ci verify_failed = true; 32535e5c12b0Sopenharmony_ci } 32545e5c12b0Sopenharmony_ci 32555e5c12b0Sopenharmony_ci printf("[FSCK] SIT valid block bitmap checking "); 32565e5c12b0Sopenharmony_ci if (memcmp(fsck->sit_area_bitmap, fsck->main_area_bitmap, 32575e5c12b0Sopenharmony_ci fsck->sit_area_bitmap_sz) == 0x0) { 32585e5c12b0Sopenharmony_ci printf("[Ok..]\n"); 32595e5c12b0Sopenharmony_ci } else { 32605e5c12b0Sopenharmony_ci printf("[Fail]\n"); 32615e5c12b0Sopenharmony_ci verify_failed = true; 32625e5c12b0Sopenharmony_ci } 32635e5c12b0Sopenharmony_ci 32645e5c12b0Sopenharmony_ci printf("[FSCK] Hard link checking for regular file "); 32655e5c12b0Sopenharmony_ci if (fsck->hard_link_list_head == NULL) { 32665e5c12b0Sopenharmony_ci printf(" [Ok..] [0x%x]\n", fsck->chk.multi_hard_link_files); 32675e5c12b0Sopenharmony_ci } else { 32685e5c12b0Sopenharmony_ci printf(" [Fail] [0x%x]\n", fsck->chk.multi_hard_link_files); 32695e5c12b0Sopenharmony_ci verify_failed = true; 32705e5c12b0Sopenharmony_ci } 32715e5c12b0Sopenharmony_ci 32725e5c12b0Sopenharmony_ci printf("[FSCK] valid_block_count matching with CP "); 32735e5c12b0Sopenharmony_ci if (sbi->total_valid_block_count == fsck->chk.valid_blk_cnt) { 32745e5c12b0Sopenharmony_ci printf(" [Ok..] [0x%x]\n", (u32)fsck->chk.valid_blk_cnt); 32755e5c12b0Sopenharmony_ci } else { 32765e5c12b0Sopenharmony_ci printf(" [Fail] [0x%x]\n", (u32)fsck->chk.valid_blk_cnt); 32775e5c12b0Sopenharmony_ci verify_failed = true; 32785e5c12b0Sopenharmony_ci } 32795e5c12b0Sopenharmony_ci 32805e5c12b0Sopenharmony_ci printf("[FSCK] valid_node_count matching with CP (de lookup) "); 32815e5c12b0Sopenharmony_ci if (sbi->total_valid_node_count == fsck->chk.valid_node_cnt) { 32825e5c12b0Sopenharmony_ci printf(" [Ok..] [0x%x]\n", fsck->chk.valid_node_cnt); 32835e5c12b0Sopenharmony_ci } else { 32845e5c12b0Sopenharmony_ci printf(" [Fail] [0x%x]\n", fsck->chk.valid_node_cnt); 32855e5c12b0Sopenharmony_ci verify_failed = true; 32865e5c12b0Sopenharmony_ci } 32875e5c12b0Sopenharmony_ci 32885e5c12b0Sopenharmony_ci printf("[FSCK] valid_node_count matching with CP (nat lookup)"); 32895e5c12b0Sopenharmony_ci if (sbi->total_valid_node_count == fsck->chk.valid_nat_entry_cnt) { 32905e5c12b0Sopenharmony_ci printf(" [Ok..] [0x%x]\n", fsck->chk.valid_nat_entry_cnt); 32915e5c12b0Sopenharmony_ci } else { 32925e5c12b0Sopenharmony_ci printf(" [Fail] [0x%x]\n", fsck->chk.valid_nat_entry_cnt); 32935e5c12b0Sopenharmony_ci verify_failed = true; 32945e5c12b0Sopenharmony_ci } 32955e5c12b0Sopenharmony_ci 32965e5c12b0Sopenharmony_ci printf("[FSCK] valid_inode_count matched with CP "); 32975e5c12b0Sopenharmony_ci if (sbi->total_valid_inode_count == fsck->chk.valid_inode_cnt) { 32985e5c12b0Sopenharmony_ci printf(" [Ok..] [0x%x]\n", fsck->chk.valid_inode_cnt); 32995e5c12b0Sopenharmony_ci } else { 33005e5c12b0Sopenharmony_ci printf(" [Fail] [0x%x]\n", fsck->chk.valid_inode_cnt); 33015e5c12b0Sopenharmony_ci verify_failed = true; 33025e5c12b0Sopenharmony_ci } 33035e5c12b0Sopenharmony_ci 33045e5c12b0Sopenharmony_ci printf("[FSCK] free segment_count matched with CP "); 33055e5c12b0Sopenharmony_ci if (le32_to_cpu(F2FS_CKPT(sbi)->free_segment_count) == 33065e5c12b0Sopenharmony_ci fsck->chk.sit_free_segs) { 33075e5c12b0Sopenharmony_ci printf(" [Ok..] [0x%x]\n", fsck->chk.sit_free_segs); 33085e5c12b0Sopenharmony_ci } else { 33095e5c12b0Sopenharmony_ci printf(" [Fail] [0x%x]\n", fsck->chk.sit_free_segs); 33105e5c12b0Sopenharmony_ci verify_failed = true; 33115e5c12b0Sopenharmony_ci } 33125e5c12b0Sopenharmony_ci 33135e5c12b0Sopenharmony_ci printf("[FSCK] next block offset is free "); 33145e5c12b0Sopenharmony_ci if (check_curseg_offsets(sbi) == 0) { 33155e5c12b0Sopenharmony_ci printf(" [Ok..]\n"); 33165e5c12b0Sopenharmony_ci } else { 33175e5c12b0Sopenharmony_ci printf(" [Fail]\n"); 33185e5c12b0Sopenharmony_ci verify_failed = true; 33195e5c12b0Sopenharmony_ci } 33205e5c12b0Sopenharmony_ci 33215e5c12b0Sopenharmony_ci printf("[FSCK] fixing SIT types\n"); 33225e5c12b0Sopenharmony_ci if (check_sit_types(sbi) != 0) 33235e5c12b0Sopenharmony_ci force = 1; 33245e5c12b0Sopenharmony_ci 33255e5c12b0Sopenharmony_ci printf("[FSCK] other corrupted bugs "); 33265e5c12b0Sopenharmony_ci if (c.bug_on == 0) { 33275e5c12b0Sopenharmony_ci printf(" [Ok..]\n"); 33285e5c12b0Sopenharmony_ci } else { 33295e5c12b0Sopenharmony_ci printf(" [Fail]\n"); 33305e5c12b0Sopenharmony_ci ret = EXIT_ERR_CODE; 33315e5c12b0Sopenharmony_ci } 33325e5c12b0Sopenharmony_ci 33335e5c12b0Sopenharmony_ci if (verify_failed) { 33345e5c12b0Sopenharmony_ci ret = EXIT_ERR_CODE; 33355e5c12b0Sopenharmony_ci c.bug_on = 1; 33365e5c12b0Sopenharmony_ci } 33375e5c12b0Sopenharmony_ci 33385e5c12b0Sopenharmony_ci#ifndef WITH_OHOS 33395e5c12b0Sopenharmony_ci if (nr_unref_nid && !c.ro) { 33405e5c12b0Sopenharmony_ci char ans[255] = {0}; 33415e5c12b0Sopenharmony_ci int res; 33425e5c12b0Sopenharmony_ci 33435e5c12b0Sopenharmony_ci printf("\nDo you want to restore lost files into ./lost_found/? [Y/N] "); 33445e5c12b0Sopenharmony_ci res = scanf("%s", ans); 33455e5c12b0Sopenharmony_ci ASSERT(res >= 0); 33465e5c12b0Sopenharmony_ci if (!strcasecmp(ans, "y")) { 33475e5c12b0Sopenharmony_ci for (i = 0; i < fsck->nr_nat_entries; i++) { 33485e5c12b0Sopenharmony_ci if (f2fs_test_bit(i, fsck->nat_area_bitmap)) 33495e5c12b0Sopenharmony_ci dump_node(sbi, i, 1); 33505e5c12b0Sopenharmony_ci } 33515e5c12b0Sopenharmony_ci } 33525e5c12b0Sopenharmony_ci } 33535e5c12b0Sopenharmony_ci#endif 33545e5c12b0Sopenharmony_ci 33555e5c12b0Sopenharmony_ci /* fix global metadata */ 33565e5c12b0Sopenharmony_ci if (force || (c.fix_on && f2fs_dev_is_writable())) { 33575e5c12b0Sopenharmony_ci struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); 33585e5c12b0Sopenharmony_ci struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); 33595e5c12b0Sopenharmony_ci 33605e5c12b0Sopenharmony_ci if (force || c.bug_on || c.bug_nat_bits || c.quota_fixed) { 33615e5c12b0Sopenharmony_ci /* flush nats to write_nit_bits below */ 33625e5c12b0Sopenharmony_ci flush_journal_entries(sbi); 33635e5c12b0Sopenharmony_ci fix_hard_links(sbi); 33645e5c12b0Sopenharmony_ci fix_nat_entries(sbi); 33655e5c12b0Sopenharmony_ci rewrite_sit_area_bitmap(sbi); 33665e5c12b0Sopenharmony_ci fix_wp_sit_alignment(sbi); 33675e5c12b0Sopenharmony_ci fix_curseg_info(sbi); 33685e5c12b0Sopenharmony_ci fix_checksum(sbi); 33695e5c12b0Sopenharmony_ci fix_checkpoints(sbi); 33705e5c12b0Sopenharmony_ci } else if (is_set_ckpt_flags(cp, CP_FSCK_FLAG) || 33715e5c12b0Sopenharmony_ci is_set_ckpt_flags(cp, CP_QUOTA_NEED_FSCK_FLAG)) { 33725e5c12b0Sopenharmony_ci write_checkpoints(sbi); 33735e5c12b0Sopenharmony_ci } 33745e5c12b0Sopenharmony_ci 33755e5c12b0Sopenharmony_ci if (c.abnormal_stop) 33765e5c12b0Sopenharmony_ci memset(sb->s_stop_reason, 0, MAX_STOP_REASON); 33775e5c12b0Sopenharmony_ci 33785e5c12b0Sopenharmony_ci if (c.fs_errors) 33795e5c12b0Sopenharmony_ci memset(sb->s_errors, 0, MAX_F2FS_ERRORS); 33805e5c12b0Sopenharmony_ci 33815e5c12b0Sopenharmony_ci if (c.abnormal_stop || c.fs_errors) 33825e5c12b0Sopenharmony_ci update_superblock(sb, SB_MASK_ALL); 33835e5c12b0Sopenharmony_ci 33845e5c12b0Sopenharmony_ci /* to return FSCK_ERROR_CORRECTED */ 33855e5c12b0Sopenharmony_ci ret = 0; 33865e5c12b0Sopenharmony_ci } 33875e5c12b0Sopenharmony_ci return ret; 33885e5c12b0Sopenharmony_ci} 33895e5c12b0Sopenharmony_ci 33905e5c12b0Sopenharmony_civoid fsck_free(struct f2fs_sb_info *sbi) 33915e5c12b0Sopenharmony_ci{ 33925e5c12b0Sopenharmony_ci struct f2fs_fsck *fsck = F2FS_FSCK(sbi); 33935e5c12b0Sopenharmony_ci 33945e5c12b0Sopenharmony_ci if (fsck->qctx) 33955e5c12b0Sopenharmony_ci quota_release_context(&fsck->qctx); 33965e5c12b0Sopenharmony_ci 33975e5c12b0Sopenharmony_ci if (fsck->main_area_bitmap) 33985e5c12b0Sopenharmony_ci free(fsck->main_area_bitmap); 33995e5c12b0Sopenharmony_ci 34005e5c12b0Sopenharmony_ci if (fsck->nat_area_bitmap) 34015e5c12b0Sopenharmony_ci free(fsck->nat_area_bitmap); 34025e5c12b0Sopenharmony_ci 34035e5c12b0Sopenharmony_ci if (fsck->sit_area_bitmap) 34045e5c12b0Sopenharmony_ci free(fsck->sit_area_bitmap); 34055e5c12b0Sopenharmony_ci 34065e5c12b0Sopenharmony_ci if (fsck->entries) 34075e5c12b0Sopenharmony_ci free(fsck->entries); 34085e5c12b0Sopenharmony_ci 34095e5c12b0Sopenharmony_ci if (tree_mark) 34105e5c12b0Sopenharmony_ci free(tree_mark); 34115e5c12b0Sopenharmony_ci 34125e5c12b0Sopenharmony_ci while (fsck->dentry) { 34135e5c12b0Sopenharmony_ci struct f2fs_dentry *dentry = fsck->dentry; 34145e5c12b0Sopenharmony_ci 34155e5c12b0Sopenharmony_ci fsck->dentry = fsck->dentry->next; 34165e5c12b0Sopenharmony_ci free(dentry); 34175e5c12b0Sopenharmony_ci } 34185e5c12b0Sopenharmony_ci} 3419