aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-01-03 03:55:15 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-01-06 14:58:43 -0500
commit864472e9b8fa76ffaad17dfcb84d79e16df6828c (patch)
tree1cc5c4624c36be0b9aebdabae30d1a5385e04dee /fs/nfs/nfs4proc.c
parente761692381f294ea079d2e869fcd7c0afc79e394 (diff)
NFSv4: Make open recovery track O_RDWR, O_RDONLY and O_WRONLY correctly
When recovering from a delegation recall or a network partition, we need to replay open(O_RDWR), open(O_RDONLY) and open(O_WRONLY) separately. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c276
1 files changed, 149 insertions, 127 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index e494cc2ea986..3ecb7da220f5 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -58,7 +58,7 @@
58#define NFS4_POLL_RETRY_MAX (15*HZ) 58#define NFS4_POLL_RETRY_MAX (15*HZ)
59 59
60struct nfs4_opendata; 60struct nfs4_opendata;
61static int _nfs4_proc_open_confirm(struct nfs4_opendata *data); 61static int _nfs4_proc_open(struct nfs4_opendata *data);
62static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); 62static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
63static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); 63static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *);
64static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); 64static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
@@ -346,32 +346,108 @@ out:
346 return state; 346 return state;
347} 347}
348 348
349static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
350{
351 struct nfs_inode *nfsi = NFS_I(state->inode);
352 struct nfs_open_context *ctx;
353
354 spin_lock(&state->inode->i_lock);
355 list_for_each_entry(ctx, &nfsi->open_files, list) {
356 if (ctx->state != state)
357 continue;
358 get_nfs_open_context(ctx);
359 spin_unlock(&state->inode->i_lock);
360 return ctx;
361 }
362 spin_unlock(&state->inode->i_lock);
363 return ERR_PTR(-ENOENT);
364}
365
366static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, nfs4_stateid *stateid)
367{
368 int ret;
369
370 opendata->o_arg.open_flags = openflags;
371 ret = _nfs4_proc_open(opendata);
372 if (ret != 0)
373 return ret;
374 memcpy(stateid->data, opendata->o_res.stateid.data,
375 sizeof(stateid->data));
376 return 0;
377}
378
379static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state)
380{
381 nfs4_stateid stateid;
382 struct nfs4_state *newstate;
383 int mode = 0;
384 int delegation = 0;
385 int ret;
386
387 /* memory barrier prior to reading state->n_* */
388 smp_rmb();
389 if (state->n_rdwr != 0) {
390 ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &stateid);
391 if (ret != 0)
392 return ret;
393 mode |= FMODE_READ|FMODE_WRITE;
394 if (opendata->o_res.delegation_type != 0)
395 delegation = opendata->o_res.delegation_type;
396 smp_rmb();
397 }
398 if (state->n_wronly != 0) {
399 ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &stateid);
400 if (ret != 0)
401 return ret;
402 mode |= FMODE_WRITE;
403 if (opendata->o_res.delegation_type != 0)
404 delegation = opendata->o_res.delegation_type;
405 smp_rmb();
406 }
407 if (state->n_rdonly != 0) {
408 ret = nfs4_open_recover_helper(opendata, FMODE_READ, &stateid);
409 if (ret != 0)
410 return ret;
411 mode |= FMODE_READ;
412 }
413 clear_bit(NFS_DELEGATED_STATE, &state->flags);
414 if (mode == 0)
415 return 0;
416 if (opendata->o_res.delegation_type == 0)
417 opendata->o_res.delegation_type = delegation;
418 opendata->o_arg.open_flags |= mode;
419 newstate = nfs4_opendata_to_nfs4_state(opendata);
420 if (newstate != NULL) {
421 if (opendata->o_res.delegation_type != 0) {
422 struct nfs_inode *nfsi = NFS_I(newstate->inode);
423 int delegation_flags = 0;
424 if (nfsi->delegation)
425 delegation_flags = nfsi->delegation->flags;
426 if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM))
427 nfs_inode_set_delegation(newstate->inode,
428 opendata->owner->so_cred,
429 &opendata->o_res);
430 else
431 nfs_inode_reclaim_delegation(newstate->inode,
432 opendata->owner->so_cred,
433 &opendata->o_res);
434 }
435 nfs4_close_state(newstate, opendata->o_arg.open_flags);
436 }
437 if (newstate != state)
438 return -ESTALE;
439 return 0;
440}
441
349/* 442/*
350 * OPEN_RECLAIM: 443 * OPEN_RECLAIM:
351 * reclaim state on the server after a reboot. 444 * reclaim state on the server after a reboot.
352 */ 445 */
353static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) 446static int _nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
354{ 447{
355 struct inode *inode = state->inode; 448 struct nfs_delegation *delegation = NFS_I(state->inode)->delegation;
356 struct nfs_server *server = NFS_SERVER(inode); 449 struct nfs4_opendata *opendata;
357 struct nfs_delegation *delegation = NFS_I(inode)->delegation; 450 int delegation_type = 0;
358 struct nfs_openargs o_arg = {
359 .fh = NFS_FH(inode),
360 .id = sp->so_id,
361 .open_flags = state->state,
362 .clientid = server->nfs4_state->cl_clientid,
363 .claim = NFS4_OPEN_CLAIM_PREVIOUS,
364 .bitmask = server->attr_bitmask,
365 };
366 struct nfs_openres o_res = {
367 .server = server, /* Grrr */
368 };
369 struct rpc_message msg = {
370 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR],
371 .rpc_argp = &o_arg,
372 .rpc_resp = &o_res,
373 .rpc_cred = sp->so_cred,
374 };
375 int status; 451 int status;
376 452
377 if (delegation != NULL) { 453 if (delegation != NULL) {
@@ -381,38 +457,27 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
381 set_bit(NFS_DELEGATED_STATE, &state->flags); 457 set_bit(NFS_DELEGATED_STATE, &state->flags);
382 return 0; 458 return 0;
383 } 459 }
384 o_arg.u.delegation_type = delegation->type; 460 delegation_type = delegation->type;
385 } 461 }
386 o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); 462 opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL);
387 if (o_arg.seqid == NULL) 463 if (opendata == NULL)
388 return -ENOMEM; 464 return -ENOMEM;
389 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 465 opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS;
390 /* Confirm the sequence as being established */ 466 opendata->o_arg.fh = NFS_FH(state->inode);
391 nfs_confirm_seqid(&sp->so_seqid, status); 467 nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh);
392 nfs_increment_open_seqid(status, o_arg.seqid); 468 opendata->o_arg.u.delegation_type = delegation_type;
393 if (status == 0) { 469 status = nfs4_open_recover(opendata, state);
394 memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); 470 nfs4_opendata_free(opendata);
395 if (o_res.delegation_type != 0) {
396 nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res);
397 /* Did the server issue an immediate delegation recall? */
398 if (o_res.do_recall)
399 nfs_async_inode_return_delegation(inode, &o_res.stateid);
400 }
401 }
402 nfs_free_seqid(o_arg.seqid);
403 clear_bit(NFS_DELEGATED_STATE, &state->flags);
404 /* Ensure we update the inode attributes */
405 NFS_CACHEINV(inode);
406 return status; 471 return status;
407} 472}
408 473
409static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state) 474static int nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
410{ 475{
411 struct nfs_server *server = NFS_SERVER(state->inode); 476 struct nfs_server *server = NFS_SERVER(state->inode);
412 struct nfs4_exception exception = { }; 477 struct nfs4_exception exception = { };
413 int err; 478 int err;
414 do { 479 do {
415 err = _nfs4_open_reclaim(sp, state); 480 err = _nfs4_do_open_reclaim(sp, state, dentry);
416 if (err != -NFS4ERR_DELAY) 481 if (err != -NFS4ERR_DELAY)
417 break; 482 break;
418 nfs4_handle_exception(server, err, &exception); 483 nfs4_handle_exception(server, err, &exception);
@@ -420,50 +485,36 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta
420 return err; 485 return err;
421} 486}
422 487
488static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
489{
490 struct nfs_open_context *ctx;
491 int ret;
492
493 ctx = nfs4_state_find_open_context(state);
494 if (IS_ERR(ctx))
495 return PTR_ERR(ctx);
496 ret = nfs4_do_open_reclaim(sp, state, ctx->dentry);
497 put_nfs_open_context(ctx);
498 return ret;
499}
500
423static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) 501static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
424{ 502{
425 struct nfs4_state_owner *sp = state->owner; 503 struct nfs4_state_owner *sp = state->owner;
426 struct inode *inode = dentry->d_inode;
427 struct nfs_server *server = NFS_SERVER(inode);
428 struct rpc_message msg = {
429 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR],
430 .rpc_cred = sp->so_cred,
431 };
432 struct nfs4_opendata *opendata; 504 struct nfs4_opendata *opendata;
433 int status = 0; 505 int ret;
434 506
435 if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) 507 if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
436 goto out; 508 return 0;
437 if (state->state == 0) 509 opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL);
438 goto out;
439 opendata = nfs4_opendata_alloc(dentry, sp, state->state, NULL);
440 status = -ENOMEM;
441 if (opendata == NULL) 510 if (opendata == NULL)
442 goto out; 511 return -ENOMEM;
443 opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; 512 opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;
444 msg.rpc_argp = &opendata->o_arg;
445 msg.rpc_resp = &opendata->o_res;
446 memcpy(opendata->o_arg.u.delegation.data, state->stateid.data, 513 memcpy(opendata->o_arg.u.delegation.data, state->stateid.data,
447 sizeof(opendata->o_arg.u.delegation.data)); 514 sizeof(opendata->o_arg.u.delegation.data));
448 status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); 515 ret = nfs4_open_recover(opendata, state);
449 nfs_increment_open_seqid(status, opendata->o_arg.seqid);
450 if (status != 0)
451 goto out_free;
452 if(opendata->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) {
453 status = _nfs4_proc_open_confirm(opendata);
454 if (status != 0)
455 goto out_free;
456 }
457 nfs_confirm_seqid(&sp->so_seqid, 0);
458 if (status >= 0) {
459 memcpy(state->stateid.data, opendata->o_res.stateid.data,
460 sizeof(state->stateid.data));
461 clear_bit(NFS_DELEGATED_STATE, &state->flags);
462 }
463out_free:
464 nfs4_opendata_free(opendata); 516 nfs4_opendata_free(opendata);
465out: 517 return ret;
466 return status;
467} 518}
468 519
469int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) 520int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
@@ -580,6 +631,8 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
580 /* Update sequence id. */ 631 /* Update sequence id. */
581 data->o_arg.id = sp->so_id; 632 data->o_arg.id = sp->so_id;
582 data->o_arg.clientid = sp->so_client->cl_clientid; 633 data->o_arg.clientid = sp->so_client->cl_clientid;
634 if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
635 msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
583 rpc_call_setup(task, &msg, 0); 636 rpc_call_setup(task, &msg, 0);
584} 637}
585 638
@@ -714,55 +767,31 @@ out:
714 */ 767 */
715static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) 768static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
716{ 769{
717 struct dentry *parent = dget_parent(dentry);
718 struct inode *inode = state->inode; 770 struct inode *inode = state->inode;
719 struct nfs_delegation *delegation = NFS_I(inode)->delegation; 771 struct nfs_delegation *delegation = NFS_I(inode)->delegation;
720 struct nfs4_opendata *opendata; 772 struct nfs4_opendata *opendata;
721 struct nfs4_state *newstate;
722 int openflags = state->state & (FMODE_READ|FMODE_WRITE); 773 int openflags = state->state & (FMODE_READ|FMODE_WRITE);
723 int status = 0; 774 int ret;
724 775
725 if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { 776 if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) {
726 status = _nfs4_do_access(inode, sp->so_cred, openflags); 777 ret = _nfs4_do_access(inode, sp->so_cred, openflags);
727 if (status < 0) 778 if (ret < 0)
728 goto out; 779 return ret;
729 memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid)); 780 memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid));
730 set_bit(NFS_DELEGATED_STATE, &state->flags); 781 set_bit(NFS_DELEGATED_STATE, &state->flags);
731 goto out; 782 return 0;
732 } 783 }
733 status = -ENOMEM;
734 opendata = nfs4_opendata_alloc(dentry, sp, openflags, NULL); 784 opendata = nfs4_opendata_alloc(dentry, sp, openflags, NULL);
735 if (opendata == NULL) 785 if (opendata == NULL)
736 goto out; 786 return -ENOMEM;
737 status = _nfs4_proc_open(opendata); 787 ret = nfs4_open_recover(opendata, state);
738 if (status != 0) 788 if (ret == -ESTALE) {
739 goto out_nodeleg; 789 /* Invalidate the state owner so we don't ever use it again */
740 newstate = nfs4_opendata_to_nfs4_state(opendata); 790 nfs4_drop_state_owner(sp);
741 if (newstate != state) 791 d_drop(dentry);
742 goto out_stale;
743 if (opendata->o_res.delegation_type != 0) {
744 if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM))
745 nfs_inode_set_delegation(inode, sp->so_cred,
746 &opendata->o_res);
747 else
748 nfs_inode_reclaim_delegation(inode, sp->so_cred,
749 &opendata->o_res);
750 } 792 }
751out_close_state:
752 nfs4_close_state(newstate, openflags);
753out_nodeleg:
754 nfs4_opendata_free(opendata); 793 nfs4_opendata_free(opendata);
755 clear_bit(NFS_DELEGATED_STATE, &state->flags); 794 return ret;
756out:
757 dput(parent);
758 return status;
759out_stale:
760 status = -ESTALE;
761 /* Invalidate the state owner so we don't ever use it again */
762 nfs4_drop_state_owner(sp);
763 d_drop(dentry);
764 /* Should we be trying to close that stateid? */
765 goto out_close_state;
766} 795}
767 796
768static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) 797static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
@@ -781,22 +810,15 @@ static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_
781 810
782static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) 811static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
783{ 812{
784 struct nfs_inode *nfsi = NFS_I(state->inode);
785 struct nfs_open_context *ctx; 813 struct nfs_open_context *ctx;
786 int status; 814 int ret;
787 815
788 spin_lock(&state->inode->i_lock); 816 ctx = nfs4_state_find_open_context(state);
789 list_for_each_entry(ctx, &nfsi->open_files, list) { 817 if (IS_ERR(ctx))
790 if (ctx->state != state) 818 return PTR_ERR(ctx);
791 continue; 819 ret = nfs4_do_open_expired(sp, state, ctx->dentry);
792 get_nfs_open_context(ctx); 820 put_nfs_open_context(ctx);
793 spin_unlock(&state->inode->i_lock); 821 return ret;
794 status = nfs4_do_open_expired(sp, state, ctx->dentry);
795 put_nfs_open_context(ctx);
796 return status;
797 }
798 spin_unlock(&state->inode->i_lock);
799 return -ENOENT;
800} 822}
801 823
802/* 824/*