Commit 2ced46c2 authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Fix up a bug in nfs4_open_recover()

Don't clobber the delegation info...
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 549d6ed5
...@@ -230,6 +230,16 @@ struct nfs4_opendata { ...@@ -230,6 +230,16 @@ struct nfs4_opendata {
int cancelled; int cancelled;
}; };
static void nfs4_init_opendata_res(struct nfs4_opendata *p)
{
p->o_res.f_attr = &p->f_attr;
p->o_res.dir_attr = &p->dir_attr;
p->o_res.server = p->o_arg.server;
nfs_fattr_init(&p->f_attr);
nfs_fattr_init(&p->dir_attr);
}
static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
struct nfs4_state_owner *sp, int flags, struct nfs4_state_owner *sp, int flags,
const struct iattr *attrs) const struct iattr *attrs)
...@@ -258,11 +268,6 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, ...@@ -258,11 +268,6 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
p->o_arg.server = server; p->o_arg.server = server;
p->o_arg.bitmask = server->attr_bitmask; p->o_arg.bitmask = server->attr_bitmask;
p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
p->o_res.f_attr = &p->f_attr;
p->o_res.dir_attr = &p->dir_attr;
p->o_res.server = server;
nfs_fattr_init(&p->f_attr);
nfs_fattr_init(&p->dir_attr);
if (flags & O_EXCL) { if (flags & O_EXCL) {
u32 *s = (u32 *) p->o_arg.u.verifier.data; u32 *s = (u32 *) p->o_arg.u.verifier.data;
s[0] = jiffies; s[0] = jiffies;
...@@ -274,6 +279,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, ...@@ -274,6 +279,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
p->c_arg.fh = &p->o_res.fh; p->c_arg.fh = &p->o_res.fh;
p->c_arg.stateid = &p->o_res.stateid; p->c_arg.stateid = &p->o_res.stateid;
p->c_arg.seqid = p->o_arg.seqid; p->c_arg.seqid = p->o_arg.seqid;
nfs4_init_opendata_res(p);
kref_init(&p->kref); kref_init(&p->kref);
return p; return p;
err_free: err_free:
...@@ -394,64 +400,54 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state * ...@@ -394,64 +400,54 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, nfs4_stateid *stateid) static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res)
{ {
struct nfs4_state *newstate;
int ret; int ret;
opendata->o_arg.open_flags = openflags; opendata->o_arg.open_flags = openflags;
memset(&opendata->o_res, 0, sizeof(opendata->o_res));
memset(&opendata->c_res, 0, sizeof(opendata->c_res));
nfs4_init_opendata_res(opendata);
ret = _nfs4_proc_open(opendata); ret = _nfs4_proc_open(opendata);
if (ret != 0) if (ret != 0)
return ret; return ret;
memcpy(stateid->data, opendata->o_res.stateid.data, newstate = nfs4_opendata_to_nfs4_state(opendata);
sizeof(stateid->data)); if (newstate != NULL)
nfs4_close_state(&opendata->path, newstate, openflags);
*res = newstate;
return 0; return 0;
} }
static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state)
{ {
nfs4_stateid stateid;
struct nfs4_state *newstate; struct nfs4_state *newstate;
int mode = 0;
int delegation = 0;
int ret; int ret;
/* memory barrier prior to reading state->n_* */ /* memory barrier prior to reading state->n_* */
clear_bit(NFS_DELEGATED_STATE, &state->flags);
smp_rmb(); smp_rmb();
if (state->n_rdwr != 0) { if (state->n_rdwr != 0) {
ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &stateid); ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
if (ret != 0) if (ret != 0)
return ret; return ret;
mode |= FMODE_READ|FMODE_WRITE; if (newstate != state)
if (opendata->o_res.delegation_type != 0) return -ESTALE;
delegation = opendata->o_res.delegation_type;
smp_rmb();
} }
if (state->n_wronly != 0) { if (state->n_wronly != 0) {
ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &stateid); ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
if (ret != 0) if (ret != 0)
return ret; return ret;
mode |= FMODE_WRITE; if (newstate != state)
if (opendata->o_res.delegation_type != 0) return -ESTALE;
delegation = opendata->o_res.delegation_type;
smp_rmb();
} }
if (state->n_rdonly != 0) { if (state->n_rdonly != 0) {
ret = nfs4_open_recover_helper(opendata, FMODE_READ, &stateid); ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
if (ret != 0) if (ret != 0)
return ret; return ret;
mode |= FMODE_READ; if (newstate != state)
return -ESTALE;
} }
clear_bit(NFS_DELEGATED_STATE, &state->flags);
if (mode == 0)
return 0;
if (opendata->o_res.delegation_type == 0)
opendata->o_res.delegation_type = delegation;
opendata->o_arg.open_flags |= mode;
newstate = nfs4_opendata_to_nfs4_state(opendata);
if (newstate != NULL)
nfs4_close_state(&opendata->path, newstate, opendata->o_arg.open_flags);
if (newstate != state)
return -ESTALE;
return 0; return 0;
} }
...@@ -730,6 +726,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) ...@@ -730,6 +726,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
* want to ensure that it takes the 'error' code path. * want to ensure that it takes the 'error' code path.
*/ */
data->rpc_status = -ENOMEM; data->rpc_status = -ENOMEM;
data->cancelled = 0;
task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data);
if (IS_ERR(task)) if (IS_ERR(task))
return PTR_ERR(task); return PTR_ERR(task);
......
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