Update fsck to latest version (1.2 -> 1.4.0++ with better fix support)

Merge remote-tracking branch 'goog/lmp-mr1-dev-plus-aosp' into update_to_140

* goog/lmp-mr1-dev-plus-aosp: (45 commits)
  fsck.f2fs: actually flag the fixed dentries as fixed
  f2fs: use last_blk for print dentries
  fsck.f2fs: fix DATA_EXIST flag for old partition
  fsck.f2fs: attempt to identify bad dentries
  Update build version from 1.2.0 to 1.4.0 after merge.
  fsck.f2fs: show inline status of inode
  fsck.f2fs: fix wrongly allocated 0'th block for inline_data
  fsck.f2fs: fix link count correctly
  fsck.f2fs: fix wrong hash_code made by previous buggy code
  fsck.f2fs: support inline_dentry
  fsck.f2fs: fix superblock offset
  mkfs.f2fs: avoid build warning
  fsck.f2fs: fix wrong block addres of nids
  mkfs.f2fs: possible endianes bug in mkfs.f2fs roll-forward speed
  f2fs-tools: fix for build big-endian processors
  f2fs-tools: release 1.4.0
  f2fstat: enhance readability of output
  tracepoint.sh: update latest tracepoints
  f2fs: rearrange options to remove redundant check
  fsck.f2fs: add auto_fix feature
  ...

Bug: 17640053
Bug: 18292088
Change-Id: Idab448af4fccd7033ca5e3e55e3f3472673df622
Signed-off-by: JP Abgrall <jpa@google.com>
diff --git a/Android.mk b/Android.mk
index bee1071..48cdb55 100644
--- a/Android.mk
+++ b/Android.mk
@@ -4,7 +4,7 @@
 ifeq ($(HOST_OS),linux)
 
 # The versions depend on $(LOCAL_PATH)/VERSION
-version_CFLAGS := -DF2FS_MAJOR_VERSION=1 -DF2FS_MINOR_VERSION=2 -DF2FS_TOOLS_VERSION=\"1.2.0\" -DF2FS_TOOLS_DATE=\"2013-10-25\"
+version_CFLAGS := -DF2FS_MAJOR_VERSION=1 -DF2FS_MINOR_VERSION=4 -DF2FS_TOOLS_VERSION=\"1.4.0\" -DF2FS_TOOLS_DATE=\"2014-10-18\"
 
 # external/e2fsprogs/lib is needed for uuid/uuid.h
 common_C_INCLUDES := $(LOCAL_PATH)/include external/e2fsprogs/lib/
diff --git a/VERSION b/VERSION
index c3a3dd8..4e11b43 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-1.2.0
-2013-10-25
+1.4.0
+2014-09-18
diff --git a/configure.ac b/configure.ac
index c2dafb0..0111e72 100644
--- a/configure.ac
+++ b/configure.ac
@@ -56,7 +56,7 @@
 PKG_CHECK_MODULES([libuuid], [uuid])
 
 # Checks for header files.
-AC_CHECK_HEADERS([fcntl.h mntent.h stdlib.h string.h \
+AC_CHECK_HEADERS([linux/fs.h fcntl.h mntent.h stdlib.h string.h \
 		sys/ioctl.h sys/mount.h unistd.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
diff --git a/fsck/dump.c b/fsck/dump.c
index 765e9db..4bb906f 100644
--- a/fsck/dump.c
+++ b/fsck/dump.c
@@ -8,6 +8,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <inttypes.h>
+
 #include "fsck.h"
 
 #define BUF_SZ	80
@@ -57,7 +59,7 @@
 	ASSERT(ret >= 0);
 
 	close(fd);
-	DBG(1, "Blocks [0x%lx] Free Segs [0x%x]\n", valid_blocks, free_segs);
+	DBG(1, "Blocks [0x%" PRIx64 "] Free Segs [0x%x]\n", valid_blocks, free_segs);
 }
 
 void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa)
@@ -113,15 +115,164 @@
 	close(fd);
 }
 
-int dump_node(struct f2fs_sb_info *sbi, nid_t nid)
+static void dump_data_blk(__u64 offset, u32 blkaddr)
+{
+	char buf[F2FS_BLKSIZE];
+
+	if (blkaddr == NULL_ADDR)
+		return;
+
+	/* get data */
+	if (blkaddr == NEW_ADDR) {
+		memset(buf, 0, F2FS_BLKSIZE);
+	} else {
+		int ret;
+		ret = dev_read_block(buf, blkaddr);
+		ASSERT(ret >= 0);
+	}
+
+	/* write blkaddr */
+	dev_write_dump(buf, offset, F2FS_BLKSIZE);
+}
+
+static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype,
+						u32 nid, u64 *ofs)
 {
 	struct node_info ni;
 	struct f2fs_node *node_blk;
+	u32 skip = 0;
+	u32 i, idx;
+
+	switch (ntype) {
+	case TYPE_DIRECT_NODE:
+		skip = idx = ADDRS_PER_BLOCK;
+		break;
+	case TYPE_INDIRECT_NODE:
+		idx = NIDS_PER_BLOCK;
+		skip = idx * ADDRS_PER_BLOCK;
+		break;
+	case TYPE_DOUBLE_INDIRECT_NODE:
+		skip = 0;
+		idx = NIDS_PER_BLOCK;
+		break;
+	}
+
+	if (nid == 0) {
+		*ofs += skip;
+		return;
+	}
+
+	get_node_info(sbi, nid, &ni);
+
+	node_blk = calloc(BLOCK_SZ, 1);
+	dev_read_block(node_blk, ni.blk_addr);
+
+	for (i = 0; i < idx; i++, (*ofs)++) {
+		switch (ntype) {
+		case TYPE_DIRECT_NODE:
+			dump_data_blk(*ofs * F2FS_BLKSIZE,
+					le32_to_cpu(node_blk->dn.addr[i]));
+			break;
+		case TYPE_INDIRECT_NODE:
+			dump_node_blk(sbi, TYPE_DIRECT_NODE,
+					le32_to_cpu(node_blk->in.nid[i]), ofs);
+			break;
+		case TYPE_DOUBLE_INDIRECT_NODE:
+			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
+					le32_to_cpu(node_blk->in.nid[i]), ofs);
+			break;
+		}
+	}
+	free(node_blk);
+}
+
+static void dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid,
+					struct f2fs_node *node_blk)
+{
+	u32 i = 0;
+	u64 ofs = 0;
+
+	/* TODO: need to dump xattr */
+
+	if((node_blk->i.i_inline & F2FS_INLINE_DATA)){
+		DBG(3, "ino[0x%x] has inline data!\n", nid);
+		/* recover from inline data */
+		dev_write_dump(((unsigned char *)node_blk) + INLINE_DATA_OFFSET,
+							0, MAX_INLINE_DATA);
+		return;
+	}
+
+	/* check data blocks in inode */
+	for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++)
+		dump_data_blk(ofs * F2FS_BLKSIZE,
+				le32_to_cpu(node_blk->i.i_addr[i]));
+
+	/* check node blocks in inode */
+	for (i = 0; i < 5; i++) {
+		if (i == 0 || i == 1)
+			dump_node_blk(sbi, TYPE_DIRECT_NODE,
+					node_blk->i.i_nid[i], &ofs);
+		else if (i == 2 || i == 3)
+			dump_node_blk(sbi, TYPE_INDIRECT_NODE,
+					node_blk->i.i_nid[i], &ofs);
+		else if (i == 4)
+			dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE,
+					node_blk->i.i_nid[i], &ofs);
+		else
+			ASSERT(0);
+	}
+}
+
+void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni,
+					struct f2fs_node *node_blk)
+{
+	struct f2fs_inode *inode = &node_blk->i;
+	u32 imode = le32_to_cpu(inode->i_mode);
+	char name[255] = {0};
+	char path[1024] = {0};
+	char ans[255] = {0};
 	int ret;
 
-	ret = get_node_info(sbi, nid, &ni);
+	if (!S_ISREG(imode)) {
+		MSG(0, "Not a regular file\n\n");
+		return;
+	}
+
+	printf("Do you want to dump this file into ./lost_found/? [Y/N] ");
+	ret = scanf("%s", ans);
 	ASSERT(ret >= 0);
 
+	if (!strcasecmp(ans, "y")) {
+		ret = system("mkdir -p ./lost_found");
+		ASSERT(ret >= 0);
+
+		/* make a file */
+		strncpy(name, (const char *)inode->i_name,
+					le32_to_cpu(inode->i_namelen));
+		name[le32_to_cpu(inode->i_namelen)] = 0;
+		sprintf(path, "./lost_found/%s", name);
+
+		config.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666);
+		ASSERT(config.dump_fd >= 0);
+
+		/* dump file's data */
+		dump_inode_blk(sbi, ni->ino, node_blk);
+
+		/* adjust file size */
+		ret = ftruncate(config.dump_fd, le32_to_cpu(inode->i_size));
+		ASSERT(ret >= 0);
+
+		close(config.dump_fd);
+	}
+}
+
+void dump_node(struct f2fs_sb_info *sbi, nid_t nid)
+{
+	struct node_info ni;
+	struct f2fs_node *node_blk;
+
+	get_node_info(sbi, nid, &ni);
+
 	node_blk = calloc(BLOCK_SZ, 1);
 	dev_read_block(node_blk, ni.blk_addr);
 
@@ -130,9 +281,8 @@
 	DBG(1, "nat_entry.version     [0x%x]\n", ni.version);
 	DBG(1, "nat_entry.ino         [0x%x]\n", ni.ino);
 
-	if (ni.blk_addr == 0x0) {
+	if (ni.blk_addr == 0x0)
 		MSG(0, "Invalid nat entry\n\n");
-	}
 
 	DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(node_blk->footer.ino));
 	DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(node_blk->footer.nid));
@@ -140,12 +290,12 @@
 	if (le32_to_cpu(node_blk->footer.ino) == ni.ino &&
 			le32_to_cpu(node_blk->footer.nid) == ni.nid) {
 		print_node_info(node_blk);
+		dump_file(sbi, &ni, node_blk);
 	} else {
 		MSG(0, "Invalid node block\n\n");
 	}
 
 	free(node_blk);
-	return 0;
 }
 
 int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr)
@@ -159,8 +309,7 @@
 	type = get_sum_entry(sbi, blk_addr, &sum_entry);
 	nid = le32_to_cpu(sum_entry.nid);
 
-	ret = get_node_info(sbi, nid, &ni);
-	ASSERT(ret >= 0);
+	get_node_info(sbi, nid, &ni);
 
 	DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n");
 	DBG(1, "Block_addr            [0x%x]\n", blk_addr);
@@ -176,7 +325,8 @@
 	node_blk = calloc(BLOCK_SZ, 1);
 
 read_node_blk:
-	dev_read_block(node_blk, blk_addr);
+	ret = dev_read_block(node_blk, blk_addr);
+	ASSERT(ret >= 0);
 
 	ino = le32_to_cpu(node_blk->footer.ino);
 	nid = le32_to_cpu(node_blk->footer.nid);
@@ -184,7 +334,7 @@
 	if (ino == nid) {
 		print_node_info(node_blk);
 	} else {
-		ret = get_node_info(sbi, ino, &ni);
+		get_node_info(sbi, ino, &ni);
 		goto read_node_blk;
 	}
 
diff --git a/fsck/f2fs.h b/fsck/f2fs.h
index 427a733..47f785d 100644
--- a/fsck/f2fs.h
+++ b/fsck/f2fs.h
@@ -26,7 +26,6 @@
 #include <sys/mount.h>
 #include <assert.h>
 
-#include <list.h>
 #include <f2fs_fs.h>
 
 #define EXIT_ERR_CODE		(-1)
@@ -34,6 +33,10 @@
 		typecheck(unsigned long long, b) &&                     \
 		((long long)((a) - (b)) > 0))
 
+struct list_head {
+	struct list_head *next, *prev;
+};
+
 enum {
 	NAT_BITMAP,
 	SIT_BITMAP
@@ -126,6 +129,7 @@
 	struct f2fs_nm_info *nm_info;
 	struct f2fs_sm_info *sm_info;
 	struct f2fs_checkpoint *ckpt;
+	int cur_cp;
 
 	struct list_head orphan_inode_list;
 	unsigned int n_orphans;
@@ -187,6 +191,11 @@
 	return (struct sit_info *)(SM_I(sbi)->sit_info);
 }
 
