This patch fixes a couple of bugs regarding to orphan inodes when handling
errors.

This tries to
 - call alloc_nid_done with add_orphan_inode in handle_failed_inode
 - let truncate blocks in f2fs_evict_inode
 - not make a bad inode due to i_mode change

Signed-off-by: Jaegeuk Kim <jaeg...@kernel.org>
---
 fs/f2fs/dir.c   | 20 ++++++++++++--------
 fs/f2fs/inode.c | 40 ++++++++++++++++------------------------
 2 files changed, 28 insertions(+), 32 deletions(-)

diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 50f42be..5373f33 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -391,9 +391,14 @@ struct page *init_inode_metadata(struct inode *inode, 
struct inode *dir,
                        return page;
 
                if (S_ISDIR(inode->i_mode)) {
+                       /* in order to handle error case */
+                       get_page(page);
                        err = make_empty_dir(inode, dir, page);
-                       if (err)
-                               goto error;
+                       if (err) {
+                               lock_page(page);
+                               goto put_error;
+                       }
+                       put_page(page);
                }
 
                err = f2fs_init_acl(inode, dir, page, dpage);
@@ -437,13 +442,12 @@ struct page *init_inode_metadata(struct inode *inode, 
struct inode *dir,
        return page;
 
 put_error:
-       f2fs_put_page(page, 1);
-error:
-       /* once the failed inode becomes a bad inode, i_mode is S_IFREG */
+       /* truncate empty dir pages */
        truncate_inode_pages(&inode->i_data, 0);
-       truncate_blocks(inode, 0, false);
-       remove_dirty_inode(inode);
-       remove_inode_page(inode);
+
+       clear_nlink(inode);
+       update_inode(inode, page);
+       f2fs_put_page(page, 1);
        return ERR_PTR(err);
 }
 
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index cb269c4..f4ac851 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -368,10 +368,7 @@ no_delete:
        if (is_inode_flag_set(fi, FI_UPDATE_WRITE))
                add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
        if (is_inode_flag_set(fi, FI_FREE_NID)) {
-               if (err && err != -ENOENT)
-                       alloc_nid_done(sbi, inode->i_ino);
-               else
-                       alloc_nid_failed(sbi, inode->i_ino);
+               alloc_nid_failed(sbi, inode->i_ino);
                clear_inode_flag(fi, FI_FREE_NID);
        }
 
@@ -397,37 +394,32 @@ out_clear:
 void handle_failed_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       int err = 0;
+       struct node_info ni;
 
-       clear_nlink(inode);
-       make_bad_inode(inode);
+       /* don't make bad inode, since it becomes a regular file. */
        unlock_new_inode(inode);
 
-       i_size_write(inode, 0);
-       if (F2FS_HAS_BLOCKS(inode))
-               err = f2fs_truncate(inode, false);
-
-       if (!err)
-               err = remove_inode_page(inode);
-
        /*
-        * if we skip truncate_node in remove_inode_page bacause we failed
-        * before, it's better to find another way to release resource of
-        * this inode (e.g. valid block count, node block or nid). Here we
-        * choose to add this inode to orphan list, so that we can call iput
-        * for releasing in orphan recovery flow.
-        *
         * Note: we should add inode to orphan list before f2fs_unlock_op()
         * so we can prevent losing this orphan when encoutering checkpoint
         * and following suddenly power-off.
         */
-       if (err && err != -ENOENT) {
-               err = acquire_orphan_inode(sbi);
-               if (!err)
+       get_node_info(sbi, inode->i_ino, &ni);
+
+       if (ni.blk_addr != NULL_ADDR) {
+               int err = acquire_orphan_inode(sbi);
+               if (err) {
+                       set_sbi_flag(sbi, SBI_NEED_FSCK);
+                       f2fs_msg(sbi->sb, KERN_WARNING,
+                               "Too many orphan inodes, run fsck to fix.");
+               } else {
                        add_orphan_inode(sbi, inode->i_ino);
+               }
+               alloc_nid_done(sbi, inode->i_ino);
+       } else {
+               set_inode_flag(F2FS_I(inode), FI_FREE_NID);
        }
 
-       set_inode_flag(F2FS_I(inode), FI_FREE_NID);
        f2fs_unlock_op(sbi);
 
        /* iput will drop the inode object */
-- 
2.6.3


------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel

Reply via email to