Merge tag 'pull-rename' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 Jan 2024 04:00:22 +0000 (20:00 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 Jan 2024 04:00:22 +0000 (20:00 -0800)
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

1  2 
Documentation/filesystems/locking.rst
Documentation/filesystems/porting.rst
fs/ecryptfs/inode.c
fs/inode.c
fs/internal.h
fs/namei.c
fs/nfsd/vfs.c
fs/overlayfs/copy_up.c
fs/overlayfs/super.c
fs/overlayfs/util.c
fs/smb/server/vfs.c

Simple merge
index ced3a6761329340d29e3ce05ce8e4f47b253d986,33cd56e2ca1a50622ee8c967d5d880a979f09930..c549fb2fc3ba7adb85edbdb573f2b801215372b1
@@@ -1064,12 -1064,27 +1064,39 @@@ generic_encode_ino32_fh() explicitly
  
  ---
  
+ **mandatory**
+ If ->rename() update of .. on cross-directory move needs an exclusion with
+ directory modifications, do *not* lock the subdirectory in question in your
+ ->rename() - it's done by the caller now [that item should've been added in
+ 28eceeda130f "fs: Lock moved directories"].
+ ---
+ **mandatory**
+ On same-directory ->rename() the (tautological) update of .. is not protected
+ by any locks; just don't do it if the old parent is the same as the new one.
+ We really can't lock two subdirectories in same-directory rename - not without
+ deadlocks.
+ ---
+ **mandatory**
+ lock_rename() and lock_rename_child() may fail in cross-directory case, if
+ their arguments do not have a common ancestor.  In that case ERR_PTR(-EXDEV)
+ is returned, with no locks taken.  In-tree users updated; out-of-tree ones
+ would need to do so.
++
++---
++
 +**recommended**
 +
 +Block device freezing and thawing have been moved to holder operations.
 +
 +Before this change, get_active_super() would only be able to find the
 +superblock of the main block device, i.e., the one stored in sb->s_bdev. Block
 +device freezing now works for any block device owned by a given superblock, not
 +just the main block device. The get_active_super() helper and bd_fsfreeze_sb
 +pointer are gone.
Simple merge
diff --cc fs/inode.c
Simple merge
diff --cc fs/internal.h
Simple merge
diff --cc fs/namei.c
Simple merge
diff --cc fs/nfsd/vfs.c
Simple merge
index 696478f09cc1b459cbe26502ae4db81ec91300b3,e44dc5f661610d760f69bd73e71685b81af86e22..b8e25ca51016d9df648ca58495baa9db553330ec
@@@ -779,13 -757,14 +779,15 @@@ static int ovl_copy_up_workdir(struct o
         * lock ordering with sb_writers, which shouldn't be held when calling
         * ovl_copy_up_data(), so lock workdir and destdir and make sure that
         * temp wasn't moved before copy up completion or cleanup.
 -       * If temp was moved, abort without the cleanup.
         */
        ovl_start_write(c->dentry);
-       if (lock_rename(c->workdir, c->destdir) != NULL ||
-           temp->d_parent != c->workdir) {
+       trap = lock_rename(c->workdir, c->destdir);
+       if (trap || temp->d_parent != c->workdir) {
 +              /* temp or workdir moved underneath us? abort without cleanup */
 +              dput(temp);
                err = -EIO;
+               if (IS_ERR(trap))
+                       goto out;
                goto unlock;
        } else if (err) {
                goto cleanup;
Simple merge
Simple merge
Simple merge