Skip to content

Commit

Permalink
NFSv4: Fix open create exclusive when the server reboots
Browse files Browse the repository at this point in the history
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.mkrtchyan@desy.de>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
  • Loading branch information
Trond Myklebust authored and Anna Schumaker committed Nov 17, 2017
1 parent ad9e02d commit 8fd1ab7
Showing 1 changed file with 26 additions and 15 deletions.
41 changes: 26 additions & 15 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,12 @@ struct nfs4_opendata {
int rpc_status;
};

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)
{
Expand Down Expand Up @@ -1157,15 +1163,15 @@ 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)
{
struct dentry *parent = dget_parent(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);
Expand Down Expand Up @@ -1231,15 +1237,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;
Expand Down Expand Up @@ -1892,7 +1894,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;
Expand Down Expand Up @@ -2823,8 +2825,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;
Expand All @@ -2836,6 +2837,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;

Expand All @@ -2854,8 +2857,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;

Expand Down Expand Up @@ -2936,10 +2939,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)
Expand Down

0 comments on commit 8fd1ab7

Please sign in to comment.