[ Upstream commit 8fd1ab747d2b1ec7ec663ad0b41a32eaa35117a8 ]

If the server that does not implement NFSv4.1 persistent session
semantics reboots while we are performing an exclusive create,
then the return value of NFS4ERR_DELAY when we replay the open
during the grace period causes us to lose the verifier.
When the grace period expires, and we present a new verifier,
the server will then correctly reply NFS4ERR_EXIST.

This commit ensures that we always present the same verifier when
replaying the OPEN.

Reported-by: Tigran Mkrtchyan <tigran.mkrtch...@desy.de>
Signed-off-by: Trond Myklebust <trond.mykleb...@primarydata.com>
Signed-off-by: Anna Schumaker <anna.schuma...@netapp.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 fs/nfs/nfs4proc.c | 41 ++++++++++++++++++++++++++---------------
 1 file changed, 26 insertions(+), 15 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 41c8ddbc80dc..d1816ee0c11b 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -997,6 +997,12 @@ struct nfs4_opendata {
        int cancelled;
 };
 
+struct nfs4_open_createattrs {
+       struct nfs4_label *label;
+       struct iattr *sattr;
+       const __u32 verf[2];
+};
+
 static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
                int err, struct nfs4_exception *exception)
 {
@@ -1066,8 +1072,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata 
*p)
 
 static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
                struct nfs4_state_owner *sp, fmode_t fmode, int flags,
-               const struct iattr *attrs,
-               struct nfs4_label *label,
+               const struct nfs4_open_createattrs *c,
                enum open_claim_type4 claim,
                gfp_t gfp_mask)
 {
@@ -1075,6 +1080,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct 
dentry *dentry,
        struct inode *dir = d_inode(parent);
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
+       struct nfs4_label *label = (c != NULL) ? c->label : NULL;
        struct nfs4_opendata *p;
 
        p = kzalloc(sizeof(*p), gfp_mask);
@@ -1131,15 +1137,11 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct 
dentry *dentry,
        case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
                p->o_arg.fh = NFS_FH(d_inode(dentry));
        }
-       if (attrs != NULL && attrs->ia_valid != 0) {
-               __u32 verf[2];
-
+       if (c != NULL && c->sattr != NULL && c->sattr->ia_valid != 0) {
                p->o_arg.u.attrs = &p->attrs;
-               memcpy(&p->attrs, attrs, sizeof(p->attrs));
+               memcpy(&p->attrs, c->sattr, sizeof(p->attrs));
 
-               verf[0] = jiffies;
-               verf[1] = current->pid;
-               memcpy(p->o_arg.u.verifier.data, verf,
+               memcpy(p->o_arg.u.verifier.data, c->verf,
                                sizeof(p->o_arg.u.verifier.data));
        }
        p->c_arg.fh = &p->o_res.fh;
@@ -1653,7 +1655,7 @@ static struct nfs4_opendata 
*nfs4_open_recoverdata_alloc(struct nfs_open_context
        struct nfs4_opendata *opendata;
 
        opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0,
-                       NULL, NULL, claim, GFP_NOFS);
+                       NULL, claim, GFP_NOFS);
        if (opendata == NULL)
                return ERR_PTR(-ENOMEM);
        opendata->state = state;
@@ -2488,8 +2490,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata 
*opendata,
 static int _nfs4_do_open(struct inode *dir,
                        struct nfs_open_context *ctx,
                        int flags,
-                       struct iattr *sattr,
-                       struct nfs4_label *label,
+                       const struct nfs4_open_createattrs *c,
                        int *opened)
 {
        struct nfs4_state_owner  *sp;
@@ -2501,6 +2502,8 @@ static int _nfs4_do_open(struct inode *dir,
        struct nfs4_threshold **ctx_th = &ctx->mdsthreshold;
        fmode_t fmode = ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC);
        enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL;
+       struct iattr *sattr = c->sattr;
+       struct nfs4_label *label = c->label;
        struct nfs4_label *olabel = NULL;
        int status;
 
@@ -2519,8 +2522,8 @@ static int _nfs4_do_open(struct inode *dir,
        status = -ENOMEM;
        if (d_really_is_positive(dentry))
                claim = NFS4_OPEN_CLAIM_FH;
-       opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr,
-                       label, claim, GFP_KERNEL);
+       opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags,
+                       c, claim, GFP_KERNEL);
        if (opendata == NULL)
                goto err_put_state_owner;
 
@@ -2596,10 +2599,18 @@ static struct nfs4_state *nfs4_do_open(struct inode 
*dir,
        struct nfs_server *server = NFS_SERVER(dir);
        struct nfs4_exception exception = { };
        struct nfs4_state *res;
+       struct nfs4_open_createattrs c = {
+               .label = label,
+               .sattr = sattr,
+               .verf = {
+                       [0] = (__u32)jiffies,
+                       [1] = (__u32)current->pid,
+               },
+       };
        int status;
 
        do {
-               status = _nfs4_do_open(dir, ctx, flags, sattr, label, opened);
+               status = _nfs4_do_open(dir, ctx, flags, &c, opened);
                res = ctx->state;
                trace_nfs4_open_file(ctx, flags, status);
                if (status == 0)
-- 
2.20.1



Reply via email to