summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@kernel.org>2023-04-06 21:18:48 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-05-17 12:50:25 +0300
commit8f57f3e112cf1d16682b6ff9c31c72f40f7da9c9 (patch)
tree81ff8d75c375840a2f2b34d9c5aa4a7ed5400381
parente2d1cc82ad509c07a9ab0ab4bf88b6613fbf784b (diff)
downloadlinux-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.c16
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);