Merge tag 'pull-rename' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull rename updates from Al Viro:
 "Fix directory locking scheme on rename

  This was broken in 6.5; we really can't lock two unrelated directories
  without holding ->s_vfs_rename_mutex first and in case of same-parent
  rename of a subdirectory 6.5 ends up doing just that"

* tag 'pull-rename' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  rename(): avoid a deadlock in the case of parents having no common ancestor
  kill lock_two_inodes()
  rename(): fix the locking of subdirectories
  f2fs: Avoid reading renamed directory if parent does not change
  ext4: don't access the source subdirectory content on same-directory rename
  ext2: Avoid reading renamed directory if parent does not change
  udf_rename(): only access the child content on cross-directory rename
  ocfs2: Avoid touching renamed directory if parent does not change
  reiserfs: Avoid touching renamed directory if parent does not change
This commit is contained in:
Linus Torvalds
2024-01-11 20:00:22 -08:00
20 changed files with 428 additions and 218 deletions

View File

@@ -325,6 +325,7 @@ static int ext2_rename (struct mnt_idmap * idmap,
struct ext2_dir_entry_2 * dir_de = NULL;
struct folio * old_folio;
struct ext2_dir_entry_2 * old_de;
bool old_is_dir = S_ISDIR(old_inode->i_mode);
int err;
if (flags & ~RENAME_NOREPLACE)
@@ -342,7 +343,7 @@ static int ext2_rename (struct mnt_idmap * idmap,
if (IS_ERR(old_de))
return PTR_ERR(old_de);
if (S_ISDIR(old_inode->i_mode)) {
if (old_is_dir && old_dir != new_dir) {
err = -EIO;
dir_de = ext2_dotdot(old_inode, &dir_folio);
if (!dir_de)
@@ -354,7 +355,7 @@ static int ext2_rename (struct mnt_idmap * idmap,
struct ext2_dir_entry_2 *new_de;
err = -ENOTEMPTY;
if (dir_de && !ext2_empty_dir (new_inode))
if (old_is_dir && !ext2_empty_dir(new_inode))
goto out_dir;
new_de = ext2_find_entry(new_dir, &new_dentry->d_name,
@@ -368,14 +369,14 @@ static int ext2_rename (struct mnt_idmap * idmap,
if (err)
goto out_dir;
inode_set_ctime_current(new_inode);
if (dir_de)
if (old_is_dir)
drop_nlink(new_inode);
inode_dec_link_count(new_inode);
} else {
err = ext2_add_link(new_dentry, old_inode);
if (err)
goto out_dir;
if (dir_de)
if (old_is_dir)
inode_inc_link_count(new_dir);
}
@@ -387,7 +388,7 @@ static int ext2_rename (struct mnt_idmap * idmap,
mark_inode_dirty(old_inode);
err = ext2_delete_entry(old_de, old_folio);
if (!err && dir_de) {
if (!err && old_is_dir) {
if (old_dir != new_dir)
err = ext2_set_link(old_inode, dir_de, dir_folio,
new_dir, false);