f2fs_trace_pid(page);
 }
 
-void add_dirty_dir_inode(struct inode *inode)
-{
-       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-
-       spin_lock(&sbi->inode_lock[DIR_INODE]);
-       __add_dirty_inode(inode, DIR_INODE);
-       spin_unlock(&sbi->inode_lock[DIR_INODE]);
-}
-
 void remove_dirty_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       struct f2fs_inode_info *fi = F2FS_I(inode);
        enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE;
 
        if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
        spin_lock(&sbi->inode_lock[type]);
        __remove_dirty_inode(inode, type);
        spin_unlock(&sbi->inode_lock[type]);
-
-       /* Only from the recovery routine */
-       if (is_inode_flag_set(fi, FI_DELAY_IPUT)) {
-               clear_inode_flag(fi, FI_DELAY_IPUT);
-               iput(inode);
-       }
 }
 
 int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
 
        FI_NO_ALLOC,            /* should not allocate any blocks */
        FI_FREE_NID,            /* free allocated nide */
        FI_UPDATE_DIR,          /* should update inode block for consistency */
-       FI_DELAY_IPUT,          /* used for the recovery */
        FI_NO_EXTENT,           /* not to use the extent cache */
        FI_INLINE_XATTR,        /* used for inline xattr */
        FI_INLINE_DATA,         /* used for inline data*/
 int recover_orphan_inodes(struct f2fs_sb_info *);
 int get_valid_checkpoint(struct f2fs_sb_info *);
 void update_dirty_page(struct inode *, struct page *);
-void add_dirty_dir_inode(struct inode *);
 void remove_dirty_inode(struct inode *);
 int sync_dirty_inodes(struct f2fs_sb_info *, enum inode_type);
 int write_checkpoint(struct f2fs_sb_info *, struct cp_control *);
 
        kmem_cache_free(fsync_entry_slab, entry);
 }
 
-static int recover_dentry(struct inode *inode, struct page *ipage)
+static int recover_dentry(struct inode *inode, struct page *ipage,
+                                               struct list_head *dir_list)
 {
        struct f2fs_inode *raw_inode = F2FS_INODE(ipage);
        nid_t pino = le32_to_cpu(raw_inode->i_pino);
        struct qstr name;
        struct page *page;
        struct inode *dir, *einode;
+       struct fsync_inode_entry *entry;
        int err = 0;
 
-       dir = f2fs_iget(inode->i_sb, pino);
-       if (IS_ERR(dir)) {
-               err = PTR_ERR(dir);
-               goto out;
+       entry = get_fsync_inode(dir_list, pino);
+       if (!entry) {
+               dir = f2fs_iget(inode->i_sb, pino);
+               if (IS_ERR(dir)) {
+                       err = PTR_ERR(dir);
+                       goto out;
+               }
+
+               entry = add_fsync_inode(dir_list, dir);
+               if (!entry) {
+                       err = -ENOMEM;
+                       iput(dir);
+                       goto out;
+               }
        }
 
-       if (file_enc_name(inode)) {
-               iput(dir);
+       dir = entry->inode;
+
+       if (file_enc_name(inode))
                return 0;
-       }
 
        name.len = le32_to_cpu(raw_inode->i_namelen);
        name.name = raw_inode->i_name;
        if (unlikely(name.len > F2FS_NAME_LEN)) {
                WARN_ON(1);
                err = -ENAMETOOLONG;
-               goto out_err;
+               goto out;
        }
 retry:
        de = f2fs_find_entry(dir, &name, &page);
                goto retry;
        }
        err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode);
-       if (err)
-               goto out_err;
-
-       if (is_inode_flag_set(F2FS_I(dir), FI_DELAY_IPUT)) {
-               iput(dir);
-       } else {
-               add_dirty_dir_inode(dir);
-               set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT);
-       }
 
        goto out;
 
 out_unmap_put:
        f2fs_dentry_kunmap(dir, page);
        f2fs_put_page(page, 0);
-out_err:
-       iput(dir);
 out:
        f2fs_msg(inode->i_sb, KERN_NOTICE,
                        "%s: ino = %x, name = %s, dir = %lx, err = %d",
        return err;
 }
 
-static int recover_data(struct f2fs_sb_info *sbi, struct list_head *head)
+static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
+                                               struct list_head *dir_list)
 {
        unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi));
        struct curseg_info *curseg;
                        break;
                }
 
-               entry = get_fsync_inode(head, ino_of_node(page));
+               entry = get_fsync_inode(inode_list, ino_of_node(page));
                if (!entry)
                        goto next;
                /*
                if (IS_INODE(page))
                        recover_inode(entry->inode, page);
                if (entry->last_dentry == blkaddr) {
-                       err = recover_dentry(entry->inode, page);
+                       err = recover_dentry(entry->inode, page, dir_list);
                        if (err) {
                                f2fs_put_page(page, 1);
                                break;
 {
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
        struct list_head inode_list;
+       struct list_head dir_list;
        block_t blkaddr;
        int err;
        int ret = 0;
                return -ENOMEM;
 
        INIT_LIST_HEAD(&inode_list);
+       INIT_LIST_HEAD(&dir_list);
 
        /* prevent checkpoint */
        mutex_lock(&sbi->cp_mutex);
        need_writecp = true;
 
        /* step #2: recover data */
-       err = recover_data(sbi, &inode_list);
+       err = recover_data(sbi, &inode_list, &dir_list);
        if (!err)
                f2fs_bug_on(sbi, !list_empty(&inode_list));
 out:
        destroy_fsync_dnodes(&inode_list);
-       kmem_cache_destroy(fsync_entry_slab);
 
        /* truncate meta pages to be used by the recovery */
        truncate_inode_pages_range(META_MAPPING(sbi),
        } else {
                mutex_unlock(&sbi->cp_mutex);
        }
+
+       destroy_fsync_dnodes(&dir_list);
+       kmem_cache_destroy(fsync_entry_slab);
        return ret ? ret: err;
 }