diff options
| author | Benny Halevy <bhalevy@panasas.com> | 2009-04-03 01:28:08 -0400 |
|---|---|---|
| committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-04-03 20:41:16 -0400 |
| commit | b85d4c01b76f6969a085d07a767fa45225cb14be (patch) | |
| tree | 5441d0f6bcec52fab3b81ad4887239ff784c5ad9 | |
| parent | a1bcecd29cdf1670df6908a620add4211c0abb7a (diff) | |
nfsd41: sequence operation
Implement the sequence operation conforming to
http://tools.ietf.org/html/draft-ietf-nfsv4-minorversion1-26
Check for stale clientid (as derived from the sessionid).
Enforce slotid range and exactly-once semantics using
the slotid and seqid.
If everything went well renew the client lease and
mark the slot INPROGRESS.
Add a struct nfsd4_slot pointer to struct nfsd4_compound_state.
To be used for sessions DRC replay.
[nfsd41: rename sequence catchthis to cachethis]
Signed-off-by: Andy Adamson<andros@netapp.com>
[pulled some code to set cstate->slot from "nfsd DRC logic"]
[use sessionid_lock spin lock]
[nfsd41: use bool inuse for slot state]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfsd: add a struct nfsd4_slot pointer to struct nfsd4_compound_state]
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfsd41: add nfsd4_session pointer to nfsd4_compound_state]
[nfsd41: set cstate session]
[nfsd41: use cstate session in nfsd4_sequence]
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[simplify nfsd4_encode_sequence error handling]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
| -rw-r--r-- | fs/nfsd/nfs4state.c | 73 | ||||
| -rw-r--r-- | fs/nfsd/nfs4xdr.c | 33 | ||||
| -rw-r--r-- | include/linux/nfsd/xdr4.h | 13 |
3 files changed, 113 insertions, 6 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 |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index bebf6d249069..8556575480ce 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
| @@ -1113,7 +1113,16 @@ static __be32 | |||
| 1113 | nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, | 1113 | nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, |
| 1114 | struct nfsd4_sequence *seq) | 1114 | struct nfsd4_sequence *seq) |
| 1115 | { | 1115 | { |
| 1116 | return nfserr_opnotsupp; /* stub */ | 1116 | DECODE_HEAD; |
| 1117 | |||
| 1118 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 16); | ||
| 1119 | COPYMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); | ||
| 1120 | READ32(seq->seqid); | ||
| 1121 | READ32(seq->slotid); | ||
| 1122 | READ32(seq->maxslots); | ||
| 1123 | READ32(seq->cachethis); | ||
| 1124 | |||
| 1125 | DECODE_TAIL; | ||
| 1117 | } | 1126 | } |
| 1118 | 1127 | ||
| 1119 | static __be32 | 1128 | static __be32 |
| @@ -2828,8 +2837,26 @@ static __be32 | |||
| 2828 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | 2837 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, |
| 2829 | struct nfsd4_sequence *seq) | 2838 | struct nfsd4_sequence *seq) |
| 2830 | { | 2839 | { |
| 2831 | /* stub */ | 2840 | ENCODE_HEAD; |
| 2832 | return nfserr; | 2841 | |
| 2842 | if (nfserr) | ||
| 2843 | return nfserr; | ||
| 2844 | |||
| 2845 | RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 20); | ||
| 2846 | WRITEMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); | ||
| 2847 | WRITE32(seq->seqid); | ||
| 2848 | WRITE32(seq->slotid); | ||
| 2849 | WRITE32(seq->maxslots); | ||
| 2850 | /* | ||
| 2851 | * FIXME: for now: | ||
| 2852 | * target_maxslots = maxslots | ||
| 2853 | * status_flags = 0 | ||
| 2854 | */ | ||
| 2855 | WRITE32(seq->maxslots); | ||
| 2856 | WRITE32(0); | ||
| 2857 | |||
| 2858 | ADJUST_ARGS(); | ||
| 2859 | return 0; | ||
| 2833 | } | 2860 | } |
| 2834 | 2861 | ||
| 2835 | static __be32 | 2862 | static __be32 |
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index 33ee71e988b4..6e28a041008d 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h | |||
| @@ -48,6 +48,9 @@ struct nfsd4_compound_state { | |||
| 48 | struct svc_fh current_fh; | 48 | struct svc_fh current_fh; |
| 49 | struct svc_fh save_fh; | 49 | struct svc_fh save_fh; |
| 50 | struct nfs4_stateowner *replay_owner; | 50 | struct nfs4_stateowner *replay_owner; |
| 51 | /* For sessions DRC */ | ||
| 52 | struct nfsd4_session *session; | ||
| 53 | struct nfsd4_slot *slot; | ||
| 51 | }; | 54 | }; |
| 52 | 55 | ||
| 53 | struct nfsd4_change_info { | 56 | struct nfsd4_change_info { |
| @@ -358,7 +361,15 @@ struct nfsd4_create_session { | |||
| 358 | }; | 361 | }; |
| 359 | 362 | ||
| 360 | struct nfsd4_sequence { | 363 | struct nfsd4_sequence { |
| 361 | int foo; /* stub */ | 364 | struct nfs4_sessionid sessionid; /* request/response */ |
| 365 | u32 seqid; /* request/response */ | ||
| 366 | u32 slotid; /* request/response */ | ||
| 367 | u32 maxslots; /* request/response */ | ||
| 368 | u32 cachethis; /* request */ | ||
| 369 | #if 0 | ||
| 370 | u32 target_maxslots; /* response */ | ||
| 371 | u32 status_flags; /* response */ | ||
| 372 | #endif /* not yet */ | ||
| 362 | }; | 373 | }; |
| 363 | 374 | ||
| 364 | struct nfsd4_destroy_session { | 375 | struct nfsd4_destroy_session { |