+static inline void *inline_data_addr(struct f2fs_node *node_blk)
+{
+	return (void *)&(node_blk->i.i_addr[1]);
+}
+
 static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag)
 {
 	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
@@ -265,10 +274,15 @@
 #define GET_SEGNO_FROM_SEG0(sbi, blk_addr)				\
 	(GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg)
 
-#define FREE_I_START_SEGNO(sbi)		GET_SEGNO_FROM_SEG0(sbi, SM_I(sbi)->main_blkaddr)
+#define GET_BLKOFF_FROM_SEG0(sbi, blk_addr)				\
+	(GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (sbi->blocks_per_seg - 1))
+
+#define FREE_I_START_SEGNO(sbi)						\
+	GET_SEGNO_FROM_SEG0(sbi, SM_I(sbi)->main_blkaddr)
 #define GET_R2L_SEGNO(sbi, segno)	(segno + FREE_I_START_SEGNO(sbi))
 
-#define START_BLOCK(sbi, segno)	(SM_I(sbi)->main_blkaddr + (segno << sbi->log_blocks_per_seg))
+#define START_BLOCK(sbi, segno)	(SM_I(sbi)->main_blkaddr +		\
+	(segno << sbi->log_blocks_per_seg))
 
 static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type)
 {
@@ -301,23 +315,32 @@
 	(segno / SIT_ENTRY_PER_BLOCK)
 #define TOTAL_SEGS(sbi) (SM_I(sbi)->main_segments)
 
-#define IS_VALID_NID(sbi, nid) 			\
-	do {						\
-		ASSERT(nid <= (NAT_ENTRY_PER_BLOCK *	\
-					F2FS_RAW_SUPER(sbi)->segment_count_nat	\
-					<< (sbi->log_blocks_per_seg - 1)));	\
-	} while (0);
+static inline bool IS_VALID_NID(struct f2fs_sb_info *sbi, u32 nid)
+{
+	return (nid <= (NAT_ENTRY_PER_BLOCK *
+			F2FS_RAW_SUPER(sbi)->segment_count_nat
+			<< (sbi->log_blocks_per_seg - 1)));
+}
 
-#define IS_VALID_BLK_ADDR(sbi, addr)				\
-	do {							\
-		if (addr >= F2FS_RAW_SUPER(sbi)->block_count ||	 	\
-				addr < SM_I(sbi)->main_blkaddr)	\
-		{						\
-			DBG(0, "block addr [0x%x]\n", addr);	\
-			ASSERT(addr <  F2FS_RAW_SUPER(sbi)->block_count);	\
-			ASSERT(addr >= SM_I(sbi)->main_blkaddr);	\
-		}						\
-	} while (0);
+static inline bool IS_VALID_BLK_ADDR(struct f2fs_sb_info *sbi, u32 addr)
+{
+	int i;
+
+	if (addr >= F2FS_RAW_SUPER(sbi)->block_count ||
+				addr < SM_I(sbi)->main_blkaddr) {
+		ASSERT_MSG("block addr [0x%x]\n", addr);
+		return 0;
+	}
+
+	for (i = 0; i < NO_CHECK_TYPE; i++) {
+		struct curseg_info *curseg = CURSEG_I(sbi, i);
+
+		if (START_BLOCK(sbi, curseg->segno) +
+					curseg->next_blkoff == addr)
+			return 0;
+	}
+	return 1;
+}
 
 static inline u64 BLKOFF_FROM_MAIN(struct f2fs_sb_info *sbi, u64 blk_addr)
 {
diff --git a/fsck/fsck.c b/fsck/fsck.c
index 0f48918..f6039b8 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -13,7 +13,30 @@
 char *tree_mark;
 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 @@
 	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 @@
 		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 @@
 			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;
 	}
 
-	return 1;
+	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 0;
 }
 
 static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
@@ -128,143 +145,200 @@
 	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;
 
-	IS_VALID_NID(sbi, nid);
+	if (!IS_VALID_NID(sbi, nid)) {
+		ASSERT_MSG("nid is not valid. [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);
+	get_node_info(sbi, nid, ni);
+	if (ni->blk_addr == NEW_ADDR) {
+		ASSERT_MSG("nid is NEW_ADDR. [0x%x]", nid);
+		return -EINVAL;
+	}
 
-	ret = get_node_info(sbi, nid, &ni);
+	if (!IS_VALID_BLK_ADDR(sbi, ni->blk_addr)) {
+		ASSERT_MSG("blkaddres is not valid. [0x%x]", ni->blk_addr);
+		return -EINVAL;
+	}
+
+	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) {
+	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;
+	}
+
+	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;
+	}
+
+	if (ntype == TYPE_XATTR) {
+		u32 flag = le32_to_cpu(node_blk->footer.flag);
+
+		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;
+		}
+	}
+
+	/* 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++;
-		if (ntype == TYPE_INODE)
-			fsck->chk.valid_inode_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;
-	}
-
-	IS_VALID_BLK_ADDR(sbi, ni.blk_addr);
-
-	is_valid_ssa_node_blk(sbi, nid, ni.blk_addr);
-
-	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 (f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, ni.blk_addr), fsck->main_area_bitmap) == 0x0) {
-		fsck->chk.valid_blk_cnt++;
-		fsck->chk.valid_node_cnt++;
-	}
 
 	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;
+	}
 
-	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));
+	*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;
+}
+
+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,
-					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,
-					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;
@@ -272,81 +346,104 @@
 	u32 i_links = le32_to_cpu(node_blk->i.i_links);
 	u64 i_blocks = le64_to_cpu(node_blk->i.i_blocks);
 	unsigned int idx = 0;
-	int ret = 0;
+	int need_fix = 0;
+	int ret;
 
-	ASSERT(node_blk->footer.nid == node_blk->footer.ino);
-	ASSERT(le32_to_cpu(node_blk->footer.nid) == nid);
-
-	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);
+				}
+				goto check;
 			}
-
-			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)
 		goto check;
-	if((node_blk->i.i_inline & F2FS_INLINE_DATA)){
+
+	if((node_blk->i.i_inline & F2FS_INLINE_DATA)) {
+		if (le32_to_cpu(node_blk->i.i_addr[0]) != 0) {
+			/* should fix this bug all the time */
+			FIX_MSG("inline_data has wrong 0'th block = %x",
+					le32_to_cpu(node_blk->i.i_addr[0]));
+			node_blk->i.i_addr[0] = 0;
+			node_blk->i.i_blocks = cpu_to_le64(*blk_cnt);
+			need_fix = 1;
+		}
+		if (!(node_blk->i.i_inline & F2FS_DATA_EXIST)) {
+			char buf[MAX_INLINE_DATA];
+			memset(buf, 0, MAX_INLINE_DATA);
+
+			if (memcmp(buf, &node_blk->i.i_addr[1],
+							MAX_INLINE_DATA)) {
+				FIX_MSG("inline_data has DATA_EXIST");
+				node_blk->i.i_inline |= F2FS_DATA_EXIST;
+				need_fix = 1;
+			}
+		}
 		DBG(3, "ino[0x%x] has inline data!\n", nid);
 		goto check;
 	}
+	if((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) {
+		DBG(3, "ino[0x%x] has inline dentry!\n", nid);
+		ret = fsck_chk_inline_dentries(sbi, node_blk,
+					&child_cnt, &child_files);
+		if (ret < 0) {
+			/* should fix this bug all the time */
+			need_fix = 1;
+		}
+		goto check;
+	}
 
 	/* 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,
 					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);
+			}
 		}
 	}
 
@@ -362,116 +459,127 @@
 			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: %u\n\n",
-				le32_to_cpu(node_blk->footer.ino), node_blk->i.i_name,
+		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 ((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);
+
+	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,
-				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,
-		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,
-		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;
 }
 
 static void print_dentry(__u32 depth, __u8 *name,
-		struct f2fs_dentry_block *de_blk, int idx, int last_blk)
+		unsigned long *bitmap,
+		struct f2fs_dir_entry *dentry,
+		int max, int idx, int last_blk)
 {
 	int last_de = 0;
 	int next_idx = 0;
@@ -482,12 +590,11 @@
 	if (config.dbg_lv != -1)
 		return;
 
-	name_len = le16_to_cpu(de_blk->dentry[idx].name_len);
+	name_len = le16_to_cpu(dentry[idx].name_len);
 	next_idx = idx + (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
 
-	bit_offset = find_next_bit((unsigned long *)de_blk->dentry_bitmap,
-			NR_DENTRY_IN_BLOCK, next_idx);
-	if (bit_offset >= NR_DENTRY_IN_BLOCK && last_blk)
+	bit_offset = find_next_bit(bitmap, max, next_idx);
+	if (bit_offset >= max && last_blk)
 		last_de = 1;
 
 	if (tree_mark_size <= depth) {
@@ -506,26 +613,153 @@
 
 	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(dentry[idx].ino));
 }
 
-int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
-		u32 blk_addr,
-		u32 *child_cnt,
-		u32 *child_files,
-		int last_blk)
+static int __chk_dentries(struct f2fs_sb_info *sbi, u32 *child_cnt,
+			u32* child_files,
+			unsigned long *bitmap,
+			struct f2fs_dir_entry *dentry,
+			__u8 (*filenames)[F2FS_SLOT_LEN],
+			int max, int last_blk)
 {
 	struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
-	int i;
-	int ret = 0;
+	enum FILE_TYPE ftype;
 	int dentries = 0;
+	u32 blk_cnt;
 	u8 *name;
 	u32 hash_code;
-	u32 blk_cnt;
 	u16 name_len;;
+	int ret = 0;
+	int fixed = 0;
+	int i;
 
-	enum FILE_TYPE ftype;
+	for (i = 0; i < max;) {
+		if (test_bit(i, bitmap) == 0) {
+			i++;
+			continue;
+		}
+		if (!IS_VALID_NID(sbi, le32_to_cpu(dentry[i].ino))) {
+			DBG(1, "Bad dentry 0x%x with invalid NID/ino 0x%x",
+			    i, le32_to_cpu(dentry[i].ino));
+			if (config.fix_on) {
+				FIX_MSG("Clear bad dentry 0x%x with bad ino 0x%x",
+					i, le32_to_cpu(dentry[i].ino));
+				clear_bit(i, bitmap);
+				i++;
+				fixed = 1;
+				continue;
+			}
+		}
+		ftype = dentry[i].file_type;
+		if ((ftype <= F2FS_FT_UNKNOWN || ftype > F2FS_FT_LAST_FILE_TYPE) && config.fix_on) {
+			DBG(1, "Bad dentry 0x%x with unexpected ftype 0x%x",
+			    i, ftype);
+			if (config.fix_on) {
+				FIX_MSG("Clear bad dentry 0x%x with bad ftype 0x%x",
+					i, ftype);
+				clear_bit(i, bitmap);
+				i++;
+				fixed = 1;
+				continue;
+			}
+		}
+		name_len = le16_to_cpu(dentry[i].name_len);
+		name = calloc(name_len + 1, 1);
+		memcpy(name, filenames[i], name_len);
+		hash_code = f2fs_dentry_hash((const unsigned char *)name,
+								name_len);
+
+		/* fix hash_code made by old buggy code */
+		if (le32_to_cpu(dentry[i].hash_code) != hash_code) {
+			dentry[i].hash_code = hash_code;
+			fixed = 1;
+			FIX_MSG("hash_code[%d] of %s", i, name);
+		}
+
+		/* Becareful. 'dentry.file_type' is not imode. */
+		if (ftype == F2FS_FT_DIR) {
+			*child_cnt = *child_cnt + 1;
+			if ((name[0] == '.' && name_len == 1) ||
+				(name[0] == '.' && name[1] == '.' &&
+							name_len == 2)) {
+				i++;
+				free(name);
+				continue;
+			}
+		}
+
+		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(dentry[i].ino),
+				dentry[i].file_type);
+
+		print_dentry(fsck->dentry_depth, name, bitmap,
+						dentry, max, i, last_blk);
+
+		blk_cnt = 1;
+		ret = fsck_chk_node_blk(sbi,
+				NULL, le32_to_cpu(dentry[i].ino),
+				ftype, TYPE_INODE, &blk_cnt);
+
+		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, bitmap);
+			FIX_MSG("Unlink [0x%x] - %s len[0x%x], type[0x%x]",
+					le32_to_cpu(dentry[i].ino),
+					name, name_len,
+					dentry[i].file_type);
+			i += slots;
+			free(name);
+			continue;
+		}
+
+		i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
+		dentries++;
+		*child_files = *child_files + 1;
+		free(name);
+	}
+	return fixed ? -1 : dentries;
+}
+
+int fsck_chk_inline_dentries(struct f2fs_sb_info *sbi,
+		struct f2fs_node *node_blk, u32 *child_cnt, u32 *child_files)
+{
+	struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+	struct f2fs_inline_dentry *de_blk;
+	int dentries;
+
+	de_blk = inline_data_addr(node_blk);
+	ASSERT(de_blk != NULL);
+
+	fsck->dentry_depth++;
+	dentries = __chk_dentries(sbi, child_cnt, child_files,
+			(unsigned long *)de_blk->dentry_bitmap,
+			de_blk->dentry, de_blk->filename,
+			NR_INLINE_DENTRY, 1);
+	if (dentries < 0) {
+		DBG(1, "[%3d] Inline Dentry Block Fixed hash_codes\n\n",
+			fsck->dentry_depth);
+	} else {
+		DBG(1, "[%3d] Inline Dentry Block Done : "
+				"dentries:%d in %d slots (len:%d)\n\n",
+			fsck->dentry_depth, dentries,
+			(int)NR_INLINE_DENTRY, F2FS_NAME_LEN);
+	}
+	fsck->dentry_depth--;
+	return dentries;
+}
+
+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);
 	struct f2fs_dentry_block *de_blk;
+	int dentries, ret;
 
 	de_blk = (struct f2fs_dentry_block *)calloc(BLOCK_SZ, 1);
 	ASSERT(de_blk != NULL);
@@ -534,73 +768,30 @@
 	ASSERT(ret >= 0);
 
 	fsck->dentry_depth++;
+	dentries = __chk_dentries(sbi, child_cnt, child_files,
+			(unsigned long *)de_blk->dentry_bitmap,
+			de_blk->dentry, de_blk->filename,
+			NR_DENTRY_IN_BLOCK, last_blk);
 
