fsck.f2fs: fix missing dentries

If a directory has no dot and dotdot dentries, fsck.f2fs sets inline_dots for
the inode so that f2fs module can handle that properly.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
diff --git a/fsck/fsck.c b/fsck/fsck.c
index d83f5a8..8211159 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -476,7 +476,7 @@
 		u32 *blk_cnt, struct node_info *ni)
 {
 	struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
-	struct child_info child = {0, 0};
+	struct child_info child = {2, 0, 0};
 	enum NODE_TYPE ntype;
 	u32 i_links = le32_to_cpu(node_blk->i.i_links);
 	u64 i_blocks = le64_to_cpu(node_blk->i.i_blocks);
@@ -631,26 +631,38 @@
 		}
 	}
 skip_blkcnt_fix:
-	if (ftype == F2FS_FT_DIR)
-		DBG(1, "Directory Inode: 0x%x [%s] depth: %d has %d files\n\n",
-				le32_to_cpu(node_blk->footer.ino),
-				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: 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.links) {
-		ASSERT_MSG("ino: 0x%x has i_links: %u but real links: %u",
-				nid, i_links, child.links);
-		if (config.fix_on) {
-			node_blk->i.i_links = cpu_to_le32(child.links);
-			need_fix = 1;
-			FIX_MSG("Dir: 0x%x i_links= 0x%x -> 0x%x",
+	if (ftype == F2FS_FT_DIR) {
+		DBG(1, "Directory Inode: 0x%x [%s] depth: %d has %d files\n\n",
+				le32_to_cpu(node_blk->footer.ino),
+				node_blk->i.i_name,
+				le32_to_cpu(node_blk->i.i_current_depth),
+				child.files);
+
+		if (i_links != child.links) {
+			ASSERT_MSG("ino: 0x%x i_links: %u, real links: %u",
+					nid, i_links, child.links);
+			if (config.fix_on) {
+				node_blk->i.i_links = cpu_to_le32(child.links);
+				need_fix = 1;
+				FIX_MSG("Dir: 0x%x i_links= 0x%x -> 0x%x",
 						nid, i_links, child.links);
+			}
+		}
+		if (child.dots < 2 &&
+				!(node_blk->i.i_inline & F2FS_INLINE_DOTS)) {
+			ASSERT_MSG("ino: 0x%x dots: %u",
+					nid, child.dots);
+			if (config.fix_on) {
+				node_blk->i.i_inline |= F2FS_INLINE_DOTS;
+				need_fix = 1;
+				FIX_MSG("Dir: 0x%x set inline_dots", nid);
+			}
 		}
 	}
 
@@ -877,7 +889,7 @@
 							name_len == 2)) {
 				i++;
 				free(name);
-				child->links++;
+				child->dots++;
 				continue;
 			}
 		}
diff --git a/fsck/fsck.h b/fsck/fsck.h
index 97e2385..5eac45c 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -22,6 +22,7 @@
 struct child_info {
 	u32 links;
 	u32 files;
+	u8 dots;
 };
 
 struct f2fs_fsck {
diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h
index 6ce58c2..d23ae1b 100644
--- a/include/f2fs_fs.h
+++ b/include/f2fs_fs.h
@@ -436,6 +436,7 @@
 #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 F2FS_INLINE_DOTS	0x10	/* file having implicit dot dentries */
 
 #define MAX_INLINE_DATA		(sizeof(__le32) * (DEF_ADDRS_PER_INODE - \
 						F2FS_INLINE_XATTR_ADDRS - 1))