diff options
author | Andy Adamson <andros@netapp.com> | 2009-04-03 01:28:01 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-04-03 20:41:15 -0400 |
commit | 0733d21338747483985a5964e852af160d88e429 (patch) | |
tree | fb8014cc66d3bfc33e1b7cc6a0da369bccc34cd3 /fs/nfsd/nfs4state.c | |
parent | 069b6ad4bb20abf175ea7875e82e8002154773af (diff) |
nfsd41: exchange_id operation
Implement the exchange_id operation confoming to
http://tools.ietf.org/html/draft-ietf-nfsv4-minorversion1-28
Based on the client provided name, hash a client id.
If a confirmed one is found, compare the op's creds and
verifier. If the creds match and the verifier is different
then expire the old client (client re-incarnated), otherwise,
if both match, assume it's a replay and ignore it.
If an unconfirmed client is found, then copy the new creds
and verifer if need update, otherwise assume replay.
The client is moved to a confirmed state on create_session.
In the nfs41 branch set the exchange_id flags to
EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_SUPP_MOVED_REFER
(pNFS is not supported, Referrals are supported,
Migration is not.).
Address various scenarios from section 18.35 of the spec:
1. Check for EXCHGID4_FLAG_UPD_CONFIRMED_REC_A and set
EXCHGID4_FLAG_CONFIRMED_R as appropriate.
2. Return error codes per 18.35.4 scenarios.
3. Update client records or generate new client ids depending on
scenario.
Note: 18.35.4 case 3 probably still needs revisiting. The handling
seems not quite right.
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: Andy Adamosn <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfsd41: use utsname for major_id (and copy to server_scope)]
[nfsd41: fix handling of various exchange id scenarios]
Signed-off-by: Mike Sager <sager@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfsd41: reverse use of EXCHGID4_INVAL_FLAG_MASK_A]
[simplify nfsd4_encode_exchange_id error handling]
[nfsd41: embed an xdr_netobj in nfsd4_exchange_id]
[nfsd41: return nfserr_serverfault for spa_how == SP4_MACH_CRED]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 142 |
1 files changed, 141 insertions, 1 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index cfc01f415d15..4f963e902972 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -832,12 +832,152 @@ out_err: | |||
832 | return; | 832 | return; |
833 | } | 833 | } |
834 | 834 | ||
835 | /* | ||
836 | * Set the exchange_id flags returned by the server. | ||
837 | */ | ||
838 | static void | ||
839 | nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) | ||
840 | { | ||
841 | /* pNFS is not supported */ | ||
842 | new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; | ||
843 | |||
844 | /* Referrals are supported, Migration is not. */ | ||
845 | new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; | ||
846 | |||
847 | /* set the wire flags to return to client. */ | ||
848 | clid->flags = new->cl_exchange_flags; | ||
849 | } | ||
850 | |||
835 | __be32 | 851 | __be32 |
836 | nfsd4_exchange_id(struct svc_rqst *rqstp, | 852 | nfsd4_exchange_id(struct svc_rqst *rqstp, |
837 | struct nfsd4_compound_state *cstate, | 853 | struct nfsd4_compound_state *cstate, |
838 | struct nfsd4_exchange_id *exid) | 854 | struct nfsd4_exchange_id *exid) |
839 | { | 855 | { |
840 | return -1; /* stub */ | 856 | struct nfs4_client *unconf, *conf, *new; |
857 | int status; | ||
858 | unsigned int strhashval; | ||
859 | char dname[HEXDIR_LEN]; | ||
860 | nfs4_verifier verf = exid->verifier; | ||
861 | u32 ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr; | ||
862 | |||
863 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " | ||
864 | " ip_addr=%u flags %x, spa_how %d\n", | ||
865 | __func__, rqstp, exid, exid->clname.len, exid->clname.data, | ||
866 | ip_addr, exid->flags, exid->spa_how); | ||
867 | |||
868 | if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A)) | ||
869 | return nfserr_inval; | ||
870 | |||
871 | /* Currently only support SP4_NONE */ | ||
872 | switch (exid->spa_how) { | ||
873 | case SP4_NONE: | ||
874 | break; | ||
875 | case SP4_SSV: | ||
876 | return nfserr_encr_alg_unsupp; | ||
877 | default: | ||
878 | BUG(); /* checked by xdr code */ | ||
879 | case SP4_MACH_CRED: | ||
880 | return nfserr_serverfault; /* no excuse :-/ */ | ||
881 | } | ||
882 | |||
883 | status = nfs4_make_rec_clidname(dname, &exid->clname); | ||
884 | |||
885 | if (status) | ||
886 | goto error; | ||
887 | |||
888 | strhashval = clientstr_hashval(dname); | ||
889 | |||
890 | nfs4_lock_state(); | ||
891 | status = nfs_ok; | ||
892 | |||
893 | conf = find_confirmed_client_by_str(dname, strhashval); | ||
894 | if (conf) { | ||
895 | if (!same_verf(&verf, &conf->cl_verifier)) { | ||
896 | /* 18.35.4 case 8 */ | ||
897 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | ||
898 | status = nfserr_not_same; | ||
899 | goto out; | ||
900 | } | ||
901 | /* Client reboot: destroy old state */ | ||
902 | expire_client(conf); | ||
903 | goto out_new; | ||
904 | } | ||
905 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | ||
906 | /* 18.35.4 case 9 */ | ||
907 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | ||
908 | status = nfserr_perm; | ||
909 | goto out; | ||
910 | } | ||
911 | expire_client(conf); | ||
912 | goto out_new; | ||
913 | } | ||
914 | if (ip_addr != conf->cl_addr && | ||
915 | !(exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A)) { | ||
916 | /* Client collision. 18.35.4 case 3 */ | ||
917 | status = nfserr_clid_inuse; | ||
918 | goto out; | ||
919 | } | ||
920 | /* | ||
921 | * Set bit when the owner id and verifier map to an already | ||
922 | * confirmed client id (18.35.3). | ||
923 | */ | ||
924 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; | ||
925 | |||
926 | /* | ||
927 | * Falling into 18.35.4 case 2, possible router replay. | ||
928 | * Leave confirmed record intact and return same result. | ||
929 | */ | ||
930 | copy_verf(conf, &verf); | ||
931 | new = conf; | ||
932 | goto out_copy; | ||
933 | } else { | ||
934 | /* 18.35.4 case 7 */ | ||
935 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | ||
936 | status = nfserr_noent; | ||
937 | goto out; | ||
938 | } | ||
939 | } | ||
940 | |||
941 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | ||
942 | if (unconf) { | ||
943 | /* | ||
944 | * Possible retry or client restart. Per 18.35.4 case 4, | ||
945 | * a new unconfirmed record should be generated regardless | ||
946 | * of whether any properties have changed. | ||
947 | */ | ||
948 | expire_client(unconf); | ||
949 | } | ||
950 | |||
951 | out_new: | ||
952 | /* Normal case */ | ||
953 | new = create_client(exid->clname, dname); | ||
954 | if (new == NULL) { | ||
955 | status = nfserr_resource; | ||
956 | goto out; | ||
957 | } | ||
958 | |||
959 | copy_verf(new, &verf); | ||
960 | copy_cred(&new->cl_cred, &rqstp->rq_cred); | ||
961 | new->cl_addr = ip_addr; | ||
962 | gen_clid(new); | ||
963 | gen_confirm(new); | ||
964 | add_to_unconfirmed(new, strhashval); | ||
965 | out_copy: | ||
966 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; | ||
967 | exid->clientid.cl_id = new->cl_clientid.cl_id; | ||
968 | |||
969 | new->cl_seqid = exid->seqid = 1; | ||
970 | nfsd4_set_ex_flags(new, exid); | ||
971 | |||
972 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", | ||
973 | new->cl_seqid, new->cl_exchange_flags); | ||
974 | status = nfs_ok; | ||
975 | |||
976 | out: | ||
977 | nfs4_unlock_state(); | ||
978 | error: | ||
979 | dprintk("nfsd4_exchange_id returns %d\n", ntohl(status)); | ||
980 | return status; | ||
841 | } | 981 | } |
842 | 982 | ||
843 | __be32 | 983 | __be32 |