aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-03 23:48:13 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-10 23:40:40 -0400
commit2ced46c27058710a6d731d6eca77f1dd14ccde75 (patch)
treed505d922873c7b3ade6426d0e9924b1c0c380614 /fs/nfs
parent549d6ed5e85003370fe858e70864a71882491d28 (diff)
NFSv4: Fix up a bug in nfs4_open_recover()
Don't clobber the delegation info... Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4proc.c65
1 files changed, 31 insertions, 34 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 4f0b06d549fa..03b60c67ca7c 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -230,6 +230,16 @@ struct nfs4_opendata {
230 int cancelled; 230 int cancelled;
231}; 231};
232 232
233
234static void nfs4_init_opendata_res(struct nfs4_opendata *p)
235{
236 p->o_res.f_attr = &p->f_attr;
237 p->o_res.dir_attr = &p->dir_attr;
238 p->o_res.server = p->o_arg.server;
239 nfs_fattr_init(&p->f_attr);
240 nfs_fattr_init(&p->dir_attr);
241}
242
233static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, 243static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
234 struct nfs4_state_owner *sp, int flags, 244 struct nfs4_state_owner *sp, int flags,
235 const struct iattr *attrs) 245 const struct iattr *attrs)
@@ -258,11 +268,6 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
258 p->o_arg.server = server; 268 p->o_arg.server = server;
259 p->o_arg.bitmask = server->attr_bitmask; 269 p->o_arg.bitmask = server->attr_bitmask;
260 p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; 270 p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
261 p->o_res.f_attr = &p->f_attr;
262 p->o_res.dir_attr = &p->dir_attr;
263 p->o_res.server = server;
264 nfs_fattr_init(&p->f_attr);
265 nfs_fattr_init(&p->dir_attr);
266 if (flags & O_EXCL) { 271 if (flags & O_EXCL) {
267 u32 *s = (u32 *) p->o_arg.u.verifier.data; 272 u32 *s = (u32 *) p->o_arg.u.verifier.data;
268 s[0] = jiffies; 273 s[0] = jiffies;
@@ -274,6 +279,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
274 p->c_arg.fh = &p->o_res.fh; 279 p->c_arg.fh = &p->o_res.fh;
275 p->c_arg.stateid = &p->o_res.stateid; 280 p->c_arg.stateid = &p->o_res.stateid;
276 p->c_arg.seqid = p->o_arg.seqid; 281 p->c_arg.seqid = p->o_arg.seqid;
282 nfs4_init_opendata_res(p);
277 kref_init(&p->kref); 283 kref_init(&p->kref);
278 return p; 284 return p;
279err_free: 285err_free:
@@ -394,64 +400,54 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *
394 return ERR_PTR(-ENOENT); 400 return ERR_PTR(-ENOENT);
395} 401}
396 402
397static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, nfs4_stateid *stateid) 403static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res)
398{ 404{
405 struct nfs4_state *newstate;
399 int ret; 406 int ret;
400 407
401 opendata->o_arg.open_flags = openflags; 408 opendata->o_arg.open_flags = openflags;
409 memset(&opendata->o_res, 0, sizeof(opendata->o_res));
410 memset(&opendata->c_res, 0, sizeof(opendata->c_res));
411 nfs4_init_opendata_res(opendata);
402 ret = _nfs4_proc_open(opendata); 412 ret = _nfs4_proc_open(opendata);
403 if (ret != 0) 413 if (ret != 0)
404 return ret; 414 return ret;
405 memcpy(stateid->data, opendata->o_res.stateid.data, 415 newstate = nfs4_opendata_to_nfs4_state(opendata);
406 sizeof(stateid->data)); 416 if (newstate != NULL)
417 nfs4_close_state(&opendata->path, newstate, openflags);
418 *res = newstate;
407 return 0; 419 return 0;
408} 420}
409 421
410static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) 422static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state)
411{ 423{
412 nfs4_stateid stateid;
413 struct nfs4_state *newstate; 424 struct nfs4_state *newstate;
414 int mode = 0;
415 int delegation = 0;
416 int ret; 425 int ret;
417 426
418 /* memory barrier prior to reading state->n_* */ 427 /* memory barrier prior to reading state->n_* */
428 clear_bit(NFS_DELEGATED_STATE, &state->flags);
419 smp_rmb(); 429 smp_rmb();
420 if (state->n_rdwr != 0) { 430 if (state->n_rdwr != 0) {
421 ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &stateid); 431 ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
422 if (ret != 0) 432 if (ret != 0)
423 return ret; 433 return ret;
424 mode |= FMODE_READ|FMODE_WRITE; 434 if (newstate != state)
425 if (opendata->o_res.delegation_type != 0) 435 return -ESTALE;
426 delegation = opendata->o_res.delegation_type;
427 smp_rmb();
428 } 436 }
429 if (state->n_wronly != 0) { 437 if (state->n_wronly != 0) {
430 ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &stateid); 438 ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
431 if (ret != 0) 439 if (ret != 0)
432 return ret; 440 return ret;
433 mode |= FMODE_WRITE; 441 if (newstate != state)
434 if (opendata->o_res.delegation_type != 0) 442 return -ESTALE;
435 delegation = opendata->o_res.delegation_type;
436 smp_rmb();
437 } 443 }
438 if (state->n_rdonly != 0) { 444 if (state->n_rdonly != 0) {
439 ret = nfs4_open_recover_helper(opendata, FMODE_READ, &stateid); 445 ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
440 if (ret != 0) 446 if (ret != 0)
441 return ret; 447 return ret;
442 mode |= FMODE_READ; 448 if (newstate != state)
449 return -ESTALE;
443 } 450 }
444 clear_bit(NFS_DELEGATED_STATE, &state->flags);
445 if (mode == 0)
446 return 0;
447 if (opendata->o_res.delegation_type == 0)
448 opendata->o_res.delegation_type = delegation;
449 opendata->o_arg.open_flags |= mode;
450 newstate = nfs4_opendata_to_nfs4_state(opendata);
451 if (newstate != NULL)
452 nfs4_close_state(&opendata->path, newstate, opendata->o_arg.open_flags);
453 if (newstate != state)
454 return -ESTALE;
455 return 0; 451 return 0;
456} 452}
457 453
@@ -730,6 +726,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
730 * want to ensure that it takes the 'error' code path. 726 * want to ensure that it takes the 'error' code path.
731 */ 727 */
732 data->rpc_status = -ENOMEM; 728 data->rpc_status = -ENOMEM;
729 data->cancelled = 0;
733 task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); 730 task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data);
734 if (IS_ERR(task)) 731 if (IS_ERR(task))
735 return PTR_ERR(task); 732 return PTR_ERR(task);