From: Al Viro Date: Wed, 15 Apr 2026 23:29:53 +0000 (-0400) Subject: nfs: get rid of fake root dentries X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=144bef84e1cfadfe100c6728593ea9838853f347;p=thirdparty%2Flinux.git nfs: get rid of fake root dentries ... 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 --- diff --git a/fs/dcache.c b/fs/dcache.c index 257eefc46f5e..e7487c92c21a 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -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); diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index eef0736beb67..ff7424bc4bec 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -32,35 +32,6 @@ #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;