]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
NFS: Initialise verifiers for visible dentries in _nfs4_open_and_get_state
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 19 Nov 2025 13:43:21 +0000 (08:43 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 18 Dec 2025 12:55:17 +0000 (13:55 +0100)
[ Upstream commit 0f900f11002ff52391fc2aa4a75e59f26ed1c242 ]

Ensure that the verifiers are initialised before calling
d_splice_alias() in _nfs4_open_and_get_state().

Reported-by: Michael Stoler <michael.stoler@vastdata.com>
Fixes: cf5b4059ba71 ("NFSv4: Fix races between open and dentry revalidation")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/nfs/nfs4proc.c

index 7fe71aaa18666c9eebc212a78b93395a41a9c81f..172ff213b50b6553cf49f0288c07b3f80817f889 100644 (file)
@@ -3148,18 +3148,6 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
        if (opendata->o_res.rflags & NFS4_OPEN_RESULT_PRESERVE_UNLINKED)
                set_bit(NFS_INO_PRESERVE_UNLINKED, &NFS_I(state->inode)->flags);
 
-       dentry = opendata->dentry;
-       if (d_really_is_negative(dentry)) {
-               struct dentry *alias;
-               d_drop(dentry);
-               alias = d_splice_alias(igrab(state->inode), dentry);
-               /* d_splice_alias() can't fail here - it's a non-directory */
-               if (alias) {
-                       dput(ctx->dentry);
-                       ctx->dentry = dentry = alias;
-               }
-       }
-
        switch(opendata->o_arg.claim) {
        default:
                break;
@@ -3170,7 +3158,20 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
                        break;
                if (opendata->o_res.delegation.type != 0)
                        dir_verifier = nfs_save_change_attribute(dir);
-               nfs_set_verifier(dentry, dir_verifier);
+       }
+
+       dentry = opendata->dentry;
+       nfs_set_verifier(dentry, dir_verifier);
+       if (d_really_is_negative(dentry)) {
+               struct dentry *alias;
+               d_drop(dentry);
+               alias = d_splice_alias(igrab(state->inode), dentry);
+               /* d_splice_alias() can't fail here - it's a non-directory */
+               if (alias) {
+                       dput(ctx->dentry);
+                       nfs_set_verifier(alias, dir_verifier);
+                       ctx->dentry = dentry = alias;
+               }
        }
 
        /* Parse layoutget results before we check for access */