aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4state.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs4state.c')
-rw-r--r--fs/nfs/nfs4state.c181
1 files changed, 135 insertions, 46 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index afe587d82f1e..2d5a6a2b9dec 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -264,13 +264,16 @@ nfs4_alloc_state_owner(void)
264{ 264{
265 struct nfs4_state_owner *sp; 265 struct nfs4_state_owner *sp;
266 266
267 sp = kmalloc(sizeof(*sp),GFP_KERNEL); 267 sp = kzalloc(sizeof(*sp),GFP_KERNEL);
268 if (!sp) 268 if (!sp)
269 return NULL; 269 return NULL;
270 init_MUTEX(&sp->so_sema); 270 spin_lock_init(&sp->so_lock);
271 sp->so_seqid = 0; /* arbitrary */
272 INIT_LIST_HEAD(&sp->so_states); 271 INIT_LIST_HEAD(&sp->so_states);
273 INIT_LIST_HEAD(&sp->so_delegations); 272 INIT_LIST_HEAD(&sp->so_delegations);
273 rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue");
274 sp->so_seqid.sequence = &sp->so_sequence;
275 spin_lock_init(&sp->so_sequence.lock);
276 INIT_LIST_HEAD(&sp->so_sequence.list);
274 atomic_set(&sp->so_count, 1); 277 atomic_set(&sp->so_count, 1);
275 return sp; 278 return sp;
276} 279}
@@ -359,7 +362,6 @@ nfs4_alloc_open_state(void)
359 memset(state->stateid.data, 0, sizeof(state->stateid.data)); 362 memset(state->stateid.data, 0, sizeof(state->stateid.data));
360 atomic_set(&state->count, 1); 363 atomic_set(&state->count, 1);
361 INIT_LIST_HEAD(&state->lock_states); 364 INIT_LIST_HEAD(&state->lock_states);
362 init_MUTEX(&state->lock_sema);
363 spin_lock_init(&state->state_lock); 365 spin_lock_init(&state->state_lock);
364 return state; 366 return state;
365} 367}
@@ -437,21 +439,23 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner)
437 if (state) 439 if (state)
438 goto out; 440 goto out;
439 new = nfs4_alloc_open_state(); 441 new = nfs4_alloc_open_state();
442 spin_lock(&owner->so_lock);
440 spin_lock(&inode->i_lock); 443 spin_lock(&inode->i_lock);
441 state = __nfs4_find_state_byowner(inode, owner); 444 state = __nfs4_find_state_byowner(inode, owner);
442 if (state == NULL && new != NULL) { 445 if (state == NULL && new != NULL) {
443 state = new; 446 state = new;
444 /* Caller *must* be holding owner->so_sem */
445 /* Note: The reclaim code dictates that we add stateless
446 * and read-only stateids to the end of the list */
447 list_add_tail(&state->open_states, &owner->so_states);
448 state->owner = owner; 447 state->owner = owner;
449 atomic_inc(&owner->so_count); 448 atomic_inc(&owner->so_count);
450 list_add(&state->inode_states, &nfsi->open_states); 449 list_add(&state->inode_states, &nfsi->open_states);
451 state->inode = igrab(inode); 450 state->inode = igrab(inode);
452 spin_unlock(&inode->i_lock); 451 spin_unlock(&inode->i_lock);
452 /* Note: The reclaim code dictates that we add stateless
453 * and read-only stateids to the end of the list */
454 list_add_tail(&state->open_states, &owner->so_states);
455 spin_unlock(&owner->so_lock);
453 } else { 456 } else {
454 spin_unlock(&inode->i_lock); 457 spin_unlock(&inode->i_lock);
458 spin_unlock(&owner->so_lock);
455 if (new) 459 if (new)
456 nfs4_free_open_state(new); 460 nfs4_free_open_state(new);
457 } 461 }
@@ -461,19 +465,21 @@ out:
461 465
462/* 466/*
463 * Beware! Caller must be holding exactly one 467 * Beware! Caller must be holding exactly one
464 * reference to clp->cl_sem and owner->so_sema! 468 * reference to clp->cl_sem!
465 */ 469 */
466void nfs4_put_open_state(struct nfs4_state *state) 470void nfs4_put_open_state(struct nfs4_state *state)
467{ 471{
468 struct inode *inode = state->inode; 472 struct inode *inode = state->inode;
469 struct nfs4_state_owner *owner = state->owner; 473 struct nfs4_state_owner *owner = state->owner;
470 474
471 if (!atomic_dec_and_lock(&state->count, &inode->i_lock)) 475 if (!atomic_dec_and_lock(&state->count, &owner->so_lock))
472 return; 476 return;
477 spin_lock(&inode->i_lock);
473 if (!list_empty(&state->inode_states)) 478 if (!list_empty(&state->inode_states))
474 list_del(&state->inode_states); 479 list_del(&state->inode_states);
475 spin_unlock(&inode->i_lock);
476 list_del(&state->open_states); 480 list_del(&state->open_states);
481 spin_unlock(&inode->i_lock);
482 spin_unlock(&owner->so_lock);
477 iput(inode); 483 iput(inode);
478 BUG_ON (state->state != 0); 484 BUG_ON (state->state != 0);
479 nfs4_free_open_state(state); 485 nfs4_free_open_state(state);
@@ -481,20 +487,17 @@ void nfs4_put_open_state(struct nfs4_state *state)
481} 487}
482 488
483/* 489/*
484 * Beware! Caller must be holding no references to clp->cl_sem! 490 * Close the current file.
485 * of owner->so_sema!
486 */ 491 */
487void nfs4_close_state(struct nfs4_state *state, mode_t mode) 492void nfs4_close_state(struct nfs4_state *state, mode_t mode)
488{ 493{
489 struct inode *inode = state->inode; 494 struct inode *inode = state->inode;
490 struct nfs4_state_owner *owner = state->owner; 495 struct nfs4_state_owner *owner = state->owner;
491 struct nfs4_client *clp = owner->so_client;
492 int newstate; 496 int newstate;
493 497
494 atomic_inc(&owner->so_count); 498 atomic_inc(&owner->so_count);
495 down_read(&clp->cl_sem);
496 down(&owner->so_sema);
497 /* Protect against nfs4_find_state() */ 499 /* Protect against nfs4_find_state() */
500 spin_lock(&owner->so_lock);
498 spin_lock(&inode->i_lock); 501 spin_lock(&inode->i_lock);
499 if (mode & FMODE_READ) 502 if (mode & FMODE_READ)
500 state->nreaders--; 503 state->nreaders--;
@@ -507,6 +510,7 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode)
507 list_move_tail(&state->open_states, &owner->so_states); 510 list_move_tail(&state->open_states, &owner->so_states);
508 } 511 }
509 spin_unlock(&inode->i_lock); 512 spin_unlock(&inode->i_lock);
513 spin_unlock(&owner->so_lock);
510 newstate = 0; 514 newstate = 0;
511 if (state->state != 0) { 515 if (state->state != 0) {
512 if (state->nreaders) 516 if (state->nreaders)
@@ -515,14 +519,16 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode)
515 newstate |= FMODE_WRITE; 519 newstate |= FMODE_WRITE;
516 if (state->state == newstate) 520 if (state->state == newstate)
517 goto out; 521 goto out;
518 if (nfs4_do_close(inode, state, newstate) == -EINPROGRESS) 522 if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
523 state->state = newstate;
524 goto out;
525 }
526 if (nfs4_do_close(inode, state, newstate) == 0)
519 return; 527 return;
520 } 528 }
521out: 529out:
522 nfs4_put_open_state(state); 530 nfs4_put_open_state(state);
523 up(&owner->so_sema);
524 nfs4_put_state_owner(owner); 531 nfs4_put_state_owner(owner);
525 up_read(&clp->cl_sem);
526} 532}
527 533
528/* 534/*
@@ -546,19 +552,16 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
546 * Return a compatible lock_state. If no initialized lock_state structure 552 * Return a compatible lock_state. If no initialized lock_state structure
547 * exists, return an uninitialized one. 553 * exists, return an uninitialized one.
548 * 554 *
549 * The caller must be holding state->lock_sema
550 */ 555 */
551static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) 556static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
552{ 557{
553 struct nfs4_lock_state *lsp; 558 struct nfs4_lock_state *lsp;
554 struct nfs4_client *clp = state->owner->so_client; 559 struct nfs4_client *clp = state->owner->so_client;
555 560
556 lsp = kmalloc(sizeof(*lsp), GFP_KERNEL); 561 lsp = kzalloc(sizeof(*lsp), GFP_KERNEL);
557 if (lsp == NULL) 562 if (lsp == NULL)
558 return NULL; 563 return NULL;
559 lsp->ls_flags = 0; 564 lsp->ls_seqid.sequence = &state->owner->so_sequence;
560 lsp->ls_seqid = 0; /* arbitrary */
561 memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data));
562 atomic_set(&lsp->ls_count, 1); 565 atomic_set(&lsp->ls_count, 1);
563 lsp->ls_owner = fl_owner; 566 lsp->ls_owner = fl_owner;
564 spin_lock(&clp->cl_lock); 567 spin_lock(&clp->cl_lock);
@@ -572,7 +575,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
572 * Return a compatible lock_state. If no initialized lock_state structure 575 * Return a compatible lock_state. If no initialized lock_state structure
573 * exists, return an uninitialized one. 576 * exists, return an uninitialized one.
574 * 577 *
575 * The caller must be holding state->lock_sema and clp->cl_sem 578 * The caller must be holding clp->cl_sem
576 */ 579 */
577static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) 580static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner)
578{ 581{
@@ -605,7 +608,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_
605 * Release reference to lock_state, and free it if we see that 608 * Release reference to lock_state, and free it if we see that
606 * it is no longer in use 609 * it is no longer in use
607 */ 610 */
608static void nfs4_put_lock_state(struct nfs4_lock_state *lsp) 611void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
609{ 612{
610 struct nfs4_state *state; 613 struct nfs4_state *state;
611 614
@@ -673,29 +676,94 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f
673 nfs4_put_lock_state(lsp); 676 nfs4_put_lock_state(lsp);
674} 677}
675 678
676/* 679struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter)
677* Called with state->lock_sema and clp->cl_sem held.
678*/
679void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp)
680{ 680{
681 if (status == NFS_OK || seqid_mutating_err(-status)) 681 struct nfs_seqid *new;
682 lsp->ls_seqid++; 682
683 new = kmalloc(sizeof(*new), GFP_KERNEL);
684 if (new != NULL) {
685 new->sequence = counter;
686 INIT_LIST_HEAD(&new->list);
687 }
688 return new;
689}
690
691void nfs_free_seqid(struct nfs_seqid *seqid)
692{
693 struct rpc_sequence *sequence = seqid->sequence->sequence;
694
695 if (!list_empty(&seqid->list)) {
696 spin_lock(&sequence->lock);
697 list_del(&seqid->list);
698 spin_unlock(&sequence->lock);
699 }
700 rpc_wake_up_next(&sequence->wait);
701 kfree(seqid);
683} 702}
684 703
685/* 704/*
686* Called with sp->so_sema and clp->cl_sem held. 705 * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or
687* 706 * failed with a seqid incrementing error -
688* Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or 707 * see comments nfs_fs.h:seqid_mutating_error()
689* failed with a seqid incrementing error - 708 */
690* see comments nfs_fs.h:seqid_mutating_error() 709static inline void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
691*/ 710{
692void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp) 711 switch (status) {
693{ 712 case 0:
694 if (status == NFS_OK || seqid_mutating_err(-status)) 713 break;
695 sp->so_seqid++; 714 case -NFS4ERR_BAD_SEQID:
696 /* If the server returns BAD_SEQID, unhash state_owner here */ 715 case -NFS4ERR_STALE_CLIENTID:
697 if (status == -NFS4ERR_BAD_SEQID) 716 case -NFS4ERR_STALE_STATEID:
717 case -NFS4ERR_BAD_STATEID:
718 case -NFS4ERR_BADXDR:
719 case -NFS4ERR_RESOURCE:
720 case -NFS4ERR_NOFILEHANDLE:
721 /* Non-seqid mutating errors */
722 return;
723 };
724 /*
725 * Note: no locking needed as we are guaranteed to be first
726 * on the sequence list
727 */
728 seqid->sequence->counter++;
729}
730
731void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
732{
733 if (status == -NFS4ERR_BAD_SEQID) {
734 struct nfs4_state_owner *sp = container_of(seqid->sequence,
735 struct nfs4_state_owner, so_seqid);
698 nfs4_drop_state_owner(sp); 736 nfs4_drop_state_owner(sp);
737 }
738 return nfs_increment_seqid(status, seqid);
739}
740
741/*
742 * Increment the seqid if the LOCK/LOCKU succeeded, or
743 * failed with a seqid incrementing error -
744 * see comments nfs_fs.h:seqid_mutating_error()
745 */
746void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
747{
748 return nfs_increment_seqid(status, seqid);
749}
750
751int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
752{
753 struct rpc_sequence *sequence = seqid->sequence->sequence;
754 int status = 0;
755
756 if (sequence->list.next == &seqid->list)
757 goto out;
758 spin_lock(&sequence->lock);
759 if (!list_empty(&sequence->list)) {
760 rpc_sleep_on(&sequence->wait, task, NULL, NULL);
761 status = -EAGAIN;
762 } else
763 list_add(&seqid->list, &sequence->list);
764 spin_unlock(&sequence->lock);
765out:
766 return status;
699} 767}
700 768
701static int reclaimer(void *); 769static int reclaimer(void *);
@@ -791,8 +859,6 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n
791 if (state->state == 0) 859 if (state->state == 0)
792 continue; 860 continue;
793 status = ops->recover_open(sp, state); 861 status = ops->recover_open(sp, state);
794 list_for_each_entry(lock, &state->lock_states, ls_locks)
795 lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
796 if (status >= 0) { 862 if (status >= 0) {
797 status = nfs4_reclaim_locks(ops, state); 863 status = nfs4_reclaim_locks(ops, state);
798 if (status < 0) 864 if (status < 0)
@@ -831,6 +897,28 @@ out_err:
831 return status; 897 return status;
832} 898}
833 899
900static void nfs4_state_mark_reclaim(struct nfs4_client *clp)
901{
902 struct nfs4_state_owner *sp;
903 struct nfs4_state *state;
904 struct nfs4_lock_state *lock;
905
906 /* Reset all sequence ids to zero */
907 list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
908 sp->so_seqid.counter = 0;
909 sp->so_seqid.flags = 0;
910 spin_lock(&sp->so_lock);
911 list_for_each_entry(state, &sp->so_states, open_states) {
912 list_for_each_entry(lock, &state->lock_states, ls_locks) {
913 lock->ls_seqid.counter = 0;
914 lock->ls_seqid.flags = 0;
915 lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
916 }
917 }
918 spin_unlock(&sp->so_lock);
919 }
920}
921
834static int reclaimer(void *ptr) 922static int reclaimer(void *ptr)
835{ 923{
836 struct reclaimer_args *args = (struct reclaimer_args *)ptr; 924 struct reclaimer_args *args = (struct reclaimer_args *)ptr;
@@ -864,6 +952,7 @@ restart_loop:
864 default: 952 default:
865 ops = &nfs4_network_partition_recovery_ops; 953 ops = &nfs4_network_partition_recovery_ops;
866 }; 954 };
955 nfs4_state_mark_reclaim(clp);
867 status = __nfs4_init_client(clp); 956 status = __nfs4_init_client(clp);
868 if (status) 957 if (status)
869 goto out_error; 958 goto out_error;