diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 73 |
1 files changed, 71 insertions, 2 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index dfc6d946cdfe..24b6e0593184 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1000,6 +1000,32 @@ error: | |||
1000 | return status; | 1000 | return status; |
1001 | } | 1001 | } |
1002 | 1002 | ||
1003 | static int | ||
1004 | check_slot_seqid(u32 seqid, struct nfsd4_slot *slot) | ||
1005 | { | ||
1006 | dprintk("%s enter. seqid %d slot->sl_seqid %d\n", __func__, seqid, | ||
1007 | slot->sl_seqid); | ||
1008 | |||
1009 | /* The slot is in use, and no response has been sent. */ | ||
1010 | if (slot->sl_inuse) { | ||
1011 | if (seqid == slot->sl_seqid) | ||
1012 | return nfserr_jukebox; | ||
1013 | else | ||
1014 | return nfserr_seq_misordered; | ||
1015 | } | ||
1016 | /* Normal */ | ||
1017 | if (likely(seqid == slot->sl_seqid + 1)) | ||
1018 | return nfs_ok; | ||
1019 | /* Replay */ | ||
1020 | if (seqid == slot->sl_seqid) | ||
1021 | return nfserr_replay_cache; | ||
1022 | /* Wraparound */ | ||
1023 | if (seqid == 1 && (slot->sl_seqid + 1) == 0) | ||
1024 | return nfs_ok; | ||
1025 | /* Misordered replay or misordered new request */ | ||
1026 | return nfserr_seq_misordered; | ||
1027 | } | ||
1028 | |||
1003 | __be32 | 1029 | __be32 |
1004 | nfsd4_create_session(struct svc_rqst *rqstp, | 1030 | nfsd4_create_session(struct svc_rqst *rqstp, |
1005 | struct nfsd4_compound_state *cstate, | 1031 | struct nfsd4_compound_state *cstate, |
@@ -1017,11 +1043,54 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1017 | } | 1043 | } |
1018 | 1044 | ||
1019 | __be32 | 1045 | __be32 |
1020 | nfsd4_sequence(struct svc_rqst *r, | 1046 | nfsd4_sequence(struct svc_rqst *rqstp, |
1021 | struct nfsd4_compound_state *cstate, | 1047 | struct nfsd4_compound_state *cstate, |
1022 | struct nfsd4_sequence *seq) | 1048 | struct nfsd4_sequence *seq) |
1023 | { | 1049 | { |
1024 | return -1; /* stub */ | 1050 | struct nfsd4_session *session; |
1051 | struct nfsd4_slot *slot; | ||
1052 | int status; | ||
1053 | |||
1054 | spin_lock(&sessionid_lock); | ||
1055 | status = nfserr_badsession; | ||
1056 | session = find_in_sessionid_hashtbl(&seq->sessionid); | ||
1057 | if (!session) | ||
1058 | goto out; | ||
1059 | |||
1060 | status = nfserr_badslot; | ||
1061 | if (seq->slotid >= session->se_fnumslots) | ||
1062 | goto out; | ||
1063 | |||
1064 | slot = &session->se_slots[seq->slotid]; | ||
1065 | dprintk("%s: slotid %d\n", __func__, seq->slotid); | ||
1066 | |||
1067 | status = check_slot_seqid(seq->seqid, slot); | ||
1068 | if (status == nfserr_replay_cache) { | ||
1069 | cstate->slot = slot; | ||
1070 | cstate->session = session; | ||
1071 | goto replay_cache; | ||
1072 | } | ||
1073 | if (status) | ||
1074 | goto out; | ||
1075 | |||
1076 | /* Success! bump slot seqid */ | ||
1077 | slot->sl_inuse = true; | ||
1078 | slot->sl_seqid = seq->seqid; | ||
1079 | |||
1080 | cstate->slot = slot; | ||
1081 | cstate->session = session; | ||
1082 | |||
1083 | replay_cache: | ||
1084 | /* Renew the clientid on success and on replay. | ||
1085 | * Hold a session reference until done processing the compound: | ||
1086 | * nfsd4_put_session called only if the cstate slot is set. | ||
1087 | */ | ||
1088 | renew_client(session->se_client); | ||
1089 | nfsd4_get_session(session); | ||
1090 | out: | ||
1091 | spin_unlock(&sessionid_lock); | ||
1092 | dprintk("%s: return %d\n", __func__, ntohl(status)); | ||
1093 | return status; | ||
1025 | } | 1094 | } |
1026 | 1095 | ||
1027 | __be32 | 1096 | __be32 |