2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

fs: add fastpath for dissolve_on_fput()

Instead of acquiring the namespace semaphore and the mount lock
everytime we close a file with FMODE_NEED_UNMOUNT set add a fastpath
that checks whether we need to at all. Most of the time the caller will
have attached the mount to the filesystem hierarchy and there's nothing
to do.

Link: https://lore.kernel.org/r/20250221-brauner-open_tree-v1-4-dbcfcb98c676@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Christian Brauner 2025-02-21 14:13:03 +01:00
parent 043bc81efb
commit b73ec10a45
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2

View File

@ -2246,22 +2246,57 @@ struct vfsmount *collect_mounts(const struct path *path)
static void free_mnt_ns(struct mnt_namespace *); static void free_mnt_ns(struct mnt_namespace *);
static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *, bool); static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *, bool);
static inline bool must_dissolve(struct mnt_namespace *mnt_ns)
{
/*
* This mount belonged to an anonymous mount namespace
* but was moved to a non-anonymous mount namespace and
* then unmounted.
*/
if (unlikely(!mnt_ns))
return false;
/*
* This mount belongs to a non-anonymous mount namespace
* and we know that such a mount can never transition to
* an anonymous mount namespace again.
*/
if (!is_anon_ns(mnt_ns)) {
/*
* A detached mount either belongs to an anonymous mount
* namespace or a non-anonymous mount namespace. It
* should never belong to something purely internal.
*/
VFS_WARN_ON_ONCE(mnt_ns == MNT_NS_INTERNAL);
return false;
}
return true;
}
void dissolve_on_fput(struct vfsmount *mnt) void dissolve_on_fput(struct vfsmount *mnt)
{ {
struct mnt_namespace *ns; struct mnt_namespace *ns;
namespace_lock(); struct mount *m = real_mount(mnt);
lock_mount_hash();
ns = real_mount(mnt)->mnt_ns; scoped_guard(rcu) {
if (ns) { if (!must_dissolve(READ_ONCE(m->mnt_ns)))
if (is_anon_ns(ns)) return;
umount_tree(real_mount(mnt), UMOUNT_CONNECTED);
else
ns = NULL;
} }
unlock_mount_hash();
namespace_unlock(); scoped_guard(rwsem_write, &namespace_sem) {
if (ns) ns = m->mnt_ns;
free_mnt_ns(ns); if (!must_dissolve(ns))
return;
lock_mount_hash();
umount_tree(m, UMOUNT_CONNECTED);
unlock_mount_hash();
}
/* Make sure we notice when we leak mounts. */
VFS_WARN_ON_ONCE(!mnt_ns_empty(ns));
free_mnt_ns(ns);
} }
void drop_collected_mounts(struct vfsmount *mnt) void drop_collected_mounts(struct vfsmount *mnt)