-	for (i = 0; i < NR_DENTRY_IN_BLOCK;) {
-		if (test_bit(i, (unsigned long *)de_blk->dentry_bitmap) == 0x0) {
-			i++;
-			continue;
-		}
-
-		name_len = le32_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 char *)name, name_len);
-		ASSERT(le32_to_cpu(de_blk->dentry[i].hash_code) == hash_code);
-
-		ftype = de_blk->dentry[i].file_type;
-
-		/* 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)) {
-				i++;
-				free(name);
-				continue;
-			}
-		}
-
-		DBG(2, "[%3u] - no[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);
-
-		print_dentry(fsck->dentry_depth, name, de_blk, i, last_blk);
-
-		blk_cnt = 1;
-		ret = fsck_chk_node_blk(sbi,
-				NULL,
-				le32_to_cpu(de_blk->dentry[i].ino),
-				ftype,
-				TYPE_INODE,
-				&blk_cnt);
-
+	if (dentries < 0) {
+		ret = dev_write_block(de_blk, blk_addr);
 		ASSERT(ret >= 0);
-
-		i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
-		dentries++;
-		*child_files = *child_files + 1;
-		free(name);
+		DBG(1, "[%3d] Dentry Block [0x%x] Fixed hash_codes\n\n",
+			fsck->dentry_depth, blk_addr);
+	} else {
+		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,
-		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);
 
@@ -610,114 +801,80 @@
 		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);
+
+	if (f2fs_test_sit_bitmap(sbi, blk_addr) == 0)
+		ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]", blk_addr);
+
+	if (f2fs_test_main_bitmap(sbi, blk_addr) != 0)
+		ASSERT_MSG("Duplicated data [0x%x]. pnid[0x%x] idx[0x%x]",
+				blk_addr, parent_nid, idx_in_node);
+
+	f2fs_set_main_bitmap(sbi, blk_addr);
 
 	fsck->chk.valid_blk_cnt++;
 
-	if (ftype == F2FS_FT_DIR) {
-		fsck_chk_dentry_blk(sbi,
-				blk_addr,
-				child_cnt,
-				child_files,
-				last_blk);
-	}
-
+	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(ckpt, CP_ORPHAN_PRESENT_FLAG))
-		return 0;
+		return;
+
+	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.
@@ -732,6 +889,83 @@
 	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;
 }
 
@@ -759,6 +993,7 @@
 					node->nid, node->links);
 			node = node->next;
 		}
+		config.bug_on = 1;
 	}
 
 	printf("[FSCK] Unreachable nat entries                       ");
@@ -767,14 +1002,17 @@
 	} 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           ");
@@ -783,6 +1021,7 @@
 	} 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            ");
@@ -791,6 +1030,7 @@
 	} else {
 		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)  ");
@@ -799,6 +1039,7 @@
 	} 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) ");
@@ -807,6 +1048,7 @@
 	} 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             ");
@@ -815,8 +1057,43 @@
 	} 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;
 }
 
diff --git a/fsck/fsck.h b/fsck/fsck.h
index e5a3841..49d6d1d 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -31,6 +31,7 @@
 		u32 multi_hard_link_files;
 		u64 sit_valid_blocks;
 		u32 sit_free_segs;
+		u32 free_segs;
 	} chk;
 
 	struct hard_link_node *hard_link_list_head;
@@ -59,7 +60,8 @@
 	TYPE_INODE = 37,
 	TYPE_DIRECT_NODE = 43,
 	TYPE_INDIRECT_NODE = 53,
-	TYPE_DOUBLE_INDIRECT_NODE = 67
+	TYPE_DOUBLE_INDIRECT_NODE = 67,
+	TYPE_XATTR = 77
 };
 
 struct hard_link_node {
@@ -76,72 +78,40 @@
 	SEG_TYPE_MAX,
 };
 
-extern int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino, u32 x_nid, u32 *blk_cnt);
-extern int fsck_chk_orphan_node(struct f2fs_sb_info *sbi);
+extern void fsck_chk_orphan_node(struct f2fs_sb_info *);
+extern int fsck_chk_node_blk(struct f2fs_sb_info *, struct f2fs_inode *, u32,
+		enum FILE_TYPE, enum NODE_TYPE, u32 *);
+extern void fsck_chk_inode_blk(struct f2fs_sb_info *, u32, enum FILE_TYPE,
+		struct f2fs_node *, u32 *, struct node_info *);
+extern int fsck_chk_dnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
+		u32, enum FILE_TYPE, struct f2fs_node *, u32 *,
+		struct node_info *);
+extern int fsck_chk_idnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
+		enum FILE_TYPE, struct f2fs_node *, u32 *);
+extern int fsck_chk_didnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
+		enum FILE_TYPE, struct f2fs_node *, u32 *);
+extern int fsck_chk_data_blk(struct f2fs_sb_info *sbi, u32, u32 *, u32 *,
+		int, enum FILE_TYPE, u32, u16, u8);
+extern int fsck_chk_dentry_blk(struct f2fs_sb_info *, u32, u32 *, u32 *, int);
+int fsck_chk_inline_dentries(struct f2fs_sb_info *, struct f2fs_node *,
+		u32 *, u32 *);
 
-extern 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);
-
-extern 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);
-
-extern 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);
-
-extern 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);
-
-extern 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);
-
-extern 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);
-
-extern int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi,
-		u32 blk_addr,
-		u32 *child_cnt,
-		u32 *child_files,
-		int last_blk);
-
-extern void print_node_info(struct f2fs_node *node_block);
-extern void print_inode_info(struct f2fs_inode *inode);
-extern struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi, unsigned int segno);
-extern int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk);
-extern int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *sum_entry);
-extern int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni);
-extern void build_nat_area_bitmap(struct f2fs_sb_info *sbi);
-extern int build_sit_area_bitmap(struct f2fs_sb_info *sbi);
-extern int fsck_init(struct f2fs_sb_info *sbi);
-extern int fsck_verify(struct f2fs_sb_info *sbi);
-extern void fsck_free(struct f2fs_sb_info *sbi);
-extern int f2fs_do_mount(struct f2fs_sb_info *sbi);
-extern void f2fs_do_umount(struct f2fs_sb_info *sbi);
+extern void print_node_info(struct f2fs_node *);
+extern void print_inode_info(struct f2fs_inode *);
+extern struct seg_entry *get_seg_entry(struct f2fs_sb_info *, unsigned int);
+extern int get_sum_block(struct f2fs_sb_info *, unsigned int,
+				struct f2fs_summary_block *);
+extern int get_sum_entry(struct f2fs_sb_info *, u32, struct f2fs_summary *);
+extern void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
+extern void nullify_nat_entry(struct f2fs_sb_info *, u32);
+extern void rewrite_sit_area_bitmap(struct f2fs_sb_info *);
+extern void build_nat_area_bitmap(struct f2fs_sb_info *);
+extern void build_sit_area_bitmap(struct f2fs_sb_info *);
+extern void fsck_init(struct f2fs_sb_info *);
+extern int fsck_verify(struct f2fs_sb_info *);
+extern void fsck_free(struct f2fs_sb_info *);
+extern int f2fs_do_mount(struct f2fs_sb_info *);
+extern void f2fs_do_umount(struct f2fs_sb_info *);
 
 /* dump.c */
 struct dump_option {
@@ -153,9 +123,9 @@
 	int32_t blk_addr;
 };
 
-extern void sit_dump(struct f2fs_sb_info *sbi, int start_sit, int end_sit);
-extern void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa);
-extern int dump_node(struct f2fs_sb_info *sbi, nid_t nid);
-extern int dump_inode_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr);
+extern void sit_dump(struct f2fs_sb_info *, int, int);
+extern void ssa_dump(struct f2fs_sb_info *, int, int);
+extern void dump_node(struct f2fs_sb_info *, nid_t);
+extern int dump_inode_from_blkaddr(struct f2fs_sb_info *, u32);
 
 #endif /* _FSCK_H_ */
diff --git a/fsck/main.c b/fsck/main.c
index 46f5d04..2af3daf 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -11,15 +11,16 @@
 #include "fsck.h"
 #include <libgen.h>
 
-struct f2fs_fsck gfsck = {
-	.sbi = { .fsck = &gfsck, },
-};
+struct f2fs_fsck gfsck;
 
 void fsck_usage()
 {
 	MSG(0, "\nUsage: fsck.f2fs [options] device\n");
 	MSG(0, "[options]:\n");
+	MSG(0, "  -a check/fix potential corruption, reported by f2fs\n");
 	MSG(0, "  -d debug level [default:0]\n");
+	MSG(0, "  -f check/fix entire partition\n");
+	MSG(0, "  -t show directory tree [-d -1]\n");
 	exit(1);
 }
 
@@ -42,22 +43,31 @@
 	char *prog = basename(argv[0]);
 
 	if (!strcmp("fsck.f2fs", prog)) {
-		const char *option_string = "d:t";
+		const char *option_string = "ad:ft";
 
 		config.func = FSCK;
 		while ((option = getopt(argc, argv, option_string)) != EOF) {
 			switch (option) {
-				case 'd':
-					config.dbg_lv = atoi(optarg);
-					MSG(0, "Info: Debug level = %d\n", config.dbg_lv);
-					break;
-				case 't':
-					config.dbg_lv = -1;
-					break;
-				default:
-					MSG(0, "\tError: Unknown option %c\n",option);
-					fsck_usage();
-					break;
+			case 'a':
+				config.auto_fix = 1;
+				MSG(0, "Info: Fix the reported corruption.\n");
+				break;
+			case 'd':
+				config.dbg_lv = atoi(optarg);
+				MSG(0, "Info: Debug level = %d\n",
+							config.dbg_lv);
+				break;
+			case 'f':
+				config.fix_on = 1;
+				MSG(0, "Info: Force to fix corruption\n");
+				break;
+			case 't':
+				config.dbg_lv = -1;
+				break;
+			default:
+				MSG(0, "\tError: Unknown option %c\n", option);
+				fsck_usage();
+				break;
 			}
 		}
 	} else if (!strcmp("dump.f2fs", prog)) {
@@ -73,34 +83,46 @@
 
 		config.func = DUMP;
 		while ((option = getopt(argc, argv, option_string)) != EOF) {
+			int ret = 0;
+
 			switch (option) {
-				case 'd':
-					config.dbg_lv = atoi(optarg);
-					MSG(0, "Info: Debug level = %d\n", config.dbg_lv);
-					break;
-				case 'i':
-					if (strncmp(optarg, "0x", 2))
-						sscanf(optarg, "%d", &dump_opt.nid);
-					else
-						sscanf(optarg, "%x", &dump_opt.nid);
-					break;
-				case 's':
-					sscanf(optarg, "%d~%d", &dump_opt.start_sit, &dump_opt.end_sit);
-					break;
-				case 'a':
-					sscanf(optarg, "%d~%d", &dump_opt.start_ssa, &dump_opt.end_ssa);
-					break;
-				case 'b':
-					if (strncmp(optarg, "0x", 2))
-						sscanf(optarg, "%d", &dump_opt.blk_addr);
-					else
-						sscanf(optarg, "%x", &dump_opt.blk_addr);
-					break;
-				default:
-					MSG(0, "\tError: Unknown option %c\n", option);
-					dump_usage();
-					break;
+			case 'd':
+				config.dbg_lv = atoi(optarg);
+				MSG(0, "Info: Debug level = %d\n",
+							config.dbg_lv);
+				break;
+			case 'i':
+				if (strncmp(optarg, "0x", 2))
+					ret = sscanf(optarg, "%d",
+							&dump_opt.nid);
+				else
+					ret = sscanf(optarg, "%x",
+							&dump_opt.nid);
+				break;
+			case 's':
+				ret = sscanf(optarg, "%d~%d",
+							&dump_opt.start_sit,
+							&dump_opt.end_sit);
+				break;
+			case 'a':
+				ret = sscanf(optarg, "%d~%d",
+							&dump_opt.start_ssa,
+							&dump_opt.end_ssa);
+				break;
+			case 'b':
+				if (strncmp(optarg, "0x", 2))
+					ret = sscanf(optarg, "%d",
+							&dump_opt.blk_addr);
+				else
+					ret = sscanf(optarg, "%x",
+							&dump_opt.blk_addr);
+				break;
+			default:
+				MSG(0, "\tError: Unknown option %c\n", option);
+				dump_usage();
+				break;
 			}
+			ASSERT(ret >= 0);
 		}
 
 		config.private = &dump_opt;
@@ -116,43 +138,27 @@
 	config.device_name = argv[optind];
 }
 
-int do_fsck(struct f2fs_sb_info *sbi)
+static void do_fsck(struct f2fs_sb_info *sbi)
 {
 	u32 blk_cnt;
-	int ret;
 
-	ret = fsck_init(sbi);
-	if (ret < 0)
-		return ret;
+	fsck_init(sbi);
 
 	fsck_chk_orphan_node(sbi);
 
-	/* Travses all block recursively from root inode  */
+	/* Traverse all block recursively from root inode */
 	blk_cnt = 1;
-	ret = fsck_chk_node_blk(sbi,
-			NULL,
-			sbi->root_ino_num,
-			F2FS_FT_DIR,
-			TYPE_INODE,
-			&blk_cnt);
-	if (ret < 0)
-		goto out1;
-
-	ret = fsck_verify(sbi);
-
-out1:
+	fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num,
+			F2FS_FT_DIR, TYPE_INODE, &blk_cnt);
+	fsck_verify(sbi);
 	fsck_free(sbi);
-	return ret;
 }
 
-int do_dump(struct f2fs_sb_info *sbi)
+static void do_dump(struct f2fs_sb_info *sbi)
 {
 	struct dump_option *opt = (struct dump_option *)config.private;
-	int ret;
 
-	ret = fsck_init(sbi);
-	if (ret < 0)
-		return ret;
+	fsck_init(sbi);
 
 	if (opt->end_sit == -1)
 		opt->end_sit = SM_I(sbi)->main_segments;
@@ -166,17 +172,14 @@
 		dump_inode_from_blkaddr(sbi, opt->blk_addr);
 		goto cleanup;
 	}
-
 	dump_node(sbi, opt->nid);
-
 cleanup:
 	fsck_free(sbi);
-	return 0;
 }
 
-int main (int argc, char **argv)
+int main(int argc, char **argv)
 {
-	struct f2fs_sb_info *sbi = &gfsck.sbi;
+	struct f2fs_sb_info *sbi;
 	int ret = 0;
 
 	f2fs_init_configuration(&config);
@@ -189,23 +192,50 @@
 	/* Get device */
 	if (f2fs_get_device_info(&config) < 0)
 		return -1;
+fsck_again:
+	memset(&gfsck, 0, sizeof(gfsck));
+	gfsck.sbi.fsck = &gfsck;
+	sbi = &gfsck.sbi;
 
-	if (f2fs_do_mount(sbi) < 0)
+	ret = f2fs_do_mount(sbi);
+	if (ret == 1) {
+		free(sbi->ckpt);
+		free(sbi->raw_super);
+		goto out;
+	} else if (ret < 0)
 		return -1;
 
 	switch (config.func) {
-		case FSCK:
-			ret = do_fsck(sbi);
-			break;
-		case DUMP:
-			ret = do_dump(sbi);
-			break;
+	case FSCK:
+		do_fsck(sbi);
+		break;
+	case DUMP:
+		do_dump(sbi);
+		break;
 	}
 
 	f2fs_do_umount(sbi);
+out:
+	if (config.func == FSCK && config.bug_on) {
+		if (config.fix_on == 0 && config.auto_fix == 0) {
+			char ans[255] = {0};
+retry:
+			printf("Do you want to fix this partition? [Y/N] ");
+			ret = scanf("%s", ans);
+			ASSERT(ret >= 0);
+			if (!strcasecmp(ans, "y"))
+				config.fix_on = 1;
+			else if (!strcasecmp(ans, "n"))
+				config.fix_on = 0;
+			else
+				goto retry;
 
+			if (config.fix_on)
+				goto fsck_again;
+		}
+	}
 	f2fs_finalize_device(&config);
 
 	printf("\nDone.\n");
-	return ret;
+	return 0;
 }
