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:
parent
043bc81efb
commit
b73ec10a45
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user