| From fe6a1f8e90e0d6bbf9b224cfe2d47430d124cf02 Mon Sep 17 00:00:00 2001 |
| From: Trond Myklebust <trondmy@gmail.com> |
| Date: Wed, 5 Feb 2020 09:01:53 -0500 |
| Subject: [PATCH] NFSv4: Fix races between open and dentry revalidation |
| |
| commit cf5b4059ba7197d6cef9c0e024979d178ed8c8ec upstream. |
| |
| 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: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c |
| index 336643b82188..49544e706c18 100644 |
| --- a/fs/nfs/nfs4file.c |
| +++ b/fs/nfs/nfs4file.c |
| @@ -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; |
| diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c |
| index e4259c15f158..690699aab2fb 100644 |
| --- a/fs/nfs/nfs4proc.c |
| +++ b/fs/nfs/nfs4proc.c |
| @@ -2929,10 +2929,13 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, |
| struct nfs_server *server = sp->so_server; |
| struct dentry *dentry; |
| struct nfs4_state *state; |
| + 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) |
| @@ -2960,8 +2963,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 */ |
| -- |
| 2.7.4 |
| |