diff --git a/fsck/mount.c b/fsck/mount.c
index 5d3231f..9ec6004 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -33,6 +33,7 @@
 	DISP_u32(inode, i_current_depth);
 	DISP_u32(inode, i_xattr_nid);
 	DISP_u32(inode, i_flags);
+	DISP_u32(inode, i_inline);
 	DISP_u32(inode, i_pino);
 
 	if (namelen) {
@@ -53,7 +54,7 @@
 
 	for (i = 4; i < ADDRS_PER_INODE(inode); i++) {
 		if (inode->i_addr[i] != 0x0) {
-			printf("i_addr[0x%x] points data block\r\t\t\t\t[0x%4x]\n",
+			printf("i_addr[0x%x] points data block\r\t\t[0x%4x]\n",
 					i, inode->i_addr[i]);
 			break;
 		}
@@ -79,9 +80,11 @@
 	} else {
 		int i;
 		u32 *dump_blk = (u32 *)node_block;
-		DBG(0, "Node ID [0x%x:%u] is direct node or indirect node.\n", nid, nid);
+		DBG(0, "Node ID [0x%x:%u] is direct node or indirect node.\n",
+								nid, nid);
 		for (i = 0; i <= 10; i++)
-			MSG(0, "[%d]\t\t\t[0x%8x : %d]\n", i, dump_blk[i], dump_blk[i]);
+			MSG(0, "[%d]\t\t\t[0x%8x : %d]\n",
+						i, dump_blk[i], dump_blk[i]);
 	}
 }
 
@@ -211,7 +214,8 @@
 		return -1;
 	}
 
-	if (F2FS_LOG_SECTORS_PER_BLOCK != le32_to_cpu(raw_super->log_sectors_per_block)) {
+	if (F2FS_LOG_SECTORS_PER_BLOCK !=
+				le32_to_cpu(raw_super->log_sectors_per_block)) {
 		return -1;
 	}
 
@@ -220,9 +224,14 @@
 
 int validate_super_block(struct f2fs_sb_info *sbi, int block)
 {
-	u64 offset = (block + 1) * F2FS_SUPER_OFFSET;
+	u64 offset;
 	sbi->raw_super = malloc(sizeof(struct f2fs_super_block));
 
+	if (block == 0)
+		offset = F2FS_SUPER_OFFSET;
+	else
+		offset = F2FS_BLKSIZE + F2FS_SUPER_OFFSET;
+
 	if (dev_read(sbi->raw_super, offset, sizeof(struct f2fs_super_block)))
 		return -1;
 
@@ -230,7 +239,7 @@
 		return 0;
 
 	free(sbi->raw_super);
-	MSG(0, "\tCan't find a valid F2FS filesystem in %d superblock\n", block);
+	MSG(0, "\tCan't find a valid F2FS superblock at 0x%x\n", block);
 
 	return -EINVAL;
 }
@@ -258,7 +267,8 @@
 	return 0;
 }
 
-void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, unsigned long long *version)
+void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr,
+				unsigned long long *version)
 {
 	void *cp_page_1, *cp_page_2;
 	struct f2fs_checkpoint *cp_block;
@@ -322,6 +332,7 @@
 	unsigned long long cp1_version = 0, cp2_version = 0;
 	unsigned long long cp_start_blk_no;
 	unsigned int cp_blks = 1 + le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload);
+	int ret;
 
 	sbi->ckpt = malloc(cp_blks * blk_size);
 	if (!sbi->ckpt)
@@ -338,14 +349,19 @@
 	cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version);
 
 	if (cp1 && cp2) {
-		if (ver_after(cp2_version, cp1_version))
+		if (ver_after(cp2_version, cp1_version)) {
 			cur_page = cp2;
-		else
+			sbi->cur_cp = 2;
+		} else {
 			cur_page = cp1;
+			sbi->cur_cp = 1;
+		}
 	} else if (cp1) {
 		cur_page = cp1;
+		sbi->cur_cp = 1;
 	} else if (cp2) {
 		cur_page = cp2;
+		sbi->cur_cp = 2;
 	} else {
 		free(cp1);
 		free(cp2);
@@ -355,16 +371,18 @@
 	memcpy(sbi->ckpt, cur_page, blk_size);
 
 	if (cp_blks > 1) {
-		int i;
+		unsigned int i;
 		unsigned long long cp_blk_no;
 
 		cp_blk_no = le32_to_cpu(raw_sb->cp_blkaddr);
 		if (cur_page == cp2)
-			cp_blk_no += 1 << le32_to_cpu(raw_sb->log_blocks_per_seg);
+			cp_blk_no += 1 <<
+				le32_to_cpu(raw_sb->log_blocks_per_seg);
 		/* copy sit bitmap */
 		for (i = 1; i < cp_blks; i++) {
 			unsigned char *ckpt = (unsigned char *)sbi->ckpt;
-			dev_read_block(cur_page, cp_blk_no + i);
+			ret = dev_read_block(cur_page, cp_blk_no + i);
+			ASSERT(ret >= 0);
 			memcpy(ckpt + i * blk_size, cur_page, blk_size);
 		}
 	}
@@ -490,196 +508,178 @@
 void reset_curseg(struct f2fs_sb_info *sbi, int type)
 {
 	struct curseg_info *curseg = CURSEG_I(sbi, type);
+	struct summary_footer *sum_footer;
+	struct seg_entry *se;
 
-	curseg->segno = curseg->next_segno;
-	curseg->zone = GET_ZONENO_FROM_SEGNO(sbi, curseg->segno);
-	curseg->next_blkoff = 0;
-	curseg->next_segno = NULL_SEGNO;
-
+	sum_footer = &(curseg->sum_blk->footer);
+	memset(sum_footer, 0, sizeof(struct summary_footer));
+	if (IS_DATASEG(type))
+		SET_SUM_TYPE(sum_footer, SUM_TYPE_DATA);
+	if (IS_NODESEG(type))
+		SET_SUM_TYPE(sum_footer, SUM_TYPE_NODE);
+	se = get_seg_entry(sbi, curseg->segno);
+	se->type = type;
 }
 
-int read_compacted_summaries(struct f2fs_sb_info *sbi)
+static void read_compacted_summaries(struct f2fs_sb_info *sbi)
 {
-	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
 	struct curseg_info *curseg;
+	unsigned int i, j, offset;
 	block_t start;
 	char *kaddr;
-	unsigned int i, j, offset;
+	int ret;
 
 	start = start_sum_block(sbi);
 
 	kaddr = (char *)malloc(PAGE_SIZE);
-	dev_read_block(kaddr, start++);
+	ret = dev_read_block(kaddr, start++);
+	ASSERT(ret >= 0);
 
 	curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
 	memcpy(&curseg->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE);
 
 	curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
-	memcpy(&curseg->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE, SUM_JOURNAL_SIZE);
+	memcpy(&curseg->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE,
+						SUM_JOURNAL_SIZE);
 
 	offset = 2 * SUM_JOURNAL_SIZE;
 	for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
 		unsigned short blk_off;
-		unsigned int segno;
+		struct curseg_info *curseg = CURSEG_I(sbi, i);
 
-		curseg = CURSEG_I(sbi, i);
-		segno = le32_to_cpu(ckpt->cur_data_segno[i]);
-		blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]);
-		curseg->next_segno = segno;
 		reset_curseg(sbi, i);
-		curseg->alloc_type = ckpt->alloc_type[i];
-		curseg->next_blkoff = blk_off;
 
 		if (curseg->alloc_type == SSR)
 			blk_off = sbi->blocks_per_seg;
+		else
+			blk_off = curseg->next_blkoff;
 
 		for (j = 0; j < blk_off; j++) {
 			struct f2fs_summary *s;
 			s = (struct f2fs_summary *)(kaddr + offset);
 			curseg->sum_blk->entries[j] = *s;
 			offset += SUMMARY_SIZE;
-			if (offset + SUMMARY_SIZE <= PAGE_CACHE_SIZE - SUM_FOOTER_SIZE)
+			if (offset + SUMMARY_SIZE <=
+					PAGE_CACHE_SIZE - SUM_FOOTER_SIZE)
 				continue;
 			memset(kaddr, 0, PAGE_SIZE);
-			dev_read_block(kaddr, start++);
+			ret = dev_read_block(kaddr, start++);
+			ASSERT(ret >= 0);
 			offset = 0;
 		}
 	}
-
 	free(kaddr);
-	return 0;
 }
 
-int restore_node_summary(struct f2fs_sb_info *sbi,
+static void restore_node_summary(struct f2fs_sb_info *sbi,
 		unsigned int segno, struct f2fs_summary_block *sum_blk)
 {
 	struct f2fs_node *node_blk;
 	struct f2fs_summary *sum_entry;
-	void *page;
 	block_t addr;
 	unsigned int i;
+	int ret;
 
-	page = malloc(PAGE_SIZE);
-	if (!page)
-		return -ENOMEM;
+	node_blk = malloc(F2FS_BLKSIZE);
+	ASSERT(node_blk);
 
 	/* scan the node segment */
 	addr = START_BLOCK(sbi, segno);
 	sum_entry = &sum_blk->entries[0];
 
 	for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) {
-		if (dev_read_block(page, addr))
-			goto out;
-
-		node_blk = (struct f2fs_node *)page;
+		ret = dev_read_block(node_blk, addr);
+		ASSERT(ret >= 0);
 		sum_entry->nid = node_blk->footer.nid;
-		/* do not change original value */
-#if 0
-		sum_entry->version = 0;
-		sum_entry->ofs_in_node = 0;
-#endif
 		addr++;
-
 	}
-out:
-	free(page);
-	return 0;
+	free(node_blk);
 }
 
-int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
+static void read_normal_summaries(struct f2fs_sb_info *sbi, int type)
 {
 	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
 	struct f2fs_summary_block *sum_blk;
 	struct curseg_info *curseg;
-	unsigned short blk_off;
 	unsigned int segno = 0;
 	block_t blk_addr = 0;
+	int ret;
 
 	if (IS_DATASEG(type)) {
 		segno = le32_to_cpu(ckpt->cur_data_segno[type]);
-		blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - CURSEG_HOT_DATA]);
-
 		if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
 			blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type);
 		else
 			blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type);
 	} else {
-		segno = le32_to_cpu(ckpt->cur_node_segno[type - CURSEG_HOT_NODE]);
-		blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type - CURSEG_HOT_NODE]);
-
+		segno = le32_to_cpu(ckpt->cur_node_segno[type -
+							CURSEG_HOT_NODE]);
 		if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
-			blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, type - CURSEG_HOT_NODE);
+			blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE,
+							type - CURSEG_HOT_NODE);
 		else
 			blk_addr = GET_SUM_BLKADDR(sbi, segno);
 	}
 
 	sum_blk = (struct f2fs_summary_block *)malloc(PAGE_SIZE);
-	dev_read_block(sum_blk, blk_addr);
+	ret = dev_read_block(sum_blk, blk_addr);
+	ASSERT(ret >= 0);
 
-	if (IS_NODESEG(type)) {
-		if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) {
-			struct f2fs_summary *sum_entry = &sum_blk->entries[0];
-			unsigned int i;
-			for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) {
-				/* do not change original value */
-#if 0
-				sum_entry->version = 0;
-				sum_entry->ofs_in_node = 0;
-#endif
-			}
-		} else {
-			if (restore_node_summary(sbi, segno, sum_blk)) {
-				free(sum_blk);
-				return -EINVAL;
-			}
-		}
-	}
+	if (IS_NODESEG(type) && !is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
+		restore_node_summary(sbi, segno, sum_blk);
 
 	curseg = CURSEG_I(sbi, type);
 	memcpy(curseg->sum_blk, sum_blk, PAGE_CACHE_SIZE);
-	curseg->next_segno = segno;
 	reset_curseg(sbi, type);
-	curseg->alloc_type = ckpt->alloc_type[type];
-	curseg->next_blkoff = blk_off;
 	free(sum_blk);
-
-	return 0;
 }
 
-int restore_curseg_summaries(struct f2fs_sb_info *sbi)
+static void restore_curseg_summaries(struct f2fs_sb_info *sbi)
 {
 	int type = CURSEG_HOT_DATA;
 
 	if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) {
-		if (read_compacted_summaries(sbi))
-			return -EINVAL;
+		read_compacted_summaries(sbi);
 		type = CURSEG_HOT_NODE;
 	}
 
-	for (; type <= CURSEG_COLD_NODE; type++) {
-		if (read_normal_summaries(sbi, type))
-			return -EINVAL;
-	}
-	return 0;
+	for (; type <= CURSEG_COLD_NODE; type++)
+		read_normal_summaries(sbi, type);
 }
 
