diff options
| author | Jaegeuk Kim <jaegeuk@kernel.org> | 2023-04-06 21:18:48 +0300 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-05-17 12:50:25 +0300 |
| commit | 8f57f3e112cf1d16682b6ff9c31c72f40f7da9c9 (patch) | |
| tree | 81ff8d75c375840a2f2b34d9c5aa4a7ed5400381 | |
| parent | e2d1cc82ad509c07a9ab0ab4bf88b6613fbf784b (diff) | |
| download | linux-8f57f3e112cf1d16682b6ff9c31c72f40f7da9c9.tar.xz | |
f2fs: fix potential corruption when moving a directory
commit d94772154e524b329a168678836745d2773a6e02 upstream.
F2FS has the same issue in ext4_rename causing crash revealed by
xfstests/generic/707.
See also commit 0813299c586b ("ext4: Fix possible corruption when moving a directory")
CC: stable@vger.kernel.org
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | fs/f2fs/namei.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 7a86a8dcf4f1..f3b7ed54f402 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -991,12 +991,20 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out; } + /* + * Copied from ext4_rename: we need to protect against old.inode + * directory getting converted from inline directory format into + * a normal one. + */ + if (S_ISDIR(old_inode->i_mode)) + inode_lock_nested(old_inode, I_MUTEX_NONDIR2); + err = -ENOENT; old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page); if (!old_entry) { if (IS_ERR(old_page)) err = PTR_ERR(old_page); - goto out; + goto out_unlock_old; } if (S_ISDIR(old_inode->i_mode)) { @@ -1104,6 +1112,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, f2fs_unlock_op(sbi); + if (S_ISDIR(old_inode->i_mode)) + inode_unlock(old_inode); + if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) f2fs_sync_fs(sbi->sb, 1); @@ -1118,6 +1129,9 @@ out_dir: f2fs_put_page(old_dir_page, 0); out_old: f2fs_put_page(old_page, 0); +out_unlock_old: + if (S_ISDIR(old_inode->i_mode)) + inode_unlock(old_inode); out: if (whiteout) iput(whiteout); |
