diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 57 |
1 files changed, 33 insertions, 24 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 795b24d82d18..bcd2339ae8c1 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -720,6 +720,28 @@ dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) | |||
720 | } | 720 | } |
721 | #endif | 721 | #endif |
722 | 722 | ||
723 | /* | ||
724 | * Bump the seqid on cstate->replay_owner, and clear replay_owner if it | ||
725 | * won't be used for replay. | ||
726 | */ | ||
727 | void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) | ||
728 | { | ||
729 | struct nfs4_stateowner *so = cstate->replay_owner; | ||
730 | |||
731 | if (nfserr == nfserr_replay_me) | ||
732 | return; | ||
733 | |||
734 | if (!seqid_mutating_err(ntohl(nfserr))) { | ||
735 | cstate->replay_owner = NULL; | ||
736 | return; | ||
737 | } | ||
738 | if (!so) | ||
739 | return; | ||
740 | if (so->so_is_open_owner) | ||
741 | release_last_closed_stateid(openowner(so)); | ||
742 | so->so_seqid++; | ||
743 | return; | ||
744 | } | ||
723 | 745 | ||
724 | static void | 746 | static void |
725 | gen_sessionid(struct nfsd4_session *ses) | 747 | gen_sessionid(struct nfsd4_session *ses) |
@@ -3702,6 +3724,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3702 | nfsd4_client_record_create(oo->oo_owner.so_client); | 3724 | nfsd4_client_record_create(oo->oo_owner.so_client); |
3703 | status = nfs_ok; | 3725 | status = nfs_ok; |
3704 | out: | 3726 | out: |
3727 | nfsd4_bump_seqid(cstate, status); | ||
3705 | if (!cstate->replay_owner) | 3728 | if (!cstate->replay_owner) |
3706 | nfs4_unlock_state(); | 3729 | nfs4_unlock_state(); |
3707 | return status; | 3730 | return status; |
@@ -3785,31 +3808,12 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3785 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 3808 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
3786 | status = nfs_ok; | 3809 | status = nfs_ok; |
3787 | out: | 3810 | out: |
3811 | nfsd4_bump_seqid(cstate, status); | ||
3788 | if (!cstate->replay_owner) | 3812 | if (!cstate->replay_owner) |
3789 | nfs4_unlock_state(); | 3813 | nfs4_unlock_state(); |
3790 | return status; | 3814 | return status; |
3791 | } | 3815 | } |
3792 | 3816 | ||
3793 | void nfsd4_purge_closed_stateid(struct nfs4_stateowner *so) | ||
3794 | { | ||
3795 | struct nfs4_openowner *oo; | ||
3796 | struct nfs4_ol_stateid *s; | ||
3797 | |||
3798 | if (!so->so_is_open_owner) | ||
3799 | return; | ||
3800 | oo = openowner(so); | ||
3801 | s = oo->oo_last_closed_stid; | ||
3802 | if (!s) | ||
3803 | return; | ||
3804 | if (!(oo->oo_flags & NFS4_OO_PURGE_CLOSE)) { | ||
3805 | /* Release the last_closed_stid on the next seqid bump: */ | ||
3806 | oo->oo_flags |= NFS4_OO_PURGE_CLOSE; | ||
3807 | return; | ||
3808 | } | ||
3809 | oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE; | ||
3810 | release_last_closed_stateid(oo); | ||
3811 | } | ||
3812 | |||
3813 | static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) | 3817 | static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) |
3814 | { | 3818 | { |
3815 | unhash_open_stateid(s); | 3819 | unhash_open_stateid(s); |
@@ -3838,17 +3842,20 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3838 | &close->cl_stateid, | 3842 | &close->cl_stateid, |
3839 | NFS4_OPEN_STID|NFS4_CLOSED_STID, | 3843 | NFS4_OPEN_STID|NFS4_CLOSED_STID, |
3840 | &stp, nn); | 3844 | &stp, nn); |
3845 | nfsd4_bump_seqid(cstate, status); | ||
3841 | if (status) | 3846 | if (status) |
3842 | goto out; | 3847 | goto out; |
3843 | oo = openowner(stp->st_stateowner); | 3848 | oo = openowner(stp->st_stateowner); |
3844 | status = nfs_ok; | ||
3845 | update_stateid(&stp->st_stid.sc_stateid); | 3849 | update_stateid(&stp->st_stid.sc_stateid); |
3846 | memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 3850 | memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
3847 | 3851 | ||
3848 | nfsd4_close_open_stateid(stp); | 3852 | nfsd4_close_open_stateid(stp); |
3849 | release_last_closed_stateid(oo); | 3853 | |
3850 | oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE; | 3854 | if (cstate->minorversion) { |
3851 | oo->oo_last_closed_stid = stp; | 3855 | unhash_stid(&stp->st_stid); |
3856 | free_generic_stateid(stp); | ||
3857 | } else | ||
3858 | oo->oo_last_closed_stid = stp; | ||
3852 | 3859 | ||
3853 | if (list_empty(&oo->oo_owner.so_stateids)) { | 3860 | if (list_empty(&oo->oo_owner.so_stateids)) { |
3854 | if (cstate->minorversion) { | 3861 | if (cstate->minorversion) { |
@@ -4270,6 +4277,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4270 | out: | 4277 | out: |
4271 | if (status && new_state) | 4278 | if (status && new_state) |
4272 | release_lockowner(lock_sop); | 4279 | release_lockowner(lock_sop); |
4280 | nfsd4_bump_seqid(cstate, status); | ||
4273 | if (!cstate->replay_owner) | 4281 | if (!cstate->replay_owner) |
4274 | nfs4_unlock_state(); | 4282 | nfs4_unlock_state(); |
4275 | if (file_lock) | 4283 | if (file_lock) |
@@ -4439,6 +4447,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4439 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 4447 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
4440 | 4448 | ||
4441 | out: | 4449 | out: |
4450 | nfsd4_bump_seqid(cstate, status); | ||
4442 | if (!cstate->replay_owner) | 4451 | if (!cstate->replay_owner) |
4443 | nfs4_unlock_state(); | 4452 | nfs4_unlock_state(); |
4444 | if (file_lock) | 4453 | if (file_lock) |