]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Merge tag 'pull-mount' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Oct 2025 17:19:44 +0000 (10:19 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Oct 2025 17:19:44 +0000 (10:19 -0700)
Pull vfs mount updates from Al Viro:
 "Several piles this cycle, this mount-related one being the largest and
  trickiest:

   - saner handling of guards in fs/namespace.c, getting rid of
     needlessly strong locking in some of the users

   - lock_mount() calling conventions change - have it set the
     environment for attaching to given location, storing the results in
     caller-supplied object, without altering the passed struct path.

     Make unlock_mount() called as __cleanup for those objects. It's not
     exactly guard(), but similar to it

   - MNT_WRITE_HOLD done right.

     mnt_hold_writers() does *not* mess with ->mnt_flags anymore, so
     insertion of a new mount into ->s_mounts of underlying superblock
     does not, in itself, expose ->mnt_flags of that mount to concurrent
     modifications

   - getting rid of pathological cases when umount() spends quadratic
     time removing the victims from propagation graph - part of that had
     been dealt with last cycle, this should finish it

   - a bunch of stuff constified

   - assorted cleanups

* tag 'pull-mount' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (64 commits)
  constify {__,}mnt_is_readonly()
  WRITE_HOLD machinery: no need for to bump mount_lock seqcount
  struct mount: relocate MNT_WRITE_HOLD bit
  preparations to taking MNT_WRITE_HOLD out of ->mnt_flags
  setup_mnt(): primitive for connecting a mount to filesystem
  simplify the callers of mnt_unhold_writers()
  copy_mnt_ns(): use guards
  copy_mnt_ns(): use the regular mechanism for freeing empty mnt_ns on failure
  open_detached_copy(): separate creation of namespace into helper
  open_detached_copy(): don't bother with mount_lock_hash()
  path_has_submounts(): use guard(mount_locked_reader)
  fs/namespace.c: sanitize descriptions for {__,}lookup_mnt()
  ecryptfs: get rid of pointless mount references in ecryptfs dentries
  umount_tree(): take all victims out of propagation graph at once
  do_mount(): use __free(path_put)
  do_move_mount_old(): use __free(path_put)
  constify can_move_mount_beneath() arguments
  path_umount(): constify struct path argument
  may_copy_tree(), __do_loopback(): constify struct path argument
  path_mount(): constify struct path argument
  ...

1  2 
fs/dcache.c
fs/ecryptfs/inode.c
fs/internal.h
fs/mount.h
fs/namespace.c
fs/super.c
include/linux/fs.h
kernel/audit_tree.c

diff --cc fs/dcache.c
Simple merge
Simple merge
diff --cc fs/internal.h
Simple merge
diff --cc fs/mount.h
Simple merge
diff --cc fs/namespace.c
index dc01b14c58cd6be25760f3e97d8552dedafbea3b,4b74fabced434d20c5bc418c51a4dd700b94f605..d39499ab5cb5bbe01d3acbbeb4ec05c88a0f7756
@@@ -90,7 -80,16 +90,15 @@@ static DECLARE_RWSEM(namespace_sem)
  static HLIST_HEAD(unmounted); /* protected by namespace_sem */
  static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */
  static struct mnt_namespace *emptied_ns; /* protected by namespace_sem */
 -static DEFINE_SEQLOCK(mnt_ns_tree_lock);
  
+ static inline void namespace_lock(void);
+ static void namespace_unlock(void);
+ DEFINE_LOCK_GUARD_0(namespace_excl, namespace_lock(), namespace_unlock())
+ DEFINE_LOCK_GUARD_0(namespace_shared, down_read(&namespace_sem),
+                                     up_read(&namespace_sem))
+ DEFINE_FREE(mntput, struct vfsmount *, if (!IS_ERR(_T)) mntput(_T))
  #ifdef CONFIG_FSNOTIFY
  LIST_HEAD(notify_list); /* protected by namespace_sem */
  #endif
@@@ -3229,7 -3305,7 +3245,7 @@@ static int do_reconfigure_mnt(const str
   * If you've mounted a non-root directory somewhere and want to do remount
   * on it - tough luck.
   */
- static int do_remount(struct path *path, int sb_flags,
 -static int do_remount(const struct path *path, int ms_flags, int sb_flags,
++static int do_remount(const struct path *path, int sb_flags,
                      int mnt_flags, void *data)
  {
        int err;
@@@ -3658,30 -3705,23 +3645,25 @@@ static bool mount_too_revealing(const s
   * Create a new mount using a superblock configuration and request it
   * be added to the namespace tree.
   */
- static int do_new_mount_fc(struct fs_context *fc, struct path *mountpoint,
+ static int do_new_mount_fc(struct fs_context *fc, const struct path *mountpoint,
                           unsigned int mnt_flags)
  {
-       struct vfsmount *mnt;
-       struct pinned_mountpoint mp = {};
-       struct super_block *sb = fc->root->d_sb;
+       struct super_block *sb;
+       struct vfsmount *mnt __free(mntput) = fc_mount(fc);
        int error;
  
-       error = security_sb_kern_mount(sb);
-       if (!error && mount_too_revealing(sb, &mnt_flags)) {
-               errorfcp(fc, "VFS", "Mount too revealing");
-               error = -EPERM;
-       }
+       if (IS_ERR(mnt))
+               return PTR_ERR(mnt);
  
-       if (unlikely(error)) {
-               fc_drop_locked(fc);
+       sb = fc->root->d_sb;
+       error = security_sb_kern_mount(sb);
+       if (unlikely(error))
                return error;
-       }
-       up_write(&sb->s_umount);
  
-       mnt = vfs_create_mount(fc);
-       if (IS_ERR(mnt))
-               return PTR_ERR(mnt);
 -      if (unlikely(mount_too_revealing(sb, &mnt_flags)))
++      if (unlikely(mount_too_revealing(sb, &mnt_flags))) {
++              errorfcp(fc, "VFS", "Mount too revealing");
+               return -EPERM;
++      }
  
        mnt_warn_timestamp_expiry(mountpoint, mnt);
  
@@@ -4205,14 -4243,7 +4174,7 @@@ struct mnt_namespace *copy_mnt_ns(u64 f
                while (p->mnt.mnt_root != q->mnt.mnt_root)
                        p = next_mnt(skip_mnt_tree(p), old);
        }
-       namespace_unlock();
-       if (rootmnt)
-               mntput(rootmnt);
-       if (pwdmnt)
-               mntput(pwdmnt);
 -      mnt_ns_tree_add(new_ns);
 +      ns_tree_add_raw(new_ns);
        return new_ns;
  }
  
@@@ -5897,22 -5902,12 +5831,23 @@@ retry
        return ret;
  }
  
 -static ssize_t do_listmount(struct mnt_namespace *ns, u64 mnt_parent_id,
 -                          u64 last_mnt_id, u64 *mnt_ids, size_t nr_mnt_ids,
 -                          bool reverse)
 +struct klistmount {
 +      u64 last_mnt_id;
 +      u64 mnt_parent_id;
 +      u64 *kmnt_ids;
 +      u32 nr_mnt_ids;
 +      struct mnt_namespace *ns;
 +      struct path root;
 +};
 +
+ /* locks: namespace_shared */
 +static ssize_t do_listmount(struct klistmount *kls, bool reverse)
  {
 -      struct path root __free(path_put) = {};
 +      struct mnt_namespace *ns = kls->ns;
 +      u64 mnt_parent_id = kls->mnt_parent_id;
 +      u64 last_mnt_id = kls->last_mnt_id;
 +      u64 *mnt_ids = kls->kmnt_ids;
 +      size_t nr_mnt_ids = kls->nr_mnt_ids;
        struct path orig;
        struct mount *r, *first;
        ssize_t ret;
@@@ -6040,8 -6014,9 +5975,8 @@@ SYSCALL_DEFINE4(listmount, const struc
         * We only need to guard against mount topology changes as
         * listmount() doesn't care about any mount properties.
         */
-       scoped_guard(rwsem_read, &namespace_sem)
+       scoped_guard(namespace_shared)
 -              ret = do_listmount(ns, kreq.mnt_id, last_mnt_id, kmnt_ids,
 -                                 nr_mnt_ids, (flags & LISTMOUNT_REVERSE));
 +              ret = do_listmount(&kls, (flags & LISTMOUNT_REVERSE));
        if (ret <= 0)
                return ret;
  
@@@ -6125,14 -6095,12 +6060,12 @@@ void __init mnt_init(void
  
  void put_mnt_ns(struct mnt_namespace *ns)
  {
 -      if (!refcount_dec_and_test(&ns->ns.count))
 +      if (!ns_ref_put(ns))
                return;
-       namespace_lock();
+       guard(namespace_excl)();
        emptied_ns = ns;
-       lock_mount_hash();
+       guard(mount_writer)();
        umount_tree(ns->root, 0);
-       unlock_mount_hash();
-       namespace_unlock();
  }
  
  struct vfsmount *kern_mount(struct file_system_type *type)
diff --cc fs/super.c
Simple merge
Simple merge
Simple merge