NFSv4: Fix races between open and dentry revalidation
authorTrond Myklebust <trondmy@gmail.com>
Wed, 5 Feb 2020 14:01:53 +0000 (09:01 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Mar 2020 15:43:37 +0000 (16:43 +0100)
[ Upstream commit cf5b4059ba7197d6cef9c0e024979d178ed8c8ec ]

We want to make sure that we revalidate the dentry if and only if
we've done an OPEN by filename.
In order to avoid races with remote changes to the directory on the
server, we want to save the verifier before calling OPEN. The exception
is if the server returned a delegation with our OPEN, as we then
know that the filename can't have changed on the server.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Reviewed-by: Benjamin Coddington <bcodding@gmail.com>
Tested-by: Benjamin Coddington <bcodding@gmail.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/nfs/nfs4file.c
fs/nfs/nfs4proc.c

index 339663d04bf83b28f3f4426eba8419d4e750146f..54f1c1f626fc58cc465fd3fee8d4a836f55769a1 100644 (file)
@@ -86,7 +86,6 @@ nfs4_file_open(struct inode *inode, struct file *filp)
        if (inode != d_inode(dentry))
                goto out_drop;
 
-       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        nfs_file_set_open_context(filp, ctx);
        nfs_fscache_open_file(inode, filp);
        err = 0;
index f808fb34b1101d77be9e2e7146d1acc05bc234a0..6b29703d2fe1e2767456e431aff29492dfb8a9ca 100644 (file)
@@ -2962,10 +2962,13 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
        struct dentry *dentry;
        struct nfs4_state *state;
        fmode_t acc_mode = _nfs4_ctx_to_accessmode(ctx);
+       struct inode *dir = d_inode(opendata->dir);
+       unsigned long dir_verifier;
        unsigned int seq;
        int ret;
 
        seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
+       dir_verifier = nfs_save_change_attribute(dir);
 
        ret = _nfs4_proc_open(opendata, ctx);
        if (ret != 0)
@@ -2993,8 +2996,19 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
                        dput(ctx->dentry);
                        ctx->dentry = dentry = alias;
                }
-               nfs_set_verifier(dentry,
-                               nfs_save_change_attribute(d_inode(opendata->dir)));
+       }
+
+       switch(opendata->o_arg.claim) {
+       default:
+               break;
+       case NFS4_OPEN_CLAIM_NULL:
+       case NFS4_OPEN_CLAIM_DELEGATE_CUR:
+       case NFS4_OPEN_CLAIM_DELEGATE_PREV:
+               if (!opendata->rpc_done)
+                       break;
+               if (opendata->o_res.delegation_type != 0)
+                       dir_verifier = nfs_save_change_attribute(dir);
+               nfs_set_verifier(dentry, dir_verifier);
        }
 
        /* Parse layoutget results before we check for access */