-int build_curseg(struct f2fs_sb_info *sbi)
+static void build_curseg(struct f2fs_sb_info *sbi)
 {
+	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
 	struct curseg_info *array;
+	unsigned short blk_off;
+	unsigned int segno;
 	int i;
 
 	array = malloc(sizeof(*array) * NR_CURSEG_TYPE);
+	ASSERT(array);
 
 	SM_I(sbi)->curseg_array = array;
 
 	for (i = 0; i < NR_CURSEG_TYPE; i++) {
 		array[i].sum_blk = malloc(PAGE_CACHE_SIZE);
-		if (!array[i].sum_blk)
-			return -ENOMEM;
-		array[i].segno = NULL_SEGNO;
-		array[i].next_blkoff = 0;
+		ASSERT(array[i].sum_blk);
+		if (i <= CURSEG_COLD_DATA) {
+			blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]);
+			segno = le32_to_cpu(ckpt->cur_data_segno[i]);
+		}
+		if (i > CURSEG_COLD_DATA) {
+			blk_off = le16_to_cpu(ckpt->cur_node_blkoff[i -
+							CURSEG_HOT_NODE]);
+			segno = le32_to_cpu(ckpt->cur_node_segno[i -
+							CURSEG_HOT_NODE]);
+		}
+		array[i].segno = segno;
+		array[i].zone = GET_ZONENO_FROM_SEGNO(sbi, segno);
+		array[i].next_segno = NULL_SEGNO;
+		array[i].next_blkoff = blk_off;
+		array[i].alloc_type = ckpt->alloc_type[i];
 	}
-	return restore_curseg_summaries(sbi);
+	restore_curseg_summaries(sbi);
 }
 
 inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
@@ -688,12 +688,14 @@
 	ASSERT(segno <= end_segno);
 }
 
-struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi, unsigned int segno)
+static struct f2fs_sit_block *get_current_sit_page(struct f2fs_sb_info *sbi,
+						unsigned int segno)
 {
 	struct sit_info *sit_i = SIT_I(sbi);
 	unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno);
 	block_t blk_addr = sit_i->sit_base_addr + offset;
 	struct f2fs_sit_block *sit_blk = calloc(BLOCK_SZ, 1);
+	int ret;
 
 	check_seg_range(sbi, segno);
 
@@ -701,11 +703,28 @@
 	if (f2fs_test_bit(offset, sit_i->sit_bitmap))
 		blk_addr += sit_i->sit_blocks;
 
-	dev_read_block(sit_blk, blk_addr);
+	ret = dev_read_block(sit_blk, blk_addr);
+	ASSERT(ret >= 0);
 
 	return sit_blk;
 }
 
+void rewrite_current_sit_page(struct f2fs_sb_info *sbi,
+			unsigned int segno, struct f2fs_sit_block *sit_blk)
+{
+	struct sit_info *sit_i = SIT_I(sbi);
+	unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno);
+	block_t blk_addr = sit_i->sit_base_addr + offset;
+	int ret;
+
+	/* calculate sit block address */
+	if (f2fs_test_bit(offset, sit_i->sit_bitmap))
+		blk_addr += sit_i->sit_blocks;
+
+	ret = dev_write_block(sit_blk, blk_addr);
+	ASSERT(ret >= 0);
+}
+
 void check_block_count(struct f2fs_sb_info *sbi,
 		unsigned int segno, struct f2fs_sit_entry *raw_sit)
 {
@@ -714,18 +733,26 @@
 	int valid_blocks = 0;
 	unsigned int i;
 
-
 	/* check segment usage */
-	ASSERT(GET_SIT_VBLOCKS(raw_sit) <= sbi->blocks_per_seg);
+	if (GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg)
+		ASSERT_MSG("Invalid SIT vblocks: segno=0x%x, %u",
+				segno, GET_SIT_VBLOCKS(raw_sit));
 
 	/* check boundary of a given segment number */
-	ASSERT(segno <= end_segno);
+	if (segno > end_segno)
+		ASSERT_MSG("Invalid SEGNO: 0x%x", segno);
 
 	/* check bitmap with valid block count */
-	for (i = 0; i < sbi->blocks_per_seg; i++)
-		if (f2fs_test_bit(i, (char *)raw_sit->valid_map))
-			valid_blocks++;
-	ASSERT(GET_SIT_VBLOCKS(raw_sit) == valid_blocks);
+	for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++)
+		valid_blocks += get_bits_in_byte(raw_sit->valid_map[i]);
+
+	if (GET_SIT_VBLOCKS(raw_sit) != valid_blocks)
+		ASSERT_MSG("Wrong SIT valid blocks: segno=0x%x, %u vs. %u",
+				segno, GET_SIT_VBLOCKS(raw_sit), valid_blocks);
+
+	if (GET_SIT_TYPE(raw_sit) >= NO_CHECK_TYPE)
+		ASSERT_MSG("Wrong SIT type: segno=0x%x, %u",
+				segno, GET_SIT_TYPE(raw_sit));
 }
 
 void seg_info_from_raw_sit(struct seg_entry *se,
@@ -746,7 +773,8 @@
 	return &sit_i->sentries[segno];
 }
 
-int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno, struct f2fs_summary_block *sum_blk)
+int get_sum_block(struct f2fs_sb_info *sbi, unsigned int segno,
+				struct f2fs_summary_block *sum_blk)
 {
 	struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
 	struct curseg_info *curseg;
@@ -757,18 +785,30 @@
 	for (type = 0; type < NR_CURSEG_NODE_TYPE; type++) {
 		if (segno == ckpt->cur_node_segno[type]) {
 			curseg = CURSEG_I(sbi, CURSEG_HOT_NODE + type);
+			if (!IS_SUM_NODE_SEG(curseg->sum_blk->footer)) {
+				ASSERT_MSG("segno [0x%x] indicates a data "
+						"segment, but should be node",
+						segno);
+				return -EINVAL;
+			}
 			memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ);
-			return SEG_TYPE_CUR_NODE; /* current node seg was not stored */
+			return SEG_TYPE_CUR_NODE;
 		}
 	}
 
 	for (type = 0; type < NR_CURSEG_DATA_TYPE; type++) {
 		if (segno == ckpt->cur_data_segno[type]) {
 			curseg = CURSEG_I(sbi, type);
+			if (IS_SUM_NODE_SEG(curseg->sum_blk->footer)) {
+				ASSERT_MSG("segno [0x%x] indicates a node "
+						"segment, but should be data",
+						segno);
+				return -EINVAL;
+			}
+			DBG(2, "segno [0x%x] is current data seg[0x%x]\n",
+								segno, type);
 			memcpy(sum_blk, curseg->sum_blk, BLOCK_SZ);
-			ASSERT(!IS_SUM_NODE_SEG(sum_blk->footer));
-			DBG(2, "segno [0x%x] is current data seg[0x%x]\n", segno, type);
-			return SEG_TYPE_CUR_DATA; /* current data seg was not stored */
+			return SEG_TYPE_CUR_DATA;
 		}
 	}
 
@@ -782,7 +822,8 @@
 
 }
 
-int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, struct f2fs_summary *sum_entry)
+int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr,
+				struct f2fs_summary *sum_entry)
 {
 	struct f2fs_summary_block *sum_blk;
 	u32 segno, offset;
@@ -794,16 +835,15 @@
 	sum_blk = calloc(BLOCK_SZ, 1);
 
 	ret = get_sum_block(sbi, segno, sum_blk);
-
-	memcpy(sum_entry, &(sum_blk->entries[offset]), sizeof(struct f2fs_summary));
-
+	memcpy(sum_entry, &(sum_blk->entries[offset]),
+				sizeof(struct f2fs_summary));
 	free(sum_blk);
 	return ret;
 }
 
-int get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, struct f2fs_nat_entry *raw_nat)
+static void get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid,
+				struct f2fs_nat_entry *raw_nat)
 {
-	struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
 	struct f2fs_nm_info *nm_i = NM_I(sbi);
 	struct f2fs_nat_block *nat_block;
 	pgoff_t block_off;
@@ -811,13 +851,8 @@
 	int seg_off, entry_off;
 	int ret;
 
-	if ((nid / NAT_ENTRY_PER_BLOCK) > fsck->nr_nat_entries) {
-		DBG(0, "nid is over max nid\n");
-		return -EINVAL;
-	}
-
 	if (lookup_nat_in_journal(sbi, nid, raw_nat) >= 0)
-		return 0;
+		return;
 
 	nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
 
@@ -835,21 +870,17 @@
 	ret = dev_read_block(nat_block, block_addr);
 	ASSERT(ret >= 0);
 
-	memcpy(raw_nat, &nat_block->entries[entry_off], sizeof(struct f2fs_nat_entry));
+	memcpy(raw_nat, &nat_block->entries[entry_off],
+					sizeof(struct f2fs_nat_entry));
 	free(nat_block);
-
-	return 0;
 }
 
-int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
+void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
 {
 	struct f2fs_nat_entry raw_nat;
-	int ret;
-
-	ret = get_nat_entry(sbi, nid, &raw_nat);
+	get_nat_entry(sbi, nid, &raw_nat);
 	ni->nid = nid;
 	node_info_from_raw_nat(ni, &raw_nat);
-	return ret;
 }
 
 void build_sit_entries(struct f2fs_sb_info *sbi)
@@ -910,18 +941,14 @@
 	return 0;
 }
 
