lkml.org 
[lkml]   [2021]   [Feb]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 5.10 34/56] f2fs: fix to set/clear I_LINKABLE under i_lock
    Date
    From: Chao Yu <yuchao0@huawei.com>

    [ Upstream commit 46085f37fc9e12d5c3539fb768b5ad7951e72acf ]

    fsstress + fault injection test case reports a warning message as
    below:

    WARNING: CPU: 13 PID: 6226 at fs/inode.c:361 inc_nlink+0x32/0x40
    Call Trace:
    f2fs_init_inode_metadata+0x25c/0x4a0 [f2fs]
    f2fs_add_inline_entry+0x153/0x3b0 [f2fs]
    f2fs_add_dentry+0x75/0x80 [f2fs]
    f2fs_do_add_link+0x108/0x160 [f2fs]
    f2fs_rename2+0x6ab/0x14f0 [f2fs]
    vfs_rename+0x70c/0x940
    do_renameat2+0x4d8/0x4f0
    __x64_sys_renameat2+0x4b/0x60
    do_syscall_64+0x33/0x80
    entry_SYSCALL_64_after_hwframe+0x44/0xa9

    Following race case can cause this:
    Thread A Kworker
    - f2fs_rename
    - f2fs_create_whiteout
    - __f2fs_tmpfile
    - f2fs_i_links_write
    - f2fs_mark_inode_dirty_sync
    - mark_inode_dirty_sync
    - writeback_single_inode
    - __writeback_single_inode
    - spin_lock(&inode->i_lock)
    - inode->i_state |= I_LINKABLE
    - inode->i_state &= ~dirty
    - spin_unlock(&inode->i_lock)
    - f2fs_add_link
    - f2fs_do_add_link
    - f2fs_add_dentry
    - f2fs_add_inline_entry
    - f2fs_init_inode_metadata
    - f2fs_i_links_write
    - inc_nlink
    - WARN_ON(!(inode->i_state & I_LINKABLE))

    Fix to add i_lock to avoid i_state update race condition.

    Signed-off-by: Chao Yu <yuchao0@huawei.com>
    Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/f2fs/namei.c | 8 ++++++++
    1 file changed, 8 insertions(+)

    diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
    index 8fa37d1434de1..5f7ab4f113224 100644
    --- a/fs/f2fs/namei.c
    +++ b/fs/f2fs/namei.c
    @@ -854,7 +854,11 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,

    if (whiteout) {
    f2fs_i_links_write(inode, false);
    +
    + spin_lock(&inode->i_lock);
    inode->i_state |= I_LINKABLE;
    + spin_unlock(&inode->i_lock);
    +
    *whiteout = inode;
    } else {
    d_tmpfile(dentry, inode);
    @@ -1040,7 +1044,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
    err = f2fs_add_link(old_dentry, whiteout);
    if (err)
    goto put_out_dir;
    +
    + spin_lock(&whiteout->i_lock);
    whiteout->i_state &= ~I_LINKABLE;
    + spin_unlock(&whiteout->i_lock);
    +
    iput(whiteout);
    }

    --
    2.27.0
    \
     
     \ /
      Last update: 2021-02-24 15:11    [W:4.122 / U:1.300 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site