NFSv4: Fix open create exclusive when the server reboots
[ 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.mkrtchyan@desy.de> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
c5b430eeae
commit
b49ba75c3c
1 changed files with 26 additions and 15 deletions
|
@ -997,6 +997,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)
|
||||||
{
|
{
|
||||||
|
@ -1066,8 +1072,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)
|
||||||
{
|
{
|
||||||
|
@ -1075,6 +1080,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);
|
||||||
|
@ -1131,15 +1137,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;
|
||||||
|
@ -1653,7 +1655,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;
|
||||||
|
@ -2488,8 +2490,7 @@ out:
|
||||||
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;
|
||||||
|
@ -2501,6 +2502,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;
|
||||||
|
|
||||||
|
@ -2519,8 +2522,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;
|
||||||
|
|
||||||
|
@ -2596,10 +2599,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)
|
||||||
|
|
Loading…
Add table
Reference in a new issue