aboutsummaryrefslogtreecommitdiffstats
path: root/fsck/fsck.c
diff options
context:
space:
mode:
Diffstat (limited to 'fsck/fsck.c')
-rw-r--r--fsck/fsck.c833
1 files changed, 499 insertions, 334 deletions
diff --git a/fsck/fsck.c b/fsck/fsck.c
index ba29ab7..d0819c4 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -11,9 +11,32 @@
#include "fsck.h"
char *tree_mark;
-int tree_mark_size = 256;
+uint32_t tree_mark_size = 256;
-static int add_into_hard_link_list(struct f2fs_sb_info *sbi, u32 nid, u32 link_cnt)
+static inline int f2fs_set_main_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+
+ return f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->main_area_bitmap);
+}
+
+static inline int f2fs_test_main_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+
+ return f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk),
+ fsck->main_area_bitmap);
+}
+
+static inline int f2fs_test_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+
+ return f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->sit_area_bitmap);
+}
+
+static int add_into_hard_link_list(struct f2fs_sb_info *sbi,
+ u32 nid, u32 link_cnt)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct hard_link_node *node = NULL, *tmp = NULL, *prev = NULL;
@@ -57,10 +80,8 @@ static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid)
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct hard_link_node *node = NULL, *prev = NULL;
- if (fsck->hard_link_list_head == NULL) {
- ASSERT(0);
- return -1;
- }
+ if (fsck->hard_link_list_head == NULL)
+ return -EINVAL;
node = fsck->hard_link_list_head;
@@ -69,10 +90,8 @@ static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid)
node = node->next;
}
- if (node == NULL || (nid != node->nid)) {
- ASSERT(0);
- return -1;
- }
+ if (node == NULL || (nid != node->nid))
+ return -EINVAL;
/* Decrease link count */
node->links = node->links - 1;
@@ -85,40 +104,38 @@ static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid)
prev->next = node->next;
free(node);
}
-
return 0;
-
}
-static int is_valid_ssa_node_blk(struct f2fs_sb_info *sbi, u32 nid, u32 blk_addr)
+static int is_valid_ssa_node_blk(struct f2fs_sb_info *sbi, u32 nid,
+ u32 blk_addr)
{
int ret = 0;
struct f2fs_summary sum_entry;
ret = get_sum_entry(sbi, blk_addr, &sum_entry);
- ASSERT(ret >= 0);
- if (ret == SEG_TYPE_DATA || ret == SEG_TYPE_CUR_DATA) {
- ASSERT_MSG(0, "Summary footer is not a node segment summary\n");;
- } else if (ret == SEG_TYPE_NODE) {
- if (le32_to_cpu(sum_entry.nid) != nid) {
- DBG(0, "nid [0x%x]\n", nid);
- DBG(0, "target blk_addr [0x%x]\n", blk_addr);
- DBG(0, "summary blk_addr [0x%x]\n",
- GET_SUM_BLKADDR(sbi, GET_SEGNO(sbi, blk_addr)));
- DBG(0, "seg no / offset [0x%x / 0x%x]\n",
- GET_SEGNO(sbi, blk_addr), OFFSET_IN_SEG(sbi, blk_addr));
- DBG(0, "summary_entry.nid [0x%x]\n", le32_to_cpu(sum_entry.nid));
- DBG(0, "--> node block's nid [0x%x]\n", nid);
- ASSERT_MSG(0, "Invalid node seg summary\n");
- }
- } else if (ret == SEG_TYPE_CUR_NODE) {
- /* current node segment has no ssa */
- } else {
- ASSERT_MSG(0, "Invalid return value of 'get_sum_entry'");
+ if (ret != SEG_TYPE_NODE && ret != SEG_TYPE_CUR_NODE) {
+ ASSERT_MSG("Summary footer is not for node segment");
+ return -EINVAL;
+ }
+
+ if (le32_to_cpu(sum_entry.nid) != nid) {
+ DBG(0, "nid [0x%x]\n", nid);
+ DBG(0, "target blk_addr [0x%x]\n", blk_addr);
+ DBG(0, "summary blk_addr [0x%x]\n",
+ GET_SUM_BLKADDR(sbi,
+ GET_SEGNO(sbi, blk_addr)));
+ DBG(0, "seg no / offset [0x%x / 0x%x]\n",
+ GET_SEGNO(sbi, blk_addr),
+ OFFSET_IN_SEG(sbi, blk_addr));
+ DBG(0, "summary_entry.nid [0x%x]\n",
+ le32_to_cpu(sum_entry.nid));
+ DBG(0, "--> node block's nid [0x%x]\n", nid);
+ ASSERT_MSG("Invalid node seg summary\n");
+ return -EINVAL;
}
-
- return 1;
+ return 0;
}
static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
@@ -128,204 +145,250 @@ static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
struct f2fs_summary sum_entry;
ret = get_sum_entry(sbi, blk_addr, &sum_entry);
- ASSERT(ret == SEG_TYPE_DATA || ret == SEG_TYPE_CUR_DATA);
+
+ if (ret != SEG_TYPE_DATA && ret != SEG_TYPE_CUR_DATA) {
+ ASSERT_MSG("Summary footer is not for data segment");
+ return -EINVAL;
+ }
if (le32_to_cpu(sum_entry.nid) != parent_nid ||
sum_entry.version != version ||
le16_to_cpu(sum_entry.ofs_in_node) != idx_in_node) {
- DBG(0, "summary_entry.nid [0x%x]\n", le32_to_cpu(sum_entry.nid));
- DBG(0, "summary_entry.version [0x%x]\n", sum_entry.version);
- DBG(0, "summary_entry.ofs_in_node [0x%x]\n", le16_to_cpu(sum_entry.ofs_in_node));
-
+ DBG(0, "summary_entry.nid [0x%x]\n",
+ le32_to_cpu(sum_entry.nid));
+ DBG(0, "summary_entry.version [0x%x]\n",
+ sum_entry.version);
+ DBG(0, "summary_entry.ofs_in_node [0x%x]\n",
+ le16_to_cpu(sum_entry.ofs_in_node));
DBG(0, "parent nid [0x%x]\n", parent_nid);
DBG(0, "version from nat [0x%x]\n", version);
DBG(0, "idx in parent node [0x%x]\n", idx_in_node);
DBG(0, "Target data block addr [0x%x]\n", blk_addr);
- ASSERT_MSG(0, "Invalid data seg summary\n");
+ ASSERT_MSG("Invalid data seg summary\n");
+ return -EINVAL;
}
-
- return 1;
+ return 0;
}
-int fsck_chk_node_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- enum NODE_TYPE ntype,
- u32 *blk_cnt)
+static int sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid,
+ struct f2fs_node *node_blk,
+ enum FILE_TYPE ftype, enum NODE_TYPE ntype,
+ struct node_info *ni)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
- struct node_info ni;
- struct f2fs_node *node_blk = NULL;
- int ret = 0;
+ int ret;
+
+ if (!IS_VALID_NID(sbi, nid)) {
+ ASSERT_MSG("nid is not valid. [0x%x]", nid);
+ return -EINVAL;
+ }
- IS_VALID_NID(sbi, nid);
+ get_node_info(sbi, nid, ni);
+ if (ni->blk_addr == NEW_ADDR) {
+ ASSERT_MSG("nid is NEW_ADDR. [0x%x]", nid);
+ return -EINVAL;
+ }
- if (ftype != F2FS_FT_ORPHAN ||
- f2fs_test_bit(nid, fsck->nat_area_bitmap) != 0x0)
- f2fs_clear_bit(nid, fsck->nat_area_bitmap);
- else
- ASSERT_MSG(0, "nid duplicated [0x%x]\n", nid);
+ if (!IS_VALID_BLK_ADDR(sbi, ni->blk_addr)) {
+ ASSERT_MSG("blkaddres is not valid. [0x%x]", ni->blk_addr);
+ return -EINVAL;
+ }
- ret = get_node_info(sbi, nid, &ni);
+ if (is_valid_ssa_node_blk(sbi, nid, ni->blk_addr)) {
+ ASSERT_MSG("summary node block is not valid. [0x%x]", nid);
+ return -EINVAL;
+ }
+
+ ret = dev_read_block(node_blk, ni->blk_addr);
ASSERT(ret >= 0);
- /* Is it reserved block?
- * if block addresss was 0xffff,ffff,ffff,ffff
- * it means that block was already allocated, but not stored in disk
- */
- if (ni.blk_addr == NEW_ADDR) {
- fsck->chk.valid_blk_cnt++;
- fsck->chk.valid_node_cnt++;
- if (ntype == TYPE_INODE)
- fsck->chk.valid_inode_cnt++;
- return 0;
+ if (ntype == TYPE_INODE &&
+ node_blk->footer.nid != node_blk->footer.ino) {
+ ASSERT_MSG("nid[0x%x] footer.nid[0x%x] footer.ino[0x%x]",
+ nid, le32_to_cpu(node_blk->footer.nid),
+ le32_to_cpu(node_blk->footer.ino));
+ return -EINVAL;
+ }
+ if (ntype != TYPE_INODE &&
+ node_blk->footer.nid == node_blk->footer.ino) {
+ ASSERT_MSG("nid[0x%x] footer.nid[0x%x] footer.ino[0x%x]",
+ nid, le32_to_cpu(node_blk->footer.nid),
+ le32_to_cpu(node_blk->footer.ino));
+ return -EINVAL;
}
- IS_VALID_BLK_ADDR(sbi, ni.blk_addr);
+ if (le32_to_cpu(node_blk->footer.nid) != nid) {
+ ASSERT_MSG("nid[0x%x] blk_addr[0x%x] footer.nid[0x%x]",
+ nid, ni->blk_addr,
+ le32_to_cpu(node_blk->footer.nid));
+ return -EINVAL;
+ }
- is_valid_ssa_node_blk(sbi, nid, ni.blk_addr);
+ if (ntype == TYPE_XATTR) {
+ u32 flag = le32_to_cpu(node_blk->footer.flag);
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->sit_area_bitmap) == 0x0) {
- DBG(0, "SIT bitmap is 0x0. blk_addr[0x%x]\n", ni.blk_addr);
- ASSERT(0);
+ if ((flag >> OFFSET_BIT_SHIFT) != XATTR_NODE_OFFSET) {
+ ASSERT_MSG("xnid[0x%x] has wrong ofs:[0x%x]",
+ nid, flag);
+ return -EINVAL;
+ }
+ }
+
+ if ((ntype == TYPE_INODE && ftype == F2FS_FT_DIR) ||
+ (ntype == TYPE_XATTR && ftype == F2FS_FT_XATTR)) {
+ /* not included '.' & '..' */
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) != 0) {
+ ASSERT_MSG("Duplicated node blk. nid[0x%x][0x%x]\n",
+ nid, ni->blk_addr);
+ return -EINVAL;
+ }
}
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) == 0x0) {
+ /* workaround to fix later */
+ if (ftype != F2FS_FT_ORPHAN ||
+ f2fs_test_bit(nid, fsck->nat_area_bitmap) != 0)
+ f2fs_clear_bit(nid, fsck->nat_area_bitmap);
+ else
+ ASSERT_MSG("orphan or xattr nid is duplicated [0x%x]\n",
+ nid);
+
+ if (f2fs_test_sit_bitmap(sbi, ni->blk_addr) == 0)
+ ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]",
+ ni->blk_addr);
+
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) {
fsck->chk.valid_blk_cnt++;
fsck->chk.valid_node_cnt++;
}
+ return 0;
+}
+
+static int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino,
+ u32 x_nid, u32 *blk_cnt)
+{
+ struct f2fs_node *node_blk = NULL;
+ struct node_info ni;
+ int ret = 0;
+
+ if (x_nid == 0x0)
+ return 0;
node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
ASSERT(node_blk != NULL);
- ret = dev_read_block(node_blk, ni.blk_addr);
- ASSERT(ret >= 0);
+ /* Sanity check */
+ if (sanity_check_nid(sbi, x_nid, node_blk,
+ F2FS_FT_XATTR, TYPE_XATTR, &ni)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ *blk_cnt = *blk_cnt + 1;
+ f2fs_set_main_bitmap(sbi, ni.blk_addr);
+ DBG(2, "ino[0x%x] x_nid[0x%x]\n", ino, x_nid);
+out:
+ free(node_blk);
+ return ret;
+}
- ASSERT_MSG(nid == le32_to_cpu(node_blk->footer.nid),
- "nid[0x%x] blk_addr[0x%x] footer.nid[0x%x]\n",
- nid, ni.blk_addr, le32_to_cpu(node_blk->footer.nid));
+int fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ u32 nid, enum FILE_TYPE ftype, enum NODE_TYPE ntype,
+ u32 *blk_cnt)
+{
+ struct node_info ni;
+ struct f2fs_node *node_blk = NULL;
+
+ node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
+ ASSERT(node_blk != NULL);
+
+ if (sanity_check_nid(sbi, nid, node_blk, ftype, ntype, &ni))
+ goto err;
if (ntype == TYPE_INODE) {
- ret = fsck_chk_inode_blk(sbi,
- nid,
- ftype,
- node_blk,
- blk_cnt,
- &ni);
+ fsck_chk_inode_blk(sbi, nid, ftype, node_blk, blk_cnt, &ni);
} else {
- /* it's not inode */
- ASSERT(node_blk->footer.nid != node_blk->footer.ino);
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) != 0) {
- DBG(0, "Duplicated node block. ino[0x%x][0x%x]\n", nid, ni.blk_addr);
- ASSERT(0);
- }
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap);
+ f2fs_set_main_bitmap(sbi, ni.blk_addr);
switch (ntype) {
case TYPE_DIRECT_NODE:
- ret = fsck_chk_dnode_blk(sbi,
- inode,
- nid,
- ftype,
- node_blk,
- blk_cnt,
- &ni);
+ fsck_chk_dnode_blk(sbi, inode, nid, ftype, node_blk,
+ blk_cnt, &ni);
break;
case TYPE_INDIRECT_NODE:
- ret = fsck_chk_idnode_blk(sbi,
- inode,
- nid,
- ftype,
- node_blk,
+ fsck_chk_idnode_blk(sbi, inode, ftype, node_blk,
blk_cnt);
break;
case TYPE_DOUBLE_INDIRECT_NODE:
- ret = fsck_chk_didnode_blk(sbi,
- inode,
- nid,
- ftype,
- node_blk,
+ fsck_chk_didnode_blk(sbi, inode, ftype, node_blk,
blk_cnt);
break;
default:
ASSERT(0);
}
}
- ASSERT(ret >= 0);
-
free(node_blk);
return 0;
+err:
+ free(node_blk);
+ return -EINVAL;
}
-int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt,
- struct node_info *ni)
+/* start with valid nid and blkaddr */
+void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
+ enum FILE_TYPE ftype, struct f2fs_node *node_blk,
+ u32 *blk_cnt, struct node_info *ni)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
u32 child_cnt = 0, child_files = 0;
enum NODE_TYPE ntype;
u32 i_links = le32_to_cpu(node_blk->i.i_links);
u64 i_blocks = le64_to_cpu(node_blk->i.i_blocks);
- int idx = 0;
- int ret = 0;
-
- ASSERT(node_blk->footer.nid == node_blk->footer.ino);
- ASSERT(le32_to_cpu(node_blk->footer.nid) == nid);
+ unsigned int idx = 0;
+ int need_fix = 0;
+ int ret;
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) == 0x0)
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0)
fsck->chk.valid_inode_cnt++;
- /* Orphan node. i_links should be 0 */
- if (ftype == F2FS_FT_ORPHAN) {
- ASSERT(i_links == 0);
- } else {
- ASSERT(i_links > 0);
- }
-
if (ftype == F2FS_FT_DIR) {
-
- /* not included '.' & '..' */
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) != 0) {
- DBG(0, "Duplicated inode blk. ino[0x%x][0x%x]\n", nid, ni->blk_addr);
- ASSERT(0);
- }
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap);
-
+ f2fs_set_main_bitmap(sbi, ni->blk_addr);
} else {
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap) == 0x0) {
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni->blk_addr), fsck->main_area_bitmap);
+ if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) {
+ f2fs_set_main_bitmap(sbi, ni->blk_addr);
if (i_links > 1) {
/* First time. Create new hard link node */
add_into_hard_link_list(sbi, nid, i_links);
fsck->chk.multi_hard_link_files++;
}
} else {
- if (i_links <= 1) {
- DBG(0, "Error. Node ID [0x%x]."
- " There are one more hard links."
- " But i_links is [0x%x]\n",
+ DBG(3, "[0x%x] has hard links [0x%x]\n", nid, i_links);
+ if (find_and_dec_hard_link_list(sbi, nid)) {
+ ASSERT_MSG("[0x%x] needs more i_links=0x%x",
nid, i_links);
- ASSERT(0);
+ if (config.fix_on) {
+ node_blk->i.i_links =
+ cpu_to_le32(i_links + 1);
+ need_fix = 1;
+ FIX_MSG("File: 0x%x "
+ "i_links= 0x%x -> 0x%x",
+ nid, i_links, i_links + 1);
+ }
}
-
- DBG(3, "ino[0x%x] has hard links [0x%x]\n", nid, i_links);
- ret = find_and_dec_hard_link_list(sbi, nid);
- ASSERT(ret >= 0);
-
/* No need to go deep into the node */
- goto out;
+ return;
}
}
- fsck_chk_xattr_blk(sbi, nid, le32_to_cpu(node_blk->i.i_xattr_nid), blk_cnt);
+ if (fsck_chk_xattr_blk(sbi, nid,
+ le32_to_cpu(node_blk->i.i_xattr_nid), blk_cnt) &&
+ config.fix_on) {
+ node_blk->i.i_xattr_nid = 0;
+ need_fix = 1;
+ FIX_MSG("Remove xattr block: 0x%x, x_nid = 0x%x",
+ nid, le32_to_cpu(node_blk->i.i_xattr_nid));
+ }
if (ftype == F2FS_FT_CHRDEV || ftype == F2FS_FT_BLKDEV ||
ftype == F2FS_FT_FIFO || ftype == F2FS_FT_SOCK)
@@ -338,18 +401,18 @@ int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
/* check data blocks in inode */
for (idx = 0; idx < ADDRS_PER_INODE(&node_blk->i); idx++) {
if (le32_to_cpu(node_blk->i.i_addr[idx]) != 0) {
- *blk_cnt = *blk_cnt + 1;
ret = fsck_chk_data_blk(sbi,
- &node_blk->i,
le32_to_cpu(node_blk->i.i_addr[idx]),
- &child_cnt,
- &child_files,
+ &child_cnt, &child_files,
(i_blocks == *blk_cnt),
- ftype,
- nid,
- idx,
- ni->version);
- ASSERT(ret >= 0);
+ ftype, nid, idx, ni->version);
+ if (!ret) {
+ *blk_cnt = *blk_cnt + 1;
+ } else if (config.fix_on) {
+ node_blk->i.i_addr[idx] = 0;
+ need_fix = 1;
+ FIX_MSG("[0x%x] i_addr[%d] = 0", nid, idx);
+ }
}
}
@@ -365,114 +428,120 @@ int fsck_chk_inode_blk(struct f2fs_sb_info *sbi,
ASSERT(0);
if (le32_to_cpu(node_blk->i.i_nid[idx]) != 0) {
- *blk_cnt = *blk_cnt + 1;
- ret = fsck_chk_node_blk(sbi,
- &node_blk->i,
+ ret = fsck_chk_node_blk(sbi, &node_blk->i,
le32_to_cpu(node_blk->i.i_nid[idx]),
- ftype,
- ntype,
- blk_cnt);
- ASSERT(ret >= 0);
+ ftype, ntype, blk_cnt);
+ if (!ret) {
+ *blk_cnt = *blk_cnt + 1;
+ } else if (config.fix_on) {
+ node_blk->i.i_nid[idx] = 0;
+ need_fix = 1;
+ FIX_MSG("[0x%x] i_nid[%d] = 0", nid, idx);
+ }
}
}
check:
if (ftype == F2FS_FT_DIR)
- DBG(1, "Directory Inode: ino: %x name: %s depth: %d child files: %d\n\n",
- le32_to_cpu(node_blk->footer.ino), node_blk->i.i_name,
- le32_to_cpu(node_blk->i.i_current_depth), child_files);
+ DBG(1, "Directory Inode: 0x%x [%s] depth: %d has %d files\n\n",
+ le32_to_cpu(node_blk->footer.ino),
+ node_blk->i.i_name,
+ le32_to_cpu(node_blk->i.i_current_depth),
+ child_files);
if (ftype == F2FS_FT_ORPHAN)
- DBG(1, "Orphan Inode: ino: %x name: %s i_blocks: %lu\n\n",
- le32_to_cpu(node_blk->footer.ino), node_blk->i.i_name,
- i_blocks);
- if ((ftype == F2FS_FT_DIR && i_links != child_cnt) ||
- (i_blocks != *blk_cnt)) {
- print_node_info(node_blk);
- DBG(1, "blk cnt [0x%x]\n", *blk_cnt);
- DBG(1, "child cnt [0x%x]\n", child_cnt);
+ DBG(1, "Orphan Inode: 0x%x [%s] i_blocks: %u\n\n",
+ le32_to_cpu(node_blk->footer.ino),
+ node_blk->i.i_name,
+ (u32)i_blocks);
+
+ if (i_blocks != *blk_cnt) {
+ ASSERT_MSG("ino: 0x%x has i_blocks: %08"PRIx64", "
+ "but has %u blocks",
+ nid, i_blocks, *blk_cnt);
+ if (config.fix_on) {
+ node_blk->i.i_blocks = cpu_to_le64(*blk_cnt);
+ need_fix = 1;
+ FIX_MSG("[0x%x] i_blocks=0x%08"PRIx64" -> 0x%x",
+ nid, i_blocks, *blk_cnt);
+ }
+ }
+ if (ftype == F2FS_FT_DIR && i_links != child_cnt) {
+ ASSERT_MSG("ino: 0x%x has i_links: %u but real links: %u",
+ nid, i_links, child_cnt);
+ if (config.fix_on) {
+ node_blk->i.i_links = cpu_to_le32(child_cnt);
+ need_fix = 1;
+ FIX_MSG("Dir: 0x%x i_links= 0x%x -> 0x%x",
+ nid, i_links, child_cnt);
+ }
}
- ASSERT(i_blocks == *blk_cnt);
- if (ftype == F2FS_FT_DIR)
- ASSERT(i_links == child_cnt);
-out:
- return 0;
+ if (ftype == F2FS_FT_ORPHAN && i_links)
+ ASSERT_MSG("ino: 0x%x is orphan inode, but has i_links: %u",
+ nid, i_links);
+ if (need_fix) {
+ ret = dev_write_block(node_blk, ni->blk_addr);
+ ASSERT(ret >= 0);
+ }
}
-int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt,
- struct node_info *ni)
+int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk,
+ u32 *blk_cnt, struct node_info *ni)
{
- int idx;
+ int idx, ret;
u32 child_cnt = 0, child_files = 0;
for (idx = 0; idx < ADDRS_PER_BLOCK; idx++) {
if (le32_to_cpu(node_blk->dn.addr[idx]) == 0x0)
continue;
- *blk_cnt = *blk_cnt + 1;
- fsck_chk_data_blk(sbi,
- inode,
- le32_to_cpu(node_blk->dn.addr[idx]),
- &child_cnt,
- &child_files,
- le64_to_cpu(inode->i_blocks) == *blk_cnt,
- ftype,
- nid,
- idx,
- ni->version);
+ ret = fsck_chk_data_blk(sbi,
+ le32_to_cpu(node_blk->dn.addr[idx]),
+ &child_cnt, &child_files,
+ le64_to_cpu(inode->i_blocks) == *blk_cnt, ftype,
+ nid, idx, ni->version);
+ if (!ret)
+ *blk_cnt = *blk_cnt + 1;
}
-
return 0;
}
-int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt)
+int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt)
{
+ int ret;
int i = 0;
for (i = 0 ; i < NIDS_PER_BLOCK; i++) {
if (le32_to_cpu(node_blk->in.nid[i]) == 0x0)
continue;
- *blk_cnt = *blk_cnt + 1;
- fsck_chk_node_blk(sbi,
- inode,
+ ret = fsck_chk_node_blk(sbi, inode,
le32_to_cpu(node_blk->in.nid[i]),
- ftype,
- TYPE_DIRECT_NODE,
- blk_cnt);
+ ftype, TYPE_DIRECT_NODE, blk_cnt);
+ if (!ret)
+ *blk_cnt = *blk_cnt + 1;
+ else if (ret == -EINVAL)
+ printf("delete in.nid[i] = 0;\n");
}
-
return 0;
}
-int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 nid,
- enum FILE_TYPE ftype,
- struct f2fs_node *node_blk,
- u32 *blk_cnt)
+int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
+ enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt)
{
int i = 0;
+ int ret = 0;
for (i = 0; i < NIDS_PER_BLOCK; i++) {
if (le32_to_cpu(node_blk->in.nid[i]) == 0x0)
continue;
- *blk_cnt = *blk_cnt + 1;
- fsck_chk_node_blk(sbi,
- inode,
+ ret = fsck_chk_node_blk(sbi, inode,
le32_to_cpu(node_blk->in.nid[i]),
- ftype,
- TYPE_INDIRECT_NODE,
- blk_cnt);
+ ftype, TYPE_INDIRECT_NODE, blk_cnt);
+ if (!ret)
+ *blk_cnt = *blk_cnt + 1;
+ else if (ret == -EINVAL)
+ printf("delete in.nid[i] = 0;\n");
}
-
return 0;
}
@@ -482,7 +551,7 @@ static void print_dentry(__u32 depth, __u8 *name,
int last_de = 0;
int next_idx = 0;
int name_len;
- int i;
+ unsigned int i;
int bit_offset;
if (config.dbg_lv != -1)
@@ -512,15 +581,12 @@ static void print_dentry(__u32 depth, __u8 *name,
for (i = 1; i < depth; i++)
printf("%c ", tree_mark[i]);
- printf("%c-- %s\n", last_de ? '`' : '|', name);
+ printf("%c-- %s 0x%x\n", last_de ? '`' : '|',
+ name, le32_to_cpu(de_blk->dentry[idx].ino));
}
-int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 blk_addr,
- u32 *child_cnt,
- u32 *child_files,
- int last_blk)
+int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
+ u32 *child_cnt, u32 *child_files, int last_blk)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
int i;
@@ -543,16 +609,17 @@ int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
fsck->dentry_depth++;
for (i = 0; i < NR_DENTRY_IN_BLOCK;) {
- if (test_bit(i, (unsigned long *)de_blk->dentry_bitmap) == 0x0) {
+ if (test_bit(i, (unsigned long *)de_blk->dentry_bitmap) == 0) {
i++;
continue;
}
- name_len = le32_to_cpu(de_blk->dentry[i].name_len);
+ name_len = le16_to_cpu(de_blk->dentry[i].name_len);
name = calloc(name_len + 1, 1);
memcpy(name, de_blk->filename[i], name_len);
+ hash_code = f2fs_dentry_hash((const unsigned char *)name,
+ name_len);
- hash_code = f2fs_dentry_hash((const char *)name, name_len);
ASSERT(le32_to_cpu(de_blk->dentry[i].hash_code) == hash_code);
ftype = de_blk->dentry[i].file_type;
@@ -560,15 +627,16 @@ int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
/* Becareful. 'dentry.file_type' is not imode. */
if (ftype == F2FS_FT_DIR) {
*child_cnt = *child_cnt + 1;
- if ((name[0] == '.' && name[1] == '.' && name_len == 2) ||
- (name[0] == '.' && name_len == 1)) {
+ if ((name[0] == '.' && name_len == 1) ||
+ (name[0] == '.' && name[1] == '.' &&
+ name_len == 2)) {
i++;
free(name);
continue;
}
}
- DBG(2, "[%3u] - no[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n",
+ DBG(1, "[%3u]-[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n",
fsck->dentry_depth, i, name, name_len,
le32_to_cpu(de_blk->dentry[i].ino),
de_blk->dentry[i].file_type);
@@ -583,7 +651,21 @@ int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
TYPE_INODE,
&blk_cnt);
- ASSERT(ret >= 0);
+ if (ret && config.fix_on) {
+ int j;
+ int slots = (name_len + F2FS_SLOT_LEN - 1) /
+ F2FS_SLOT_LEN;
+ for (j = 0; j < slots; j++)
+ clear_bit(i + j,
+ (unsigned long *)de_blk->dentry_bitmap);
+ FIX_MSG("Unlink [0x%x] - %s len[0x%x], type[0x%x]",
+ le32_to_cpu(de_blk->dentry[i].ino),
+ name, name_len,
+ de_blk->dentry[i].file_type);
+ i += slots;
+ free(name);
+ continue;
+ }
i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
dentries++;
@@ -591,24 +673,19 @@ int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
free(name);
}
- DBG(1, "[%3d] Dentry Block [0x%x] Done : dentries:%d in %d slots (len:%d)\n\n",
- fsck->dentry_depth, blk_addr, dentries, NR_DENTRY_IN_BLOCK, F2FS_NAME_LEN);
+ DBG(1, "[%3d] Dentry Block [0x%x] Done : "
+ "dentries:%d in %d slots (len:%d)\n\n",
+ fsck->dentry_depth, blk_addr, dentries,
+ NR_DENTRY_IN_BLOCK, F2FS_NAME_LEN);
fsck->dentry_depth--;
free(de_blk);
return 0;
}
-int fsck_chk_data_blk(struct f2fs_sb_info *sbi,
- struct f2fs_inode *inode,
- u32 blk_addr,
- u32 *child_cnt,
- u32 *child_files,
- int last_blk,
- enum FILE_TYPE ftype,
- u32 parent_nid,
- u16 idx_in_node,
- u8 ver)
+int fsck_chk_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
+ u32 *child_cnt, u32 *child_files, int last_blk,
+ enum FILE_TYPE ftype, u32 parent_nid, u16 idx_in_node, u8 ver)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
@@ -618,112 +695,80 @@ int fsck_chk_data_blk(struct f2fs_sb_info *sbi,
return 0;
}
- IS_VALID_BLK_ADDR(sbi, blk_addr);
-
- is_valid_ssa_data_blk(sbi, blk_addr, parent_nid, idx_in_node, ver);
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->sit_area_bitmap) == 0x0) {
- ASSERT_MSG(0, "SIT bitmap is 0x0. blk_addr[0x%x]\n", blk_addr);
+ if (!IS_VALID_BLK_ADDR(sbi, blk_addr)) {
+ ASSERT_MSG("blkaddres is not valid. [0x%x]", blk_addr);
+ return -EINVAL;
}
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->main_area_bitmap) != 0) {
- ASSERT_MSG(0, "Duplicated data block. pnid[0x%x] idx[0x%x] blk_addr[0x%x]\n",
- parent_nid, idx_in_node, blk_addr);
+ if (is_valid_ssa_data_blk(sbi, blk_addr, parent_nid,
+ idx_in_node, ver)) {
+ ASSERT_MSG("summary data block is not valid. [0x%x]",
+ parent_nid);
+ return -EINVAL;
}
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk_addr), fsck->main_area_bitmap);
- fsck->chk.valid_blk_cnt++;
+ if (f2fs_test_sit_bitmap(sbi, blk_addr) == 0)
+ ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]", blk_addr);
- if (ftype == F2FS_FT_DIR) {
- fsck_chk_dentry_blk(sbi,
- inode,
- blk_addr,
- child_cnt,
- child_files,
- last_blk);
- }
+ if (f2fs_test_main_bitmap(sbi, blk_addr) != 0)
+ ASSERT_MSG("Duplicated data [0x%x]. pnid[0x%x] idx[0x%x]",
+ blk_addr, parent_nid, idx_in_node);
+
+ f2fs_set_main_bitmap(sbi, blk_addr);
+
+ fsck->chk.valid_blk_cnt++;
+ if (ftype == F2FS_FT_DIR)
+ return fsck_chk_dentry_blk(sbi, blk_addr, child_cnt,
+ child_files, last_blk);
return 0;
}
-int fsck_chk_orphan_node(struct f2fs_sb_info *sbi)
+void fsck_chk_orphan_node(struct f2fs_sb_info *sbi)
{
- int ret = 0;
u32 blk_cnt = 0;
-
block_t start_blk, orphan_blkaddr, i, j;
struct f2fs_orphan_block *orphan_blk;
+ struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
- if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG))
- return 0;
+ if (!is_set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG))
+ return;
- start_blk = __start_cp_addr(sbi) + 1;
- orphan_blkaddr = __start_sum_addr(sbi) - 1;
+ if (config.fix_on)
+ return;
+ start_blk = __start_cp_addr(sbi) + 1 +
+ le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
+ orphan_blkaddr = __start_sum_addr(sbi) - 1;
orphan_blk = calloc(BLOCK_SZ, 1);
for (i = 0; i < orphan_blkaddr; i++) {
- dev_read_block(orphan_blk, start_blk + i);
+ int ret = dev_read_block(orphan_blk, start_blk + i);
+
+ ASSERT(ret >= 0);
for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) {
nid_t ino = le32_to_cpu(orphan_blk->ino[j]);
DBG(1, "[%3d] ino [0x%x]\n", i, ino);
blk_cnt = 1;
- ret = fsck_chk_node_blk(sbi,
- NULL,
- ino,
- F2FS_FT_ORPHAN,
- TYPE_INODE,
- &blk_cnt);
- ASSERT(ret >= 0);
+ fsck_chk_node_blk(sbi, NULL, ino,
+ F2FS_FT_ORPHAN, TYPE_INODE, &blk_cnt);
}
memset(orphan_blk, 0, BLOCK_SZ);
}
free(orphan_blk);
-
-
- return 0;
}
-int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino, u32 x_nid, u32 *blk_cnt)
-{
- struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
- struct node_info ni;
-
- if (x_nid == 0x0)
- return 0;
-
- if (f2fs_test_bit(x_nid, fsck->nat_area_bitmap) != 0x0) {
- f2fs_clear_bit(x_nid, fsck->nat_area_bitmap);
- } else {
- ASSERT_MSG(0, "xattr_nid duplicated [0x%x]\n", x_nid);
- }
-
- *blk_cnt = *blk_cnt + 1;
- fsck->chk.valid_blk_cnt++;
- fsck->chk.valid_node_cnt++;
-
- ASSERT(get_node_info(sbi, x_nid, &ni) >= 0);
-
- if (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) != 0) {
- ASSERT_MSG(0, "Duplicated node block for x_attr. "
- "x_nid[0x%x] block addr[0x%x]\n",
- x_nid, ni.blk_addr);
- }
- f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap);
-
- DBG(2, "ino[0x%x] x_nid[0x%x]\n", ino, x_nid);
- return 0;
-}
-
-int fsck_init(struct f2fs_sb_info *sbi)
+void fsck_init(struct f2fs_sb_info *sbi)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_sm_info *sm_i = SM_I(sbi);
/*
- * We build three bitmap for main/sit/nat so that may check consistency of filesystem.
- * 1. main_area_bitmap will be used to check whether all blocks of main area is used or not.
+ * We build three bitmap for main/sit/nat so that may check consistency
+ * of filesystem.
+ * 1. main_area_bitmap will be used to check whether all blocks of main
+ * area is used or not.
* 2. nat_area_bitmap has bitmap information of used nid in NAT.
* 3. sit_area_bitmap has bitmap information of used main block.
* At Last sequence, we compare main_area_bitmap with sit_area_bitmap.
@@ -738,12 +783,89 @@ int fsck_init(struct f2fs_sb_info *sbi)
build_sit_area_bitmap(sbi);
tree_mark = calloc(tree_mark_size, 1);
+ ASSERT(tree_mark != NULL);
+}
+
+static void fix_nat_entries(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ u32 i;
+
+ for (i = 0; i < fsck->nr_nat_entries; i++)
+ if (f2fs_test_bit(i, fsck->nat_area_bitmap) != 0)
+ nullify_nat_entry(sbi, i);
+}
+
+static void fix_checkpoint(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+ struct f2fs_super_block *raw_sb = sbi->raw_super;
+ struct f2fs_checkpoint *ckp = F2FS_CKPT(sbi);
+ unsigned long long cp_blk_no;
+ u32 i;
+ int ret;
+ u_int32_t crc = 0;
+
+ ckp->ckpt_flags = cpu_to_le32(CP_UMOUNT_FLAG);
+ ckp->cp_pack_total_block_count =
+ cpu_to_le32(8 + le32_to_cpu(raw_sb->cp_payload));
+ ckp->cp_pack_start_sum = cpu_to_le32(1 +
+ le32_to_cpu(raw_sb->cp_payload));
+
+ ckp->free_segment_count = cpu_to_le32(fsck->chk.free_segs);
+ ckp->valid_block_count = cpu_to_le32(fsck->chk.valid_blk_cnt);
+ ckp->valid_node_count = cpu_to_le32(fsck->chk.valid_node_cnt);
+ ckp->valid_inode_count = cpu_to_le32(fsck->chk.valid_inode_cnt);
+
+ crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, ckp, CHECKSUM_OFFSET);
+ *((__le32 *)((unsigned char *)ckp + CHECKSUM_OFFSET)) =
+ cpu_to_le32(crc);
+
+ cp_blk_no = le32_to_cpu(raw_sb->cp_blkaddr);
+ if (sbi->cur_cp == 2)
+ cp_blk_no += 1 << le32_to_cpu(raw_sb->log_blocks_per_seg);
+
+ ret = dev_write_block(ckp, cp_blk_no++);
+ ASSERT(ret >= 0);
+
+ for (i = 0; i < le32_to_cpu(raw_sb->cp_payload); i++) {
+ ret = dev_write_block(((unsigned char *)ckp) + i * F2FS_BLKSIZE,
+ cp_blk_no++);
+ ASSERT(ret >= 0);
+ }
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+
+ ret = dev_write_block(curseg->sum_blk, cp_blk_no++);
+ ASSERT(ret >= 0);
+ }
+
+ ret = dev_write_block(ckp, cp_blk_no++);
+ ASSERT(ret >= 0);
+}
+
+int check_curseg_offset(struct f2fs_sb_info *sbi)
+{
+ int i;
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+ struct seg_entry *se;
+
+ se = get_seg_entry(sbi, curseg->segno);
+ if (f2fs_test_bit(curseg->next_blkoff,
+ (const char *)se->cur_valid_map) == 1) {
+ ASSERT_MSG("Next block offset is not free, type:%d", i);
+ return -EINVAL;
+ }
+ }
return 0;
}
int fsck_verify(struct f2fs_sb_info *sbi)
{
- int i = 0;
+ unsigned int i = 0;
int ret = 0;
u32 nr_unref_nid = 0;
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
@@ -765,6 +887,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
node->nid, node->links);
node = node->next;
}
+ config.bug_on = 1;
}
printf("[FSCK] Unreachable nat entries ");
@@ -773,14 +896,17 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", nr_unref_nid);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] SIT valid block bitmap checking ");
- if (memcmp(fsck->sit_area_bitmap, fsck->main_area_bitmap, fsck->sit_area_bitmap_sz) == 0x0) {
+ if (memcmp(fsck->sit_area_bitmap, fsck->main_area_bitmap,
+ fsck->sit_area_bitmap_sz) == 0x0) {
printf("[Ok..]\n");
} else {
printf("[Fail]\n");
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] Hard link checking for regular file ");
@@ -789,14 +915,16 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.multi_hard_link_files);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_block_count matching with CP ");
if (sbi->total_valid_block_count == fsck->chk.valid_blk_cnt) {
- printf(" [Ok..] [0x%lx]\n", fsck->chk.valid_blk_cnt);
+ printf(" [Ok..] [0x%x]\n", (u32)fsck->chk.valid_blk_cnt);
} else {
- printf(" [Fail] [0x%lx]\n", fsck->chk.valid_blk_cnt);
+ printf(" [Fail] [0x%x]\n", (u32)fsck->chk.valid_blk_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_node_count matcing with CP (de lookup) ");
@@ -805,6 +933,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_node_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_node_count matcing with CP (nat lookup) ");
@@ -813,6 +942,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_nat_entry_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
printf("[FSCK] valid_inode_count matched with CP ");
@@ -821,8 +951,43 @@ int fsck_verify(struct f2fs_sb_info *sbi)
} else {
printf(" [Fail] [0x%x]\n", fsck->chk.valid_inode_cnt);
ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
}
+ printf("[FSCK] free segment_count matched with CP ");
+ if (le32_to_cpu(F2FS_CKPT(sbi)->free_segment_count) ==
+ fsck->chk.sit_free_segs) {
+ printf(" [Ok..] [0x%x]\n", fsck->chk.sit_free_segs);
+ } else {
+ printf(" [Fail] [0x%x]\n", fsck->chk.sit_free_segs);
+ ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
+ }
+
+ printf("[FSCK] next block offset is free ");
+ if (check_curseg_offset(sbi) == 0) {
+ printf(" [Ok..]\n");
+ } else {
+ printf(" [Fail]\n");
+ ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
+ }
+
+ printf("[FSCK] other corrupted bugs ");
+ if (config.bug_on == 0) {
+ printf(" [Ok..]\n");
+ } else {
+ printf(" [Fail]\n");
+ ret = EXIT_ERR_CODE;
+ config.bug_on = 1;
+ }
+
+ /* fix global metadata */
+ if (config.bug_on && config.fix_on) {
+ fix_nat_entries(sbi);
+ rewrite_sit_area_bitmap(sbi);
+ fix_checkpoint(sbi);
+ }
return ret;
}