f2fs: avoid to use failed inode immediately
authorJaegeuk Kim <jaegeuk@kernel.org>
Tue, 23 Jun 2015 17:36:08 +0000 (10:36 -0700)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 4 Aug 2015 21:09:53 +0000 (14:09 -0700)
Before iput is called, the inode number used by a bad inode can be reassigned
to other new inode, resulting in any abnormal behaviors on the new inode.
This should not happen for the new inode.

Reviewed-by: Chao Yu <chao2.yu@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/f2fs.h
fs/f2fs/inode.c
fs/f2fs/namei.c

index 516220454a4ee805d8df491f38e31b8ea15a995e..3aaa4b99050a94515bd9c33d81e6208c29b36cb0 100644 (file)
@@ -1343,6 +1343,7 @@ enum {
        FI_INC_LINK,            /* need to increment i_nlink */
        FI_ACL_MODE,            /* indicate acl mode */
        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 */
index 2550868dc651eefe3ed3f1643f9af47a777cdeb9..757fed253697ad95432795026e81c4478109191b 100644 (file)
@@ -314,7 +314,8 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
 void f2fs_evict_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       nid_t xnid = fi->i_xattr_nid;
 
        /* some remained atomic pages should discarded */
        if (f2fs_is_atomic_file(inode))
@@ -334,7 +335,7 @@ void f2fs_evict_inode(struct inode *inode)
                goto no_delete;
 
        sb_start_intwrite(inode->i_sb);
-       set_inode_flag(F2FS_I(inode), FI_NO_ALLOC);
+       set_inode_flag(fi, FI_NO_ALLOC);
        i_size_write(inode, 0);
 
        if (F2FS_HAS_BLOCKS(inode))
@@ -357,14 +358,18 @@ no_delete:
        invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino);
        if (xnid)
                invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid);
-       if (is_inode_flag_set(F2FS_I(inode), FI_APPEND_WRITE))
+       if (is_inode_flag_set(fi, FI_APPEND_WRITE))
                add_dirty_inode(sbi, inode->i_ino, APPEND_INO);
-       if (is_inode_flag_set(F2FS_I(inode), FI_UPDATE_WRITE))
+       if (is_inode_flag_set(fi, FI_UPDATE_WRITE))
                add_dirty_inode(sbi, inode->i_ino, UPDATE_INO);
+       if (is_inode_flag_set(fi, FI_FREE_NID)) {
+               alloc_nid_failed(sbi, inode->i_ino);
+               clear_inode_flag(fi, FI_FREE_NID);
+       }
 out_clear:
 #ifdef CONFIG_F2FS_FS_ENCRYPTION
-       if (F2FS_I(inode)->i_crypt_info)
-               f2fs_free_encryption_info(inode, F2FS_I(inode)->i_crypt_info);
+       if (fi->i_crypt_info)
+               f2fs_free_encryption_info(inode, fi->i_crypt_info);
 #endif
        clear_inode(inode);
 }
@@ -384,9 +389,9 @@ void handle_failed_inode(struct inode *inode)
 
        remove_inode_page(inode);
 
+       set_inode_flag(F2FS_I(inode), FI_FREE_NID);
        clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
        clear_inode_flag(F2FS_I(inode), FI_INLINE_DENTRY);
-       alloc_nid_failed(sbi, inode->i_ino);
        f2fs_unlock_op(sbi);
 
        /* iput will drop the inode object */
index fdbae21ee8fb2ca991c2e37e35b9fdc505eb291a..08656fca8f838ee41418ca9d80f267400862c999 100644 (file)
@@ -78,9 +78,9 @@ out:
 fail:
        trace_f2fs_new_inode(inode, err);
        make_bad_inode(inode);
-       iput(inode);
        if (nid_free)
-               alloc_nid_failed(sbi, ino);
+               set_inode_flag(F2FS_I(inode), FI_FREE_NID);
+       iput(inode);
        return ERR_PTR(err);
 }