mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
libfs: hold one mount reference for all pins
simple_pin_fs() takes a reference on the internal mount for every pin and simple_release_fs() drops it again. So every debugfs, tracefs, securityfs, configfs, apparmorfs, drm and vfio file that is created and removed costs a mntget() and a mntput() on that mount. The mount comes from vfs_kern_mount() and not from kern_mount(), so it never gets MNT_NS_INTERNAL and mntput_no_expire() can't take the fast path for it. Each of those mntput()s ends up in mntput_no_expire_slowpath(), takes mount_lock and sums the per-cpu counters in mnt_get_count() to find out whether it dropped the last reference. It never did for anything but the last pin, that's what the pin count is for. The reference per pin never bought anything. The pin count under pin_fs_lock is what keeps the mount alive, nothing looks at the mount's refcount to find out how many pins there are and the mount is only torn down once the last pin is gone. Keep the reference vfs_kern_mount() returned as the one reference the pins hold. Further pins only bump the count and the last simple_release_fs() drops the reference. The refcount of a pinned mount now changes when it is first pinned and when the last pin goes away. Everything in between is a spinlock and a counter. Reported-by: kernel test robot <yi1.lai@intel.com> Closes: https://lore.kernel.org/oe-lkp/202610130959.d3ca4cfa-lkp@intel.com Link: https://patch.msgid.link/20261026-work-libfs-pin_fs-v1-1-99ef52ee10a3@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
parent
eeecea75ec
commit
02a336a831
12
fs/libfs.c
12
fs/libfs.c
|
|
@ -1103,10 +1103,11 @@ int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *c
|
|||
if (IS_ERR(mnt))
|
||||
return PTR_ERR(mnt);
|
||||
spin_lock(&pin_fs_lock);
|
||||
if (!*mount)
|
||||
if (!*mount) {
|
||||
*mount = mnt;
|
||||
mnt = NULL;
|
||||
}
|
||||
}
|
||||
mntget(*mount);
|
||||
++*count;
|
||||
spin_unlock(&pin_fs_lock);
|
||||
mntput(mnt);
|
||||
|
|
@ -1116,11 +1117,12 @@ EXPORT_SYMBOL(simple_pin_fs);
|
|||
|
||||
void simple_release_fs(struct vfsmount **mount, int *count)
|
||||
{
|
||||
struct vfsmount *mnt;
|
||||
struct vfsmount *mnt = NULL;
|
||||
spin_lock(&pin_fs_lock);
|
||||
mnt = *mount;
|
||||
if (!--*count)
|
||||
if (!--*count) {
|
||||
mnt = *mount;
|
||||
*mount = NULL;
|
||||
}
|
||||
spin_unlock(&pin_fs_lock);
|
||||
mntput(mnt);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user