]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
f2fs: set I_LINKABLE early to avoid wrong access by vfs
authorJaegeuk Kim <jaegeuk@kernel.org>
Sat, 7 Dec 2019 00:59:58 +0000 (16:59 -0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 15 Jan 2020 21:43:48 +0000 (13:43 -0800)
This patch moves setting I_LINKABLE early in rename2(whiteout) to avoid the
below warning.

[ 3189.163385] WARNING: CPU: 3 PID: 59523 at fs/inode.c:358 inc_nlink+0x32/0x40
[ 3189.246979] Call Trace:
[ 3189.248707]  f2fs_init_inode_metadata+0x2d6/0x440 [f2fs]
[ 3189.251399]  f2fs_add_inline_entry+0x162/0x8c0 [f2fs]
[ 3189.254010]  f2fs_add_dentry+0x69/0xe0 [f2fs]
[ 3189.256353]  f2fs_do_add_link+0xc5/0x100 [f2fs]
[ 3189.258774]  f2fs_rename2+0xabf/0x1010 [f2fs]
[ 3189.261079]  vfs_rename+0x3f8/0xaa0
[ 3189.263056]  ? tomoyo_path_rename+0x44/0x60
[ 3189.265283]  ? do_renameat2+0x49b/0x550
[ 3189.267324]  do_renameat2+0x49b/0x550
[ 3189.269316]  __x64_sys_renameat2+0x20/0x30
[ 3189.271441]  do_syscall_64+0x5a/0x230
[ 3189.273410]  entry_SYSCALL_64_after_hwframe+0x49/0xbe
[ 3189.275848] RIP: 0033:0x7f270b4d9a49

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/namei.c

index a1c507b0b4ac4b293b4e086675b2a3669f76d177..5d9584281935fa9290906f3bef89fe705675ad2d 100644 (file)
@@ -797,6 +797,7 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
 
        if (whiteout) {
                f2fs_i_links_write(inode, false);
+               inode->i_state |= I_LINKABLE;
                *whiteout = inode;
        } else {
                d_tmpfile(dentry, inode);
@@ -867,6 +868,12 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        F2FS_I(old_dentry->d_inode)->i_projid)))
                return -EXDEV;
 
+       if (flags & RENAME_WHITEOUT) {
+               err = f2fs_create_whiteout(old_dir, &whiteout);
+               if (err)
+                       return err;
+       }
+
        err = dquot_initialize(old_dir);
        if (err)
                goto out;
@@ -898,17 +905,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                }
        }
 
-       if (flags & RENAME_WHITEOUT) {
-               err = f2fs_create_whiteout(old_dir, &whiteout);
-               if (err)
-                       goto out_dir;
-       }
-
        if (new_inode) {
 
                err = -ENOTEMPTY;
                if (old_dir_entry && !f2fs_empty_dir(new_inode))
-                       goto out_whiteout;
+                       goto out_dir;
 
                err = -ENOENT;
                new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
@@ -916,7 +917,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (!new_entry) {
                        if (IS_ERR(new_page))
                                err = PTR_ERR(new_page);
-                       goto out_whiteout;
+                       goto out_dir;
                }
 
                f2fs_balance_fs(sbi, true);
@@ -948,7 +949,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                err = f2fs_add_link(new_dentry, old_inode);
                if (err) {
                        f2fs_unlock_op(sbi);
-                       goto out_whiteout;
+                       goto out_dir;
                }
 
                if (old_dir_entry)
@@ -972,7 +973,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                                if (IS_ERR(old_page))
                                        err = PTR_ERR(old_page);
                                f2fs_unlock_op(sbi);
-                               goto out_whiteout;
+                               goto out_dir;
                        }
                }
        }
@@ -991,7 +992,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
        f2fs_delete_entry(old_entry, old_page, old_dir, NULL);
 
        if (whiteout) {
-               whiteout->i_state |= I_LINKABLE;
                set_inode_flag(whiteout, FI_INC_LINK);
                err = f2fs_add_link(old_dentry, whiteout);
                if (err)
@@ -1027,15 +1027,14 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
        f2fs_unlock_op(sbi);
        if (new_page)
                f2fs_put_page(new_page, 0);
-out_whiteout:
-       if (whiteout)
-               iput(whiteout);
 out_dir:
        if (old_dir_entry)
                f2fs_put_page(old_dir_page, 0);
 out_old:
        f2fs_put_page(old_page, 0);
 out:
+       if (whiteout)
+               iput(whiteout);
        return err;
 }