From 5179241521401ef364294128bb43cdbce7252457 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 17 Sep 2026 13:20:25 +0200 Subject: [PATCH] fs: don't create the private nullfs mount under namespace_sem init_mount_tree() mounts the mutable rootfs on top of nullfs via LOCK_MOUNT_EXACT(). That declares a pinned mountpoint with a cleanup attribute in the scope of the whole function so the nullfs root inode lock and namespace_sem are only dropped when init_mount_tree() returns. This became a problem when the private nullfs instance for kthreads was added. kern_mount() allocates a new superblock and alloc_super() takes the new s_umount with SINGLE_DEPTH_NESTING and then shrinker_mutex via shrinker_alloc(). Doing that with namespace_sem held teaches lockdep the dependency namespace_sem -> s_umount/1 -> shrinker_mutex With CONFIG_SHRINKER_DEBUG shrinker_debugfs_rename() takes the debugfs directory inode lock under shrinker_mutex every time a block device is mounted and lock_mount_exact() takes namespace_sem under the inode lock of the mountpoint for every mount. So mounting anything on debugfs, e.g. the tracefs automount on /sys/kernel/debug/tracing, closes the cycle: WARNING: possible circular locking dependency detected 7.3.0-rc3+ #17 Not tainted ------------------------------------------------------ rasdaemon/4449 is trying to acquire lock: (namespace_sem){++++}-{4:4}, at: lock_mount_exact+0x4c/0x308 but task is already holding lock: (&sb->s_type->i_mutex_key#17){++++}-{4:4}, at: lock_mount_exact+0x3c/0x308 which lock already depends on the new lock. ... Chain exists of: namespace_sem --> shrinker_mutex --> &sb->s_type->i_mutex_key#17 This can't actually deadlock. init_mount_tree() runs single-threaded during early boot before any other task exists and nothing allocates a superblock under namespace_sem after that. But lockdep can't know that and disables itself for the rest of the boot. Move mounting the rootfs on top of nullfs into a helper so the locks are dropped when it returns. Fixes: 32750c77e811 ("fs: start all kthreads in nullfs") Reported-by: Zenghui Yu Closes: https://lore.kernel.org/15174353-3f4a-a1ca-5bd1-ea2a4c77828e@huawei.com Link: https://patch.msgid.link/20260917-atemtechnik-bleichen-befassen-9a57db01baf0@brauner Signed-off-by: Christian Brauner (Amutable) --- fs/namespace.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index ae5dc64f8b45..5e41021eaa63 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -6184,6 +6184,21 @@ struct mnt_namespace init_mnt_ns = { .poll = __WAIT_QUEUE_HEAD_INITIALIZER(init_mnt_ns.poll), }; +static void __init mount_rootfs_on_nullfs(struct vfsmount *mnt, + struct vfsmount *nullfs_mnt) +{ + struct path root = { + .mnt = nullfs_mnt, + .dentry = nullfs_mnt->mnt_root, + }; + + LOCK_MOUNT_EXACT(mp, &root); + if (unlikely(IS_ERR(mp.parent))) + panic("VFS: Failed to mount rootfs on nullfs"); + scoped_guard(mount_writer) + attach_mnt(real_mount(mnt), mp.parent, mp.mp); +} + static void __init init_mount_tree(void) { struct vfsmount *mnt, *nullfs_mnt; @@ -6215,15 +6230,7 @@ static void __init init_mount_tree(void) mnt_root = real_mount(nullfs_mnt); init_mnt_ns.root = mnt_root; - /* Mount mutable rootfs on top of nullfs. */ - root.mnt = nullfs_mnt; - root.dentry = nullfs_mnt->mnt_root; - - LOCK_MOUNT_EXACT(mp, &root); - if (unlikely(IS_ERR(mp.parent))) - panic("VFS: Failed to mount rootfs on nullfs"); - scoped_guard(mount_writer) - attach_mnt(real_mount(mnt), mp.parent, mp.mp); + mount_rootfs_on_nullfs(mnt, nullfs_mnt); pr_info("VFS: Finished mounting rootfs on nullfs\n");