aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4state.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2005-10-18 17:20:12 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2005-10-18 17:20:12 -0400
commitcee54fc944422c44e476736c045a9e8053cb0644 (patch)
tree95f4728b3ffa8a2456727b10cd3a68f2a3065415 /fs/nfs/nfs4state.c
parent5e5ce5be6f0161d2a069a4f8a1154fe639c5c02f (diff)
NFSv4: Add functions to order RPC calls
NFSv4 file state-changing functions such as OPEN, CLOSE, LOCK,... are all labelled with "sequence identifiers" in order to prevent the server from reordering RPC requests, as this could cause its file state to become out of sync with the client. Currently the NFS client code enforces this ordering locally using semaphores to restrict access to structures until the RPC call is done. This, of course, only works with synchronous RPC calls, since the user process must first grab the semaphore. By dropping semaphores, and instead teaching the RPC engine to hold the RPC calls until they are ready to be sent, we can extend this process to work nicely with asynchronous RPC calls too. This patch adds a new list called "rpc_sequence" that defines the order of the RPC calls to be sent. We add one such list for each state_owner. When an RPC call is ready to be sent, it checks if it is top of the rpc_sequence list. If so, it proceeds. If not, it goes back to sleep, and loops until it hits top of the list. Once the RPC call has completed, it can then bump the sequence id counter, and remove itself from the rpc_sequence list, and then wake up the next sleeper. Note that the state_owner sequence ids and lock_owner sequence ids are all indexed to the same rpc_sequence list, so OPEN, LOCK,... requests are all ordered w.r.t. each other. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4state.c')
-rw-r--r--fs/nfs/nfs4state.c145
1 files changed, 119 insertions, 26 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index afe587d82f1e..f535c219cf3a 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 init_MUTEX(&sp->so_sema);
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}
@@ -553,12 +556,10 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
553 struct nfs4_lock_state *lsp; 556 struct nfs4_lock_state *lsp;
554 struct nfs4_client *clp = state->owner->so_client; 557 struct nfs4_client *clp = state->owner->so_client;
555 558
556 lsp = kmalloc(sizeof(*lsp), GFP_KERNEL); 559 lsp = kzalloc(sizeof(*lsp), GFP_KERNEL);
557 if (lsp == NULL) 560 if (lsp == NULL)
558 return NULL; 561 return NULL;
559 lsp->ls_flags = 0; 562 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); 563 atomic_set(&lsp->ls_count, 1);
563 lsp->ls_owner = fl_owner; 564 lsp->ls_owner = fl_owner;
564 spin_lock(&clp->cl_lock); 565 spin_lock(&clp->cl_lock);
@@ -673,29 +674,102 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f
673 nfs4_put_lock_state(lsp); 674 nfs4_put_lock_state(lsp);
674} 675}
675 676
676/* 677struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter)
677* Called with state->lock_sema and clp->cl_sem held. 678{
678*/ 679 struct rpc_sequence *sequence = counter->sequence;
679void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp) 680 struct nfs_seqid *new;
681
682 new = kmalloc(sizeof(*new), GFP_KERNEL);
683 if (new != NULL) {
684 new->sequence = counter;
685 new->task = NULL;
686 spin_lock(&sequence->lock);
687 list_add_tail(&new->list, &sequence->list);
688 spin_unlock(&sequence->lock);
689 }
690 return new;
691}
692
693void nfs_free_seqid(struct nfs_seqid *seqid)
680{ 694{
681 if (status == NFS_OK || seqid_mutating_err(-status)) 695 struct rpc_sequence *sequence = seqid->sequence->sequence;
682 lsp->ls_seqid++; 696 struct rpc_task *next = NULL;
697
698 spin_lock(&sequence->lock);
699 list_del(&seqid->list);
700 if (!list_empty(&sequence->list)) {
701 next = list_entry(sequence->list.next, struct nfs_seqid, list)->task;
702 if (next)
703 rpc_wake_up_task(next);
704 }
705 spin_unlock(&sequence->lock);
706 kfree(seqid);
683} 707}
684 708
685/* 709/*
686* Called with sp->so_sema and clp->cl_sem held. 710 * Called with sp->so_sema and clp->cl_sem held.
687* 711 *
688* Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or 712 * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or
689* failed with a seqid incrementing error - 713 * failed with a seqid incrementing error -
690* see comments nfs_fs.h:seqid_mutating_error() 714 * see comments nfs_fs.h:seqid_mutating_error()
691*/ 715 */
692void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp) 716static inline void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
693{ 717{
694 if (status == NFS_OK || seqid_mutating_err(-status)) 718 switch (status) {
695 sp->so_seqid++; 719 case 0:
696 /* If the server returns BAD_SEQID, unhash state_owner here */ 720 break;
697 if (status == -NFS4ERR_BAD_SEQID) 721 case -NFS4ERR_BAD_SEQID:
722 case -NFS4ERR_STALE_CLIENTID:
723 case -NFS4ERR_STALE_STATEID:
724 case -NFS4ERR_BAD_STATEID:
725 case -NFS4ERR_BADXDR:
726 case -NFS4ERR_RESOURCE:
727 case -NFS4ERR_NOFILEHANDLE:
728 /* Non-seqid mutating errors */
729 return;
730 };
731 /*
732 * Note: no locking needed as we are guaranteed to be first
733 * on the sequence list
734 */
735 seqid->sequence->counter++;
736}
737
738void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
739{
740 if (status == -NFS4ERR_BAD_SEQID) {
741 struct nfs4_state_owner *sp = container_of(seqid->sequence,
742 struct nfs4_state_owner, so_seqid);
698 nfs4_drop_state_owner(sp); 743 nfs4_drop_state_owner(sp);
744 }
745 return nfs_increment_seqid(status, seqid);
746}
747
748/*
749 * Called with ls->lock_sema and clp->cl_sem held.
750 *
751 * Increment the seqid if the LOCK/LOCKU succeeded, or
752 * failed with a seqid incrementing error -
753 * see comments nfs_fs.h:seqid_mutating_error()
754 */
755void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
756{
757 return nfs_increment_seqid(status, seqid);
758}
759
760int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
761{
762 struct rpc_sequence *sequence = seqid->sequence->sequence;
763 int status = 0;
764
765 spin_lock(&sequence->lock);
766 if (sequence->list.next != &seqid->list) {
767 seqid->task = task;
768 rpc_sleep_on(&sequence->wait, task, NULL, NULL);
769 status = -EAGAIN;
770 }
771 spin_unlock(&sequence->lock);
772 return status;
699} 773}
700 774
701static int reclaimer(void *); 775static int reclaimer(void *);
@@ -791,8 +865,6 @@ static int nfs4_reclaim_open_state(struct nfs4_state_recovery_ops *ops, struct n
791 if (state->state == 0) 865 if (state->state == 0)
792 continue; 866 continue;
793 status = ops->recover_open(sp, state); 867 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) { 868 if (status >= 0) {
797 status = nfs4_reclaim_locks(ops, state); 869 status = nfs4_reclaim_locks(ops, state);
798 if (status < 0) 870 if (status < 0)
@@ -831,6 +903,26 @@ out_err:
831 return status; 903 return status;
832} 904}
833 905
906static void nfs4_state_mark_reclaim(struct nfs4_client *clp)
907{
908 struct nfs4_state_owner *sp;
909 struct nfs4_state *state;
910 struct nfs4_lock_state *lock;
911
912 /* Reset all sequence ids to zero */
913 list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
914 sp->so_seqid.counter = 0;
915 sp->so_seqid.flags = 0;
916 list_for_each_entry(state, &sp->so_states, open_states) {
917 list_for_each_entry(lock, &state->lock_states, ls_locks) {
918 lock->ls_seqid.counter = 0;
919 lock->ls_seqid.flags = 0;
920 lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
921 }
922 }
923 }
924}
925
834static int reclaimer(void *ptr) 926static int reclaimer(void *ptr)
835{ 927{
836 struct reclaimer_args *args = (struct reclaimer_args *)ptr; 928 struct reclaimer_args *args = (struct reclaimer_args *)ptr;
@@ -864,6 +956,7 @@ restart_loop:
864 default: 956 default:
865 ops = &nfs4_network_partition_recovery_ops; 957 ops = &nfs4_network_partition_recovery_ops;
866 }; 958 };
959 nfs4_state_mark_reclaim(clp);
867 status = __nfs4_init_client(clp); 960 status = __nfs4_init_client(clp);
868 if (status) 961 if (status)
869 goto out_error; 962 goto out_error;