From 02a336a831f02a18047bacbd49018a237af8a172 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 26 Oct 2026 15:00:42 +0100 Subject: [PATCH] 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 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) --- fs/libfs.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/fs/libfs.c b/fs/libfs.c index 8e2cc627bc7f..96a6e9b1535f 100644 --- a/fs/libfs.c +++ b/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); }