-int build_sit_area_bitmap(struct f2fs_sb_info *sbi)
+void build_sit_area_bitmap(struct f2fs_sb_info *sbi)
 {
 	struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
 	struct f2fs_sm_info *sm_i = SM_I(sbi);
 	unsigned int segno = 0;
-	int j = 0;
 	char *ptr = NULL;
-
 	u32 sum_vblocks = 0;
 	u32 free_segs = 0;
-	u32 vblocks = 0;
-
 	struct seg_entry *se;
 
 	fsck->sit_area_bitmap_sz = sm_i->main_segments * SIT_VBLOCK_MAP_SIZE;
@@ -930,20 +957,13 @@
 
 	ASSERT(fsck->sit_area_bitmap_sz == fsck->main_area_bitmap_sz);
 
-	for (segno = 0; segno < sm_i->main_segments; segno++) {
+	for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) {
 		se = get_seg_entry(sbi, segno);
 
 		memcpy(ptr, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
 		ptr += SIT_VBLOCK_MAP_SIZE;
 
-		vblocks = 0;
-		for (j = 0; j < SIT_VBLOCK_MAP_SIZE; j++) {
-			vblocks += get_bits_in_byte(se->cur_valid_map[j]);
-		}
-		ASSERT(vblocks == se->valid_blocks);
-
 		if (se->valid_blocks == 0x0) {
-
 			if (sbi->ckpt->cur_node_segno[0] == segno ||
 					sbi->ckpt->cur_data_segno[0] == segno ||
 					sbi->ckpt->cur_node_segno[1] == segno ||
@@ -954,22 +974,76 @@
 			} else {
 				free_segs++;
 			}
-
 		} else {
-			ASSERT(se->valid_blocks <= 512);
 			sum_vblocks += se->valid_blocks;
 		}
 	}
-
 	fsck->chk.sit_valid_blocks = sum_vblocks;
 	fsck->chk.sit_free_segs = free_segs;
 
-	DBG(1, "Blocks [0x%x : %d] Free Segs [0x%x : %d]\n\n", sum_vblocks, sum_vblocks,
+	DBG(1, "Blocks [0x%x : %d] Free Segs [0x%x : %d]\n\n",
+			sum_vblocks, sum_vblocks,
 			free_segs, free_segs);
-	return 0;
 }
 
-int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_entry *raw_nat)
+void rewrite_sit_area_bitmap(struct f2fs_sb_info *sbi)
+{
+	struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
+	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
+	struct sit_info *sit_i = SIT_I(sbi);
+	unsigned int segno = 0;
+	struct f2fs_summary_block *sum = curseg->sum_blk;
+	char *ptr = NULL;
+
+	/* remove sit journal */
+	sum->n_sits = 0;
+
+	fsck->chk.free_segs = 0;
+
+	ptr = fsck->main_area_bitmap;
+
+	for (segno = 0; segno < TOTAL_SEGS(sbi); segno++) {
+		struct f2fs_sit_block *sit_blk;
+		struct f2fs_sit_entry *sit;
+		struct seg_entry *se;
+		u16 valid_blocks = 0;
+		u16 type;
+		int i;
+
+		sit_blk = get_current_sit_page(sbi, segno);
+		sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)];
+		memcpy(sit->valid_map, ptr, SIT_VBLOCK_MAP_SIZE);
+
+		/* update valid block count */
+		for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++)
+			valid_blocks += get_bits_in_byte(sit->valid_map[i]);
+
+		se = get_seg_entry(sbi, segno);
+		type = se->type;
+		if (type >= NO_CHECK_TYPE) {
+			ASSERT(valid_blocks);
+			type = 0;
+		}
+		sit->vblocks = cpu_to_le16((type << SIT_VBLOCKS_SHIFT) |
+								valid_blocks);
+		rewrite_current_sit_page(sbi, segno, sit_blk);
+		free(sit_blk);
+
+		if (valid_blocks == 0 &&
+				sbi->ckpt->cur_node_segno[0] != segno &&
+				sbi->ckpt->cur_data_segno[0] != segno &&
+				sbi->ckpt->cur_node_segno[1] != segno &&
+				sbi->ckpt->cur_data_segno[1] != segno &&
+				sbi->ckpt->cur_node_segno[2] != segno &&
+				sbi->ckpt->cur_data_segno[2] != segno)
+			fsck->chk.free_segs++;
+
+		ptr += SIT_VBLOCK_MAP_SIZE;
+	}
+}
+
+int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid,
+					struct f2fs_nat_entry *raw_nat)
 {
 	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
 	struct f2fs_summary_block *sum = curseg->sum_blk;
@@ -977,7 +1051,8 @@
 
 	for (i = 0; i < nats_in_cursum(sum); i++) {
 		if (le32_to_cpu(nid_in_journal(sum, i)) == nid) {
-			memcpy(raw_nat, &nat_in_journal(sum, i), sizeof(struct f2fs_nat_entry));
+			memcpy(raw_nat, &nat_in_journal(sum, i),
+						sizeof(struct f2fs_nat_entry));
 			DBG(3, "==> Found nid [0x%x] in nat cache\n", nid);
 			return i;
 		}
@@ -985,6 +1060,51 @@
 	return -1;
 }
 
+void nullify_nat_entry(struct f2fs_sb_info *sbi, u32 nid)
+{
+	struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
+	struct f2fs_summary_block *sum = curseg->sum_blk;
+	struct f2fs_nm_info *nm_i = NM_I(sbi);
+	struct f2fs_nat_block *nat_block;
+	pgoff_t block_off;
+	pgoff_t block_addr;
+	int seg_off, entry_off;
+	int ret;
+	int i = 0;
+
+	/* check in journal */
+	for (i = 0; i < nats_in_cursum(sum); i++) {
+		if (le32_to_cpu(nid_in_journal(sum, i)) == nid) {
+			memset(&nat_in_journal(sum, i), 0,
+					sizeof(struct f2fs_nat_entry));
+			FIX_MSG("Remove nid [0x%x] in nat journal\n", nid);
+			return;
+		}
+	}
+	nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
+
+	block_off = nid / NAT_ENTRY_PER_BLOCK;
+	entry_off = nid % NAT_ENTRY_PER_BLOCK;
+
+	seg_off = block_off >> sbi->log_blocks_per_seg;
+	block_addr = (pgoff_t)(nm_i->nat_blkaddr +
+			(seg_off << sbi->log_blocks_per_seg << 1) +
+			(block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
+
+	if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
+		block_addr += sbi->blocks_per_seg;
+
+	ret = dev_read_block(nat_block, block_addr);
+	ASSERT(ret >= 0);
+
+	memset(&nat_block->entries[entry_off], 0,
+					sizeof(struct f2fs_nat_entry));
+
+	ret = dev_write_block(nat_block, block_addr);
+	ASSERT(ret >= 0);
+	free(nat_block);
+}
+
 void build_nat_area_bitmap(struct f2fs_sb_info *sbi)
 {
 	struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
@@ -992,18 +1112,18 @@
 	struct f2fs_nm_info *nm_i = NM_I(sbi);
 	struct f2fs_nat_block *nat_block;
 	u32 nid, nr_nat_blks;
-
 	pgoff_t block_off;
 	pgoff_t block_addr;
 	int seg_off;
 	int ret;
 	unsigned int i;
 
-
 	nat_block = (struct f2fs_nat_block *)calloc(BLOCK_SZ, 1);
+	ASSERT(nat_block);
 
 	/* Alloc & build nat entry bitmap */
-	nr_nat_blks = (le32_to_cpu(raw_sb->segment_count_nat) / 2) << sbi->log_blocks_per_seg;
+	nr_nat_blks = (le32_to_cpu(raw_sb->segment_count_nat) / 2) <<
+						sbi->log_blocks_per_seg;
 
 	fsck->nr_nat_entries = nr_nat_blks * NAT_ENTRY_PER_BLOCK;
 	fsck->nat_area_bitmap_sz = (fsck->nr_nat_entries + 7) / 8;
@@ -1014,8 +1134,8 @@
 
 		seg_off = block_off >> sbi->log_blocks_per_seg;
 		block_addr = (pgoff_t)(nm_i->nat_blkaddr +
-				(seg_off << sbi->log_blocks_per_seg << 1) +
-				(block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
+			(seg_off << sbi->log_blocks_per_seg << 1) +
+			(block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
 
 		if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
 			block_addr += sbi->blocks_per_seg;
@@ -1029,44 +1149,47 @@
 			struct node_info ni;
 			ni.nid = nid + i;
 
-			if ((nid + i) == F2FS_NODE_INO(sbi) || (nid + i) == F2FS_META_INO(sbi)) {
+			if ((nid + i) == F2FS_NODE_INO(sbi) ||
+					(nid + i) == F2FS_META_INO(sbi)) {
 				ASSERT(nat_block->entries[i].block_addr != 0x0);
 				continue;
 			}
 
-			if (lookup_nat_in_journal(sbi, nid + i, &raw_nat) >= 0) {
+			if (lookup_nat_in_journal(sbi, nid + i,
+							&raw_nat) >= 0) {
 				node_info_from_raw_nat(&ni, &raw_nat);
 				if (ni.blk_addr != 0x0) {
-					f2fs_set_bit(nid + i, fsck->nat_area_bitmap);
+					f2fs_set_bit(nid + i,
+							fsck->nat_area_bitmap);
 					fsck->chk.valid_nat_entry_cnt++;
-					DBG(3, "nid[0x%x] in nat cache\n", nid + i);
+					DBG(3, "nid[0x%x] in nat cache\n",
+								nid + i);
 				}
 			} else {
-				node_info_from_raw_nat(&ni, &nat_block->entries[i]);
-				if (ni.blk_addr != 0) {
-					ASSERT(nid + i != 0x0);
+				node_info_from_raw_nat(&ni,
+						&nat_block->entries[i]);
+				if (ni.blk_addr == 0)
+					continue;
+				ASSERT(nid + i != 0x0);
 
-					DBG(3, "nid[0x%8x] in nat entry [0x%16x] [0x%8x]\n",
-							nid + i,
-							ni.blk_addr,
-							ni.ino);
-
-					f2fs_set_bit(nid + i, fsck->nat_area_bitmap);
-					fsck->chk.valid_nat_entry_cnt++;
-				}
+				DBG(3, "nid[0x%8x] addr[0x%16x] ino[0x%8x]\n",
+					nid + i, ni.blk_addr, ni.ino);
+				f2fs_set_bit(nid + i, fsck->nat_area_bitmap);
+				fsck->chk.valid_nat_entry_cnt++;
 			}
 		}
 	}
 	free(nat_block);
 
 	DBG(1, "valid nat entries (block_addr != 0x0) [0x%8x : %u]\n",
-			fsck->chk.valid_nat_entry_cnt, fsck->chk.valid_nat_entry_cnt);
-
+			fsck->chk.valid_nat_entry_cnt,
+			fsck->chk.valid_nat_entry_cnt);
 }
 
 int f2fs_do_mount(struct f2fs_sb_info *sbi)
 {
 	int ret;
+
 	sbi->active_logs = NR_CURSEG_TYPE;
 	ret = validate_super_block(sbi, 0);
 	if (ret) {
@@ -1092,10 +1215,23 @@
 
 	print_ckpt_info(sbi);
 
+	if (config.auto_fix) {
+		u32 flag = le32_to_cpu(sbi->ckpt->ckpt_flags);
+
+		if (flag & CP_FSCK_FLAG)
+			config.fix_on = 1;
+		else
+			return 1;
+	}
+
+	config.bug_on = 0;
+
 	sbi->total_valid_node_count = le32_to_cpu(sbi->ckpt->valid_node_count);
-	sbi->total_valid_inode_count = le32_to_cpu(sbi->ckpt->valid_inode_count);
+	sbi->total_valid_inode_count =
+			le32_to_cpu(sbi->ckpt->valid_inode_count);
 	sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count);
-	sbi->total_valid_block_count = le64_to_cpu(sbi->ckpt->valid_block_count);
+	sbi->total_valid_block_count =
+			le64_to_cpu(sbi->ckpt->valid_block_count);
 	sbi->last_valid_block_count = sbi->total_valid_block_count;
 	sbi->alloc_valid_block_count = 0;
 
@@ -1109,7 +1245,7 @@
 		return -1;
 	}
 
-	return ret;
+	return 0;
 }
 
 void f2fs_do_umount(struct f2fs_sb_info *sbi)
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index 53b8cb9..b02002c 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -5,6 +5,9 @@
  *             http://www.samsung.com/
  *
  * Dual licensed under the GPL or LGPL version 2 licenses.
+ *
+ * The byteswap codes are copied from:
+ *   samba_3_master/lib/ccan/endian/endian.h under LGPL 2.1
  */
 #ifndef __F2FS_FS_H__
 #define __F2FS_FS_H__
@@ -26,6 +29,63 @@
 typedef u8		bool;
 typedef unsigned long	pgoff_t;
 
+#if HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+/**
+ * bswap_16 - reverse bytes in a uint16_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ *	// Output contains "1024 is 4 as two bytes reversed"
+ *	printf("1024 is %u as two bytes reversed\n", bswap_16(1024));
+ */
+static inline uint16_t bswap_16(uint16_t val)
+{
+	return ((val & (uint16_t)0x00ffU) << 8)
+		| ((val & (uint16_t)0xff00U) >> 8);
+}
+
+/**
+ * bswap_32 - reverse bytes in a uint32_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ *	// Output contains "1024 is 262144 as four bytes reversed"
+ *	printf("1024 is %u as four bytes reversed\n", bswap_32(1024));
+ */
+static inline uint32_t bswap_32(uint32_t val)
+{
+	return ((val & (uint32_t)0x000000ffUL) << 24)
+		| ((val & (uint32_t)0x0000ff00UL) <<  8)
+		| ((val & (uint32_t)0x00ff0000UL) >>  8)
+		| ((val & (uint32_t)0xff000000UL) >> 24);
+}
+#endif /* !HAVE_BYTESWAP_H */
+
+#if !HAVE_BSWAP_64
+/**
+ * bswap_64 - reverse bytes in a uint64_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ *	// Output contains "1024 is 1125899906842624 as eight bytes reversed"
+ *	printf("1024 is %llu as eight bytes reversed\n",
+ *		(unsigned long long)bswap_64(1024));
+ */
+static inline uint64_t bswap_64(uint64_t val)
+{
+	return ((val & (uint64_t)0x00000000000000ffULL) << 56)
+		| ((val & (uint64_t)0x000000000000ff00ULL) << 40)
+		| ((val & (uint64_t)0x0000000000ff0000ULL) << 24)
+		| ((val & (uint64_t)0x00000000ff000000ULL) <<  8)
+		| ((val & (uint64_t)0x000000ff00000000ULL) >>  8)
+		| ((val & (uint64_t)0x0000ff0000000000ULL) >> 24)
+		| ((val & (uint64_t)0x00ff000000000000ULL) >> 40)
+		| ((val & (uint64_t)0xff00000000000000ULL) >> 56);
+}
+#endif
+
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #define le16_to_cpu(x)	((__u16)(x))
 #define le32_to_cpu(x)	((__u32)(x))
@@ -54,37 +114,39 @@
 /*
  * Debugging interfaces
  */
-#define ASSERT_MSG(exp, fmt, ...)					\
+#define FIX_MSG(fmt, ...)						\
 	do {								\
-		if (!(exp)) {						\
-			printf("\nAssertion failed!\n");		\
-			printf("[%s:%4d] " #exp, __func__, __LINE__);	\
-			printf("\n --> "fmt, ##__VA_ARGS__);		\
-			exit(-1);					\
-		}							\
-	} while (0);
+		printf("[FIX] (%s:%4d) ", __func__, __LINE__);		\
+		printf(" --> "fmt"\n", ##__VA_ARGS__);			\
+	} while (0)
+
+#define ASSERT_MSG(fmt, ...)						\
+	do {								\
+		printf("[ASSERT] (%s:%4d) ", __func__, __LINE__);	\
+		printf(" --> "fmt"\n", ##__VA_ARGS__);			\
+		config.bug_on = 1;					\
+	} while (0)
 
 #define ASSERT(exp)							\
 	do {								\
 		if (!(exp)) {						\
-			printf("\nAssertion failed!\n");		\
-			printf("[%s:%4d] " #exp"\n", __func__, __LINE__);\
+			printf("[ASSERT] (%s:%4d) " #exp"\n",		\
+					__func__, __LINE__);		\
 			exit(-1);					\
 		}							\
-	} while (0);
+	} while (0)
 
 #define ERR_MSG(fmt, ...)						\
 	do {								\
-		printf("[%s:%d] " fmt, __func__, __LINE__, ##__VA_ARGS__);	\
-	} while (0);
-
+		printf("[%s:%d] " fmt, __func__, __LINE__, ##__VA_ARGS__); \
+	} while (0)
 
 #define MSG(n, fmt, ...)						\
 	do {								\
 		if (config.dbg_lv >= n) {				\
 			printf(fmt, ##__VA_ARGS__);			\
 		}							\
-	} while (0);
+	} while (0)
 
 #define DBG(n, fmt, ...)						\
 	do {								\
@@ -92,52 +154,52 @@
 			printf("[%s:%4d] " fmt,				\
 				__func__, __LINE__, ##__VA_ARGS__);	\
 		}							\
-	} while (0);
+	} while (0)
 
 /* Display on console */
 #define DISP(fmt, ptr, member)				\
 	do {						\
 		printf("%-30s" fmt, #member, ((ptr)->member));	\
-	} while (0);
+	} while (0)
 
 #define DISP_u32(ptr, member)						\
 	do {								\
 		assert(sizeof((ptr)->member) <= 4);			\
 		printf("%-30s" "\t\t[0x%8x : %u]\n",		\
-			#member, ((ptr)->member), ((ptr)->member) );	\
-	} while (0);
+			#member, ((ptr)->member), ((ptr)->member));	\
+	} while (0)
 
 #define DISP_u64(ptr, member)						\
 	do {								\
 		assert(sizeof((ptr)->member) == 8);			\
 		printf("%-30s" "\t\t[0x%8llx : %llu]\n",		\
-			#member, ((ptr)->member), ((ptr)->member) );	\
-	} while (0);
+			#member, ((ptr)->member), ((ptr)->member));	\
+	} while (0)
 
 #define DISP_utf(ptr, member)						\
 	do {								\
-		printf("%-30s" "\t\t[%s]\n", #member, ((ptr)->member) );	\
-	} while (0);
+		printf("%-30s" "\t\t[%s]\n", #member, ((ptr)->member)); \
+	} while (0)
 
 /* Display to buffer */
-#define BUF_DISP_u32(buf, data, len, ptr, member)					\
-	do {										\
-		assert(sizeof((ptr)->member) <= 4);					\
-		snprintf(buf, len, #member);						\
-		snprintf(data, len, "0x%x : %u", ((ptr)->member), ((ptr)->member));	\
-	} while (0);
+#define BUF_DISP_u32(buf, data, len, ptr, member)			\
+	do {								\
+		assert(sizeof((ptr)->member) <= 4);			\
+		snprintf(buf, len, #member);				\
+		snprintf(data, len, "0x%x : %u", ((ptr)->member),	\
+						((ptr)->member));	\
+	} while (0)
 
-#define BUF_DISP_u64(buf, data, len, ptr, member)					\
-	do {										\
-		assert(sizeof((ptr)->member) == 8);					\
-		snprintf(buf, len, #member);						\
-		snprintf(data, len, "0x%llx : %llu", ((ptr)->member), ((ptr)->member));	\
-	} while (0);
+#define BUF_DISP_u64(buf, data, len, ptr, member)			\
+	do {								\
+		assert(sizeof((ptr)->member) == 8);			\
+		snprintf(buf, len, #member);				\
+		snprintf(data, len, "0x%llx : %llu", ((ptr)->member),	\
+						((ptr)->member));	\
+	} while (0)
 
-#define BUF_DISP_utf(buf, data, len, ptr, member)				\
-	do {									\
-		snprintf(buf, len, #member);					\
-	} while (0);
+#define BUF_DISP_utf(buf, data, len, ptr, member)			\
+		snprintf(buf, len, #member)
 
 /* these are defined in kernel */
 #define PAGE_SIZE		4096
@@ -173,12 +235,16 @@
 	char *vol_label;
 	int heap;
 	int32_t fd;
+	int32_t dump_fd;
 	char *device_name;
 	char *extension_list;
 	int dbg_lv;
 	int trim;
 	int func;
 	void *private;
+	int fix_on;
+	int bug_on;
+	int auto_fix;
 } __attribute__((packed));
 
 #ifdef CONFIG_64BIT
@@ -221,6 +287,7 @@
 #define F2FS_LOG_SECTORS_PER_BLOCK	3	/* 4KB: F2FS_BLKSIZE */
 #define F2FS_BLKSIZE			4096	/* support only 4KB block */
 #define F2FS_MAX_EXTENSION		64	/* # of extension entries */
+#define F2FS_BLK_ALIGN(x)	(((x) + F2FS_BLKSIZE - 1) / F2FS_BLKSIZE)
 
 #define NULL_ADDR		0x0U
 #define NEW_ADDR		-1U
@@ -283,6 +350,7 @@
 /*
  * For checkpoint
  */
+#define CP_FSCK_FLAG		0x00000010
 #define CP_ERROR_FLAG		0x00000008
 #define CP_COMPACT_SUM_FLAG	0x00000004
 #define CP_ORPHAN_PRESENT_FLAG	0x00000002
@@ -357,6 +425,9 @@
 
 #define F2FS_INLINE_XATTR	0x01	/* file inline xattr flag */
 #define F2FS_INLINE_DATA	0x02	/* file inline data flag */
+#define F2FS_INLINE_DENTRY	0x04	/* file inline dentry flag */
+#define F2FS_DATA_EXIST		0x08	/* file inline data exist flag */
+
 #define MAX_INLINE_DATA		(sizeof(__le32) * (DEF_ADDRS_PER_INODE - \
 						F2FS_INLINE_XATTR_ADDRS - 1))
 
@@ -412,6 +483,9 @@
 	OFFSET_BIT_SHIFT
 };
 
+#define XATTR_NODE_OFFSET	((((unsigned int)-1) << OFFSET_BIT_SHIFT) \
+				>> OFFSET_BIT_SHIFT)
+
 struct node_footer {
 	__le32 nid;		/* node id */
 	__le32 ino;		/* inode nunmber */
@@ -456,6 +530,13 @@
 #define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry))
 
 /*
+ * F2FS uses 4 bytes to represent block address. As a result, supported size of
+ * disk is 16 TB and it equals to 16 * 1024 * 1024 / 2 segments.
+ */
+#define F2FS_MAX_SEGMENT       ((16 * 1024 * 1024) / 2)
+#define MAX_SIT_BITMAP_SIZE    ((F2FS_MAX_SEGMENT / SIT_ENTRY_PER_BLOCK) / 8)
+
+/*
  * Note that f2fs_sit_entry->vblocks has the following bit-field information.
  * [15:10] : allocation type such as CURSEG_XXXX_TYPE
  * [9:0] : valid block count
@@ -619,6 +700,24 @@
 	__u8 filename[NR_DENTRY_IN_BLOCK][F2FS_SLOT_LEN];
 } __attribute__((packed));
 
+/* for inline dir */
+#define NR_INLINE_DENTRY	(MAX_INLINE_DATA * BITS_PER_BYTE / \
+				((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
+				BITS_PER_BYTE + 1))
+#define INLINE_DENTRY_BITMAP_SIZE	((NR_INLINE_DENTRY + \
+					BITS_PER_BYTE - 1) / BITS_PER_BYTE)
+#define INLINE_RESERVED_SIZE	(MAX_INLINE_DATA - \
+				((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
+				NR_INLINE_DENTRY + INLINE_DENTRY_BITMAP_SIZE))
+
+/* inline directory entry structure */
+struct f2fs_inline_dentry {
+	__u8 dentry_bitmap[INLINE_DENTRY_BITMAP_SIZE];
+	__u8 reserved[INLINE_RESERVED_SIZE];
+	struct f2fs_dir_entry dentry[NR_INLINE_DENTRY];
+	__u8 filename[NR_INLINE_DENTRY][F2FS_SLOT_LEN];
+} __packed;
+
 /* file types used in inode_info->flags */
 enum FILE_TYPE {
 	F2FS_FT_UNKNOWN,
@@ -632,6 +731,8 @@
 	F2FS_FT_MAX,
 	/* added for fsck */
 	F2FS_FT_ORPHAN,
+	F2FS_FT_XATTR,
+	F2FS_FT_LAST_FILE_TYPE = F2FS_FT_XATTR,
 };
 
 /* from f2fs/segment.h */
@@ -651,7 +752,8 @@
 extern int f2fs_test_bit(unsigned int, const char *);
 extern int f2fs_set_bit(unsigned int, char *);
 extern int f2fs_clear_bit(unsigned int, char *);
-extern unsigned long find_next_bit(const unsigned long *, unsigned long, unsigned long);
+extern unsigned long find_next_bit(const unsigned long *,
+				unsigned long, unsigned long);
 
 extern u_int32_t f2fs_cal_crc32(u_int32_t, void *, int);
 extern int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len);
@@ -663,13 +765,15 @@
 
 extern int dev_read(void *, __u64, size_t);
 extern int dev_write(void *, __u64, size_t);
+extern int dev_write_block(void *, __u64);
+extern int dev_write_dump(void *, __u64, size_t);
 /* All bytes in the buffer must be 0 use dev_fill(). */
 extern int dev_fill(void *, __u64, size_t);
 
 extern int dev_read_block(void *, __u64);
 extern int dev_read_blocks(void *, __u64, __u32 );
 
-f2fs_hash_t f2fs_dentry_hash(const char *, int);
+f2fs_hash_t f2fs_dentry_hash(const unsigned char *, int);
 
 extern struct f2fs_configuration config;
 
diff --git a/lib/libf2fs.c b/lib/libf2fs.c
index 6168c5c..73c551b 100644
--- a/lib/libf2fs.c
+++ b/lib/libf2fs.c
@@ -235,7 +235,8 @@
 
 }
 
-static void str2hashbuf(const char *msg, int len, unsigned int *buf, int num)
+static void str2hashbuf(const unsigned char *msg, int len,
+					unsigned int *buf, int num)
 {
 	unsigned pad, val;
 	int i;
@@ -269,24 +270,17 @@
  * @param len           name lenth
  * @return              return on success hash value, errno on failure
  */
-f2fs_hash_t f2fs_dentry_hash(const char *name, int len)
+f2fs_hash_t f2fs_dentry_hash(const unsigned char *name, int len)
 {
 	__u32 hash;
 	f2fs_hash_t	f2fs_hash;
-	const char	*p;
+	const unsigned char	*p;
 	__u32 in[8], buf[4];
 
 	/* special hash codes for special dentries */
-	if (name[0] == '.') {
-		if (name[1] == '\0') {
-			f2fs_hash = F2FS_DOT_HASH;
-			goto exit;
-		}
-		if (name[1] == '.' && name[2] == '\0') {
-			f2fs_hash = F2FS_DDOT_HASH;
-			goto exit;
-		}
-	}
+	if ((len <= 2) && (name[0] == '.') &&
+		(name[1] == '.' || name[1] == '\0'))
+		return 0;
 
 	/* Initialize the default seed for the hash checksum functions */
 	buf[0] = 0x67452301;
@@ -295,18 +289,17 @@
 	buf[3] = 0x10325476;
 
 	p = name;
-	while (len > 0) {
+	while (1) {
 		str2hashbuf(p, len, in, 4);
 		TEA_transform(buf, in);
-		len -= 16;
 		p += 16;
+		if (len <= 16)
+			break;
+		len -= 16;
 	}
 	hash = buf[0];
 
-	f2fs_hash = hash;
-exit:
-	f2fs_hash &= ~F2FS_HASH_COL_BIT;
-
+	f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT);
 	return f2fs_hash;
 }
 
@@ -429,6 +422,9 @@
 {
 	int32_t fd = 0;
 	uint32_t sector_size;
+#ifndef BLKGETSIZE64
+	uint32_t total_sectors;
+#endif
 	struct stat stat_buf;
 	struct hd_geometry geom;
 	u_int64_t wanted_total_sectors = c->total_sectors;
@@ -461,11 +457,20 @@
 			}
 		}
 
-		if (ioctl(fd, BLKGETSIZE, &c->total_sectors) < 0) {
+#ifdef BLKGETSIZE64
+		if (ioctl(fd, BLKGETSIZE64, &c->total_sectors) < 0) {
 			MSG(0, "\tError: Cannot get the device size\n");
 			return -1;
 		}
-
+		c->total_sectors /= c->sector_size;
+#else
+		if (ioctl(fd, BLKGETSIZE, &total_sectors) < 0) {
+			MSG(0, "\tError: Cannot get the device size\n");
+			return -1;
+		}
+		total_sectors /= c->sector_size;
+		c->total_sectors = total_sectors;
+#endif
 		if (ioctl(fd, HDIO_GETGEO, &geom) < 0)
 			c->start_sector = 0;
 		else
diff --git a/lib/libf2fs_io.c b/lib/libf2fs_io.c
index 5d9b68d..0c89ee4 100644
--- a/lib/libf2fs_io.c
+++ b/lib/libf2fs_io.c
@@ -46,6 +46,20 @@
 	return 0;
 }
 
+int dev_write_block(void *buf, __u64 blk_addr)
+{
+	return dev_write(buf, blk_addr * F2FS_BLKSIZE, F2FS_BLKSIZE);
+}
+
+int dev_write_dump(void *buf, __u64 offset, size_t len)
+{
+	if (lseek64(config.dump_fd, (off64_t)offset, SEEK_SET) < 0)
+		return -1;
+	if (write(config.dump_fd, buf, len) < 0)
+		return -1;
+	return 0;
+}
+
 int dev_fill(void *buf, __u64 offset, size_t len)
 {
 	/* Only allow fill to zero */
diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am
index ff136a7..fa48699 100644
--- a/mkfs/Makefile.am
+++ b/mkfs/Makefile.am
@@ -1,7 +1,7 @@
 ## Makefile.am
 
 AM_CPPFLAGS = ${libuuid_CFLAGS} -I$(top_srcdir)/include
-AM_CFLAGS = -Wall -DBLKDISCARD
+AM_CFLAGS = -Wall -DWITH_BLKDISCARD
 sbin_PROGRAMS = mkfs.f2fs
 mkfs_f2fs_SOURCES = f2fs_format_main.c f2fs_format.c f2fs_format_utils.c
 mkfs_f2fs_LDADD = ${libuuid_LIBS} $(top_builddir)/lib/libf2fs.la
diff --git a/mkfs/f2fs_format.c b/mkfs/f2fs_format.c
index 1568545..e300731 100644
--- a/mkfs/f2fs_format.c
+++ b/mkfs/f2fs_format.c
@@ -101,7 +101,8 @@
 	u_int32_t blocks_for_sit, blocks_for_nat, blocks_for_ssa;
 	u_int32_t total_valid_blks_available;
 	u_int64_t zone_align_start_offset, diff, total_meta_segments;
-	u_int32_t sit_bitmap_size, max_nat_bitmap_size, max_nat_segments;
+	u_int32_t sit_bitmap_size, max_sit_bitmap_size;
+	u_int32_t max_nat_bitmap_size, max_nat_segments;
 	u_int32_t total_zones;
 
 	super_block.magic = cpu_to_le32(F2FS_SUPER_MAGIC);
@@ -197,8 +198,26 @@
 	 */
 	sit_bitmap_size = ((le32_to_cpu(super_block.segment_count_sit) / 2) <<
 				log_blks_per_seg) / 8;
-	max_nat_bitmap_size = CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 1 -
-			sit_bitmap_size;
+
+	if (sit_bitmap_size > MAX_SIT_BITMAP_SIZE)
+		max_sit_bitmap_size = MAX_SIT_BITMAP_SIZE;
+	else
+		max_sit_bitmap_size = sit_bitmap_size;
+
+	/*
+	 * It should be reserved minimum 1 segment for nat.
+	 * When sit is too large, we should expand cp area. It requires more pages for cp.
+	 */
+	if (max_sit_bitmap_size >
+			(CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 65)) {
+		max_nat_bitmap_size = CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 1;
+		super_block.cp_payload = F2FS_BLK_ALIGN(max_sit_bitmap_size);
+	} else {
+		max_nat_bitmap_size = CHECKSUM_OFFSET - sizeof(struct f2fs_checkpoint) + 1
+			- max_sit_bitmap_size;
+		super_block.cp_payload = 0;
+	}
+
 	max_nat_segments = (max_nat_bitmap_size * 8) >> log_blks_per_seg;
 
 	if (le32_to_cpu(super_block.segment_count_nat) > max_nat_segments)
@@ -413,7 +432,8 @@
 	u_int32_t blk_size_bytes;
 	u_int64_t cp_seg_blk_offset = 0;
 	u_int32_t crc = 0;
-	int i;
+	unsigned int i;
+	char *cp_payload = NULL;
 
 	ckp = calloc(F2FS_BLKSIZE, 1);
 	if (ckp == NULL) {
@@ -427,6 +447,12 @@
 		return -1;
 	}
 
+	cp_payload = calloc(F2FS_BLKSIZE, 1);
+	if (cp_payload == NULL) {
+		MSG(1, "\tError: Calloc Failed for cp_payload!!!\n");
+		return -1;
+	}
+
 	/* 1. cp page 1 of checkpoint pack 1 */
 	ckp->checkpoint_ver = cpu_to_le64(1);
 	ckp->cur_node_segno[0] =
@@ -465,9 +491,10 @@
 			((le32_to_cpu(ckp->free_segment_count) + 6 -
 			le32_to_cpu(ckp->overprov_segment_count)) *
 			 config.blks_per_seg));
-	ckp->cp_pack_total_block_count = cpu_to_le32(8);
+	ckp->cp_pack_total_block_count =
+		cpu_to_le32(8 + le32_to_cpu(super_block.cp_payload));
 	ckp->ckpt_flags = cpu_to_le32(CP_UMOUNT_FLAG);
-	ckp->cp_pack_start_sum = cpu_to_le32(1);
+	ckp->cp_pack_start_sum = cpu_to_le32(1 + le32_to_cpu(super_block.cp_payload));
 	ckp->valid_node_count = cpu_to_le32(1);
 	ckp->valid_inode_count = cpu_to_le32(1);
 	ckp->next_free_nid = cpu_to_le32(
@@ -491,11 +518,20 @@
 	cp_seg_blk_offset *= blk_size_bytes;
 
 	DBG(1, "\tWriting main segments, ckp at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
-	if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+	if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
 		MSG(1, "\tError: While writing the ckp to disk!!!\n");
 		return -1;
 	}
 
+	for (i = 0; i < le32_to_cpu(super_block.cp_payload); i++) {
+		cp_seg_blk_offset += blk_size_bytes;
+		if (dev_fill(cp_payload, cp_seg_blk_offset, blk_size_bytes)) {
+			MSG(1, "\tError: While zeroing out the sit bitmap area \
+					on disk!!!\n");
+			return -1;
+		}
+	}
+
 	/* 2. Prepare and write Segment summary for data blocks */
 	memset(sum, 0, sizeof(struct f2fs_summary_block));
 	SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
@@ -505,7 +541,7 @@
 
 	cp_seg_blk_offset += blk_size_bytes;
 	DBG(1, "\tWriting segment summary for data, ckp at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
-	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+	if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
 		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
 		return -1;
 	}
@@ -516,7 +552,7 @@
 
 	cp_seg_blk_offset += blk_size_bytes;
 	DBG(1, "\tWriting segment summary, ckp at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
-	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+	if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
 		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
 		return -1;
 	}
@@ -546,7 +582,7 @@
 
 	cp_seg_blk_offset += blk_size_bytes;
 	DBG(1, "\tWriting data sit for root, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
-	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+	if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
 		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
 		return -1;
 	}
@@ -560,7 +596,7 @@
 
 	cp_seg_blk_offset += blk_size_bytes;
 	DBG(1, "\tWriting Segment summary for node blocks, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
-	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+	if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
 		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
 		return -1;
 	}
@@ -571,7 +607,7 @@
 
 	cp_seg_blk_offset += blk_size_bytes;
 	DBG(1, "\tWriting Segment summary for data block (1/2), at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
-	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+	if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
 		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
 		return -1;
 	}
@@ -581,7 +617,7 @@
 	SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
 	cp_seg_blk_offset += blk_size_bytes;
 	DBG(1, "\tWriting Segment summary for data block (2/2), at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
-	if (dev_write(sum, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+	if (dev_write(sum, cp_seg_blk_offset, blk_size_bytes)) {
 		MSG(1, "\tError: While writing the sum_blk to disk!!!\n");
 		return -1;
 	}
@@ -589,7 +625,7 @@
 	/* 8. cp page2 */
 	cp_seg_blk_offset += blk_size_bytes;
 	DBG(1, "\tWriting cp page2, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
-	if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+	if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
 		MSG(1, "\tError: While writing the ckp to disk!!!\n");
 		return -1;
 	}
@@ -606,21 +642,32 @@
 				config.blks_per_seg) *
 				blk_size_bytes;
 	DBG(1, "\tWriting cp page 1 of checkpoint pack 2, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
-	if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+	if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
 		MSG(1, "\tError: While writing the ckp to disk!!!\n");
 		return -1;
 	}
 
+	for (i = 0; i < le32_to_cpu(super_block.cp_payload); i++) {
+		cp_seg_blk_offset += blk_size_bytes;
+		if (dev_fill(cp_payload, cp_seg_blk_offset, blk_size_bytes)) {
+			MSG(1, "\tError: While zeroing out the sit bitmap area \
+					on disk!!!\n");
+			return -1;
+		}
+	}
+
 	/* 10. cp page 2 of check point pack 2 */
-	cp_seg_blk_offset += blk_size_bytes * (le32_to_cpu(ckp->cp_pack_total_block_count) - 1);
+	cp_seg_blk_offset += blk_size_bytes * (le32_to_cpu(ckp->cp_pack_total_block_count)
+			- le32_to_cpu(super_block.cp_payload) - 1);
 	DBG(1, "\tWriting cp page 2 of checkpoint pack 2, at offset 0x%08"PRIx64"\n", cp_seg_blk_offset);
-	if (dev_write(ckp, cp_seg_blk_offset, F2FS_BLKSIZE)) {
+	if (dev_write(ckp, cp_seg_blk_offset, blk_size_bytes)) {
 		MSG(1, "\tError: While writing the ckp to disk!!!\n");
 		return -1;
 	}
 
 	free(sum) ;
 	free(ckp) ;
+	free(cp_payload);
 	return	0;
 }
 
diff --git a/mkfs/f2fs_format_main.c b/mkfs/f2fs_format_main.c
index 19c52e4..e1f7c69 100644
--- a/mkfs/f2fs_format_main.c
+++ b/mkfs/f2fs_format_main.c
@@ -103,7 +103,8 @@
 	if ((optind + 1) < argc) {
 		/* We have a sector count. */
 		config.total_sectors = atoll(argv[optind+1]);
-		MSG(0, "\ttotal_sectors=%lu (%s bytes)\n", config.total_sectors, argv[optind+1]);
+		MSG(0, "\ttotal_sectors=%08"PRIx64" (%s bytes)\n",
+				config.total_sectors, argv[optind+1]);
 	}
 
 	config.reserved_segments  =
diff --git a/mkfs/f2fs_format_utils.c b/mkfs/f2fs_format_utils.c
index 8f7e094..9892a8f 100644
--- a/mkfs/f2fs_format_utils.c
+++ b/mkfs/f2fs_format_utils.c
@@ -15,6 +15,10 @@
 
 #include "f2fs_fs.h"
 
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#endif
+
 int f2fs_trim_device()
 {
 	unsigned long long range[2];
@@ -31,7 +35,7 @@
 		return -1;
 	}
 
-#if defined(BLKDISCARD)
+#if defined(WITH_BLKDISCARD) && defined(BLKDISCARD)
 	MSG(0, "Info: Discarding device\n");
 	if (S_ISREG(stat_buf.st_mode))
 		return 0;
diff --git a/scripts/tracepoint.sh b/scripts/tracepoint.sh
index b0d2fcb..15588d7 100755
--- a/scripts/tracepoint.sh
+++ b/scripts/tracepoint.sh
@@ -1,13 +1,16 @@
-#!/bin/bash
+#!/system/bin/sh
 
 TRACE=/sys/kernel/debug/tracing/
 dev=$(((8<<20) + 17)) # sdb1 (8,17)
 
-echo 1 > tracing_on
+echo 1 > $TRACE/tracing_on
+
+# mmc tracepoints
+echo 0 > $TRACE/events/mmc/enable
 
 # block tracepoints
-echo "dev == $dev" > $TRACE/events/block/block_rq_complete/filter
-echo 1 > $TRACE/events/block/block_rq_complete/enable
+#echo "dev == $dev" > $TRACE/events/block/block_rq_complete/filter
+echo 0 > $TRACE/events/block/block_rq_complete/enable
 echo 0 > $TRACE/events/block/block_bio_complete/enable
 
 # GC
@@ -41,9 +44,18 @@
 # IOs
 R=0
 W=0
-echo $W > $TRACE/events/f2fs/f2fs_submit_write_page/enable
-echo $W > $TRACE/events/f2fs/f2fs_do_submit_bio/enable
 echo $R > $TRACE/events/f2fs/f2fs_readpage/enable
+echo $W > $TRACE/events/f2fs/f2fs_writepage/enable
+echo $W > $TRACE/events/f2fs/f2fs_write_begin/enable
+echo $W > $TRACE/events/f2fs/f2fs_write_end/enable
+
+echo 0 > $TRACE/events/f2fs/f2fs_submit_page_bio/enable
+echo 0 > $TRACE/events/f2fs/f2fs_submit_page_mbio/enable
+echo $R > $TRACE/events/f2fs/f2fs_submit_read_bio/enable
+echo $W > $TRACE/events/f2fs/f2fs_submit_write_bio/enable
+
+echo 0 > $TRACE/events/f2fs/f2fs_issue_discard/enable
+echo 0 > $TRACE/events/f2fs/f2fs_issue_flush/enable
 
 # VFS interfaces
 V=0
diff --git a/tools/f2fstat.c b/tools/f2fstat.c
index c9c1d30..8643797 100644
--- a/tools/f2fstat.c
+++ b/tools/f2fstat.c
@@ -212,15 +212,72 @@
 	}
 }
 
-void print_head(void)
+void __make_head(char *head, int index, int i, int len)
 {
-	fprintf(stderr, "---utilization--- -----------main area-------- ---------balancing async------- ---gc--- ---alloc--- -----memory-----\n");
-	fprintf(stderr, "util  node   data   free  valid  dirty prefree node  dent meta  sit   nat fnid  cp   gc    ssr    lfs  total  node  meta\n");
+	char name_h[5][20] = {"main segments", "page/slab caches", "cp/gc", "blks", "memory"};
+	int half = (len - strlen(name_h[i])) / 2;
+
+	*(head + index) = '|';
+	index++;
+	memset(head + index, '-', half);
+	index += half;
+	strcpy(head + index, name_h[i]);
+	index += strlen(name_h[i]);
+	memset(head + index, '-', half);
+}
+
+void print_head(char *res)
+{
+	char *ptr, *ptr_buf;
+	char buf[1024], head[1024];
+	char name[20][10] = {"util", "node", "data", "free", "valid", "dirty", "prefree", "node", "dent", "meta",
+		"sit", "nat", "fnid", "cp", "gc", "ssr", "lfs", "total", "node", "meta"};
+	int i, len, prev_index = 0;
+
+	ptr_buf = buf;
+	memset(buf, ' ', 1024);
+	memset(head, ' ', 1024);
+
+	for (i = 0; i < 20; i++) {
+		ptr = (i == 0) ? strtok(res, " ") : strtok(NULL, " ");
+		strncpy(ptr_buf, name[i], strlen(name[i]));
+		if (i == 1) {
+			prev_index = ptr_buf - buf - 1;
+		} else if (i == 7) {
+			len = (ptr_buf - buf) - 1 - prev_index;
+			__make_head(head, prev_index, 0, len);
+			prev_index = ptr_buf - buf - 1;
+		} else if (i == 13) {
+			len = (ptr_buf - buf) - 1 - prev_index;
+			__make_head(head, prev_index, 1, len);
+			prev_index = ptr_buf - buf - 1;
+		} else if (i == 15) {
+			len = (ptr_buf - buf) - 1 - prev_index;
+			__make_head(head, prev_index, 2, len);
+			prev_index = ptr_buf - buf - 1;
+		} else if (i == 17) {
+			len = (ptr_buf - buf) - 1 - prev_index;
+			__make_head(head, prev_index, 3, len);
+			prev_index = ptr_buf - buf - 1;
+		}
+
+		len = strlen(ptr);
+		ptr_buf += (len > strlen(name[i]) ? len : strlen(name[i])) + 1;
+	}
+
+	len = (ptr_buf - buf) - 1 - prev_index;
+	__make_head(head, prev_index, 4, len);
+
+	*ptr_buf = 0;
+	*(head + (ptr_buf - buf - 1)) = '|';
+	*(head + (ptr_buf - buf)) = 0;
+	fprintf(stderr, "%s\n%s\n", head, buf);
 }
 
 int main(int argc, char *argv[])
 {
-	char format[] = "%3ld %6ld %6ld %6ld %6ld %6ld %6ld %5ld %5ld %3ld %5ld %5ld %3ld %3ld %3ld %6ld %6ld %6ld %6ld %6ld\n";
+	char format[] = "%4ld %4ld %4ld %4ld %5ld %5ld %7ld %4ld %4ld %4ld %3ld %3ld %4ld %2ld %2ld %3ld %3ld %5ld %4ld %4ld";
+	char buf[1024], tmp[1024];
 	int head_interval;
 	struct options opt = {
 		.delay = 1,
@@ -231,20 +288,22 @@
 	parse_option(argc, argv, &opt);
 	head_interval = opt.interval;
 
-	print_head();
 	while (1) {
-		if (head_interval-- == 0) {
-			print_head();
-			head_interval = opt.interval;
-		}
-
+		memset(buf, 0, 1024);
 		f2fstat(&opt);
-
-		fprintf(stderr, format, util, used_node_blks, used_data_blks,
+		sprintf(buf, format, util, used_node_blks, used_data_blks,
 			free_segs, valid_segs, dirty_segs, prefree_segs,
 			dirty_node, dirty_dents, dirty_meta, dirty_sit, nat_caches, free_nids,
 			cp, gc, ssr_blks, lfs_blks, memory_kb, node_kb, meta_kb);
 
+		strcpy(tmp, buf);
+		if (head_interval == opt.interval)
+			print_head(tmp);
+		if (head_interval-- == 0)
+			head_interval = opt.interval;
+
+		fprintf(stderr, "%s\n", buf);
+
 		sleep(opt.delay);
 	}