Commit 2d9b39de authored by Trond Myklebust's avatar Trond Myklebust Committed by Greg Kroah-Hartman

NFSv4: Fix open create exclusive when the server reboots

[ Upstream commit 8fd1ab74 ]

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: default avatarTigran Mkrtchyan <tigran.mkrtchyan@desy.de>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent f448eb01
...@@ -1121,6 +1121,12 @@ struct nfs4_opendata { ...@@ -1121,6 +1121,12 @@ struct nfs4_opendata {
int cancelled; 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, static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
int err, struct nfs4_exception *exception) int err, struct nfs4_exception *exception)
{ {
...@@ -1190,8 +1196,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) ...@@ -1190,8 +1196,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
struct nfs4_state_owner *sp, fmode_t fmode, int flags, struct nfs4_state_owner *sp, fmode_t fmode, int flags,
const struct iattr *attrs, const struct nfs4_open_createattrs *c,
struct nfs4_label *label,
enum open_claim_type4 claim, enum open_claim_type4 claim,
gfp_t gfp_mask) gfp_t gfp_mask)
{ {
...@@ -1199,6 +1204,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, ...@@ -1199,6 +1204,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
struct inode *dir = d_inode(parent); struct inode *dir = d_inode(parent);
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t); struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
struct nfs4_label *label = (c != NULL) ? c->label : NULL;
struct nfs4_opendata *p; struct nfs4_opendata *p;
p = kzalloc(sizeof(*p), gfp_mask); p = kzalloc(sizeof(*p), gfp_mask);
...@@ -1255,15 +1261,11 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, ...@@ -1255,15 +1261,11 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
case NFS4_OPEN_CLAIM_DELEG_PREV_FH: case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
p->o_arg.fh = NFS_FH(d_inode(dentry)); p->o_arg.fh = NFS_FH(d_inode(dentry));
} }
if (attrs != NULL && attrs->ia_valid != 0) { if (c != NULL && c->sattr != NULL && c->sattr->ia_valid != 0) {
__u32 verf[2];
p->o_arg.u.attrs = &p->attrs; 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; memcpy(p->o_arg.u.verifier.data, c->verf,
verf[1] = current->pid;
memcpy(p->o_arg.u.verifier.data, verf,
sizeof(p->o_arg.u.verifier.data)); sizeof(p->o_arg.u.verifier.data));
} }
p->c_arg.fh = &p->o_res.fh; p->c_arg.fh = &p->o_res.fh;
...@@ -1814,7 +1816,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context ...@@ -1814,7 +1816,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
struct nfs4_opendata *opendata; struct nfs4_opendata *opendata;
opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0,
NULL, NULL, claim, GFP_NOFS); NULL, claim, GFP_NOFS);
if (opendata == NULL) if (opendata == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
opendata->state = state; opendata->state = state;
...@@ -2759,8 +2761,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, ...@@ -2759,8 +2761,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
static int _nfs4_do_open(struct inode *dir, static int _nfs4_do_open(struct inode *dir,
struct nfs_open_context *ctx, struct nfs_open_context *ctx,
int flags, int flags,
struct iattr *sattr, const struct nfs4_open_createattrs *c,
struct nfs4_label *label,
int *opened) int *opened)
{ {
struct nfs4_state_owner *sp; struct nfs4_state_owner *sp;
...@@ -2772,6 +2773,8 @@ static int _nfs4_do_open(struct inode *dir, ...@@ -2772,6 +2773,8 @@ static int _nfs4_do_open(struct inode *dir,
struct nfs4_threshold **ctx_th = &ctx->mdsthreshold; struct nfs4_threshold **ctx_th = &ctx->mdsthreshold;
fmode_t fmode = ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC); fmode_t fmode = ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC);
enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL; 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; struct nfs4_label *olabel = NULL;
int status; int status;
...@@ -2790,8 +2793,8 @@ static int _nfs4_do_open(struct inode *dir, ...@@ -2790,8 +2793,8 @@ static int _nfs4_do_open(struct inode *dir,
status = -ENOMEM; status = -ENOMEM;
if (d_really_is_positive(dentry)) if (d_really_is_positive(dentry))
claim = NFS4_OPEN_CLAIM_FH; claim = NFS4_OPEN_CLAIM_FH;
opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags,
label, claim, GFP_KERNEL); c, claim, GFP_KERNEL);
if (opendata == NULL) if (opendata == NULL)
goto err_put_state_owner; goto err_put_state_owner;
...@@ -2872,10 +2875,18 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, ...@@ -2872,10 +2875,18 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_exception exception = { }; struct nfs4_exception exception = { };
struct nfs4_state *res; struct nfs4_state *res;
struct nfs4_open_createattrs c = {
.label = label,
.sattr = sattr,
.verf = {
[0] = (__u32)jiffies,
[1] = (__u32)current->pid,
},
};
int status; int status;
do { do {
status = _nfs4_do_open(dir, ctx, flags, sattr, label, opened); status = _nfs4_do_open(dir, ctx, flags, &c, opened);
res = ctx->state; res = ctx->state;
trace_nfs4_open_file(ctx, flags, status); trace_nfs4_open_file(ctx, flags, status);
if (status == 0) if (status == 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment