]> git.ipfire.org Git - thirdparty/linux.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)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Wed, 19 Nov 2025 16:46:50 +0000 (11:46 -0500)
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>
fs/nfs/nfs4proc.c

index 93c6ce04332b89ac1daec5c56c305c164dc6028c..6f4e14fb7b9b8c9dc533c258fc90ec58247547cd 100644 (file)
@@ -3174,18 +3174,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;
@@ -3196,7 +3184,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 */