]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
nfs: get rid of fake root dentries
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 15 Apr 2026 23:29:53 +0000 (19:29 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 5 Jun 2026 04:34:56 +0000 (00:34 -0400)
... just grab the reference to the (real) root we are about to return
for the first mount of this superblock and be done with that.

Once upon a time dentry tree eviction at fs shutdown used to break
if ->s_root had been spliced on top of something; that hadn't been
the case for years now, and these fake root dentries violate a bunch
of invariants.  Let's get rid of them...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/dcache.c
fs/nfs/getroot.c

index 257eefc46f5ef61a69485080a27344876fa53f17..e7487c92c21a64c019de7b53ec600e5b38b13b18 100644 (file)
@@ -455,14 +455,10 @@ static void dentry_unlink_inode(struct dentry * dentry)
 
        raw_write_seqcount_begin(&dentry->d_seq);
        __d_clear_type_and_inode(dentry);
-       hlist_del_init(&dentry->d_alias);
+       __hlist_del(&dentry->d_alias);
        /*
         * dentry becomes negative, so the space occupied by ->d_alias
-        * belongs to ->waiters now; we could use __hlist_del() instead
-        * of hlist_del_init(), if not for the stunt pulled by nfs
-        * dummy root dentries - positive dentry *not* included into
-        * the alias list of its inode.  Open-coding hlist_del_init()
-        * and removing zeroing would be too clumsy...
+        * belongs to ->waiters now.
         */
        dentry->waiters = NULL;
        raw_write_seqcount_end(&dentry->d_seq);
index eef0736beb67fbc8ef4159c6e123f5baae0deed3..ff7424bc4bece808f1559f5c2bdc465103e282d4 100644 (file)
 
 #define NFSDBG_FACILITY                NFSDBG_CLIENT
 
-/*
- * Set the superblock root dentry.
- * Note that this function frees the inode in case of error.
- */
-static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *inode)
-{
-       /* The mntroot acts as the dummy root dentry for this superblock */
-       if (sb->s_root == NULL) {
-               sb->s_root = d_make_root(inode);
-               if (sb->s_root == NULL)
-                       return -ENOMEM;
-               ihold(inode);
-               /*
-                * Ensure that this dentry is invisible to d_find_alias().
-                * Otherwise, it may be spliced into the tree by
-                * d_splice_alias if a parent directory from the same
-                * filesystem gets mounted at a later time.
-                * This again causes shrink_dcache_for_umount_subtree() to
-                * Oops, since the test for IS_ROOT() will fail.
-                */
-               spin_lock(&d_inode(sb->s_root)->i_lock);
-               spin_lock(&sb->s_root->d_lock);
-               hlist_del_init(&sb->s_root->d_alias);
-               spin_unlock(&sb->s_root->d_lock);
-               spin_unlock(&d_inode(sb->s_root)->i_lock);
-       }
-       return 0;
-}
-
 /*
  * get a root dentry from the root filehandle
  */
@@ -99,10 +70,6 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
                goto out_fattr;
        }
 
-       error = nfs_superblock_set_dummy_root(s, inode);
-       if (error != 0)
-               goto out_fattr;
-
        /* root dentries normally start off anonymous and get spliced in later
         * if the dentry tree reaches them; however if the dentry already
         * exists, we'll pick it up at this point and use it as the root
@@ -123,6 +90,8 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
                name = NULL;
        }
        spin_unlock(&root->d_lock);
+       if (!s->s_root)
+               s->s_root = dget(root);
        fc->root = root;
        if (server->caps & NFS_CAP_SECURITY_LABEL)
                kflags |= SECURITY_LSM_NATIVE_LABELS;