aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorAndy Adamson <andros@netapp.com>2009-04-03 01:28:01 -0400
committerJ. Bruce Fields <bfields@citi.umich.edu>2009-04-03 20:41:15 -0400
commit0733d21338747483985a5964e852af160d88e429 (patch)
treefb8014cc66d3bfc33e1b7cc6a0da369bccc34cd3 /fs/nfsd
parent069b6ad4bb20abf175ea7875e82e8002154773af (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')
-rw-r--r--fs/nfsd/nfs4state.c142
-rw-r--r--fs/nfsd/nfs4xdr.c147
2 files changed, 284 insertions, 5 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 */
838static void
839nfsd4_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
836nfsd4_exchange_id(struct svc_rqst *rqstp, 852nfsd4_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
951out_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);
965out_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
976out:
977 nfs4_unlock_state();
978error:
979 dprintk("nfsd4_exchange_id returns %d\n", ntohl(status));
980 return status;
841} 981}
842 982
843__be32 983__be32
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 6973d61bedea..bebf6d249069 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -45,6 +45,7 @@
45#include <linux/fs.h> 45#include <linux/fs.h>
46#include <linux/namei.h> 46#include <linux/namei.h>
47#include <linux/vfs.h> 47#include <linux/vfs.h>
48#include <linux/utsname.h>
48#include <linux/sunrpc/xdr.h> 49#include <linux/sunrpc/xdr.h>
49#include <linux/sunrpc/svc.h> 50#include <linux/sunrpc/svc.h>
50#include <linux/sunrpc/clnt.h> 51#include <linux/sunrpc/clnt.h>
@@ -998,9 +999,100 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel
998 999
999static __be32 1000static __be32
1000nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, 1001nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
1001 struct nfsd4_exchange_id *clid) 1002 struct nfsd4_exchange_id *exid)
1002{ 1003{
1003 return nfserr_opnotsupp; /* stub */ 1004 int dummy;
1005 DECODE_HEAD;
1006
1007 READ_BUF(NFS4_VERIFIER_SIZE);
1008 COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE);
1009
1010 READ_BUF(4);
1011 READ32(exid->clname.len);
1012
1013 READ_BUF(exid->clname.len);
1014 SAVEMEM(exid->clname.data, exid->clname.len);
1015
1016 READ_BUF(4);
1017 READ32(exid->flags);
1018
1019 /* Ignore state_protect4_a */
1020 READ_BUF(4);
1021 READ32(exid->spa_how);
1022 switch (exid->spa_how) {
1023 case SP4_NONE:
1024 break;
1025 case SP4_MACH_CRED:
1026 /* spo_must_enforce */
1027 READ_BUF(4);
1028 READ32(dummy);
1029 READ_BUF(dummy * 4);
1030 p += dummy;
1031
1032 /* spo_must_allow */
1033 READ_BUF(4);
1034 READ32(dummy);
1035 READ_BUF(dummy * 4);
1036 p += dummy;
1037 break;
1038 case SP4_SSV:
1039 /* ssp_ops */
1040 READ_BUF(4);
1041 READ32(dummy);
1042 READ_BUF(dummy * 4);
1043 p += dummy;
1044
1045 READ_BUF(4);
1046 READ32(dummy);
1047 READ_BUF(dummy * 4);
1048 p += dummy;
1049
1050 /* ssp_hash_algs<> */
1051 READ_BUF(4);
1052 READ32(dummy);
1053 READ_BUF(dummy);
1054 p += XDR_QUADLEN(dummy);
1055
1056 /* ssp_encr_algs<> */
1057 READ_BUF(4);
1058 READ32(dummy);
1059 READ_BUF(dummy);
1060 p += XDR_QUADLEN(dummy);
1061
1062 /* ssp_window and ssp_num_gss_handles */
1063 READ_BUF(8);
1064 READ32(dummy);
1065 READ32(dummy);
1066 break;
1067 default:
1068 goto xdr_error;
1069 }
1070
1071 /* Ignore Implementation ID */
1072 READ_BUF(4); /* nfs_impl_id4 array length */
1073 READ32(dummy);
1074
1075 if (dummy > 1)
1076 goto xdr_error;
1077
1078 if (dummy == 1) {
1079 /* nii_domain */
1080 READ_BUF(4);
1081 READ32(dummy);
1082 READ_BUF(dummy);
1083 p += XDR_QUADLEN(dummy);
1084
1085 /* nii_name */
1086 READ_BUF(4);
1087 READ32(dummy);
1088 READ_BUF(dummy);
1089 p += XDR_QUADLEN(dummy);
1090
1091 /* nii_date */
1092 READ_BUF(12);
1093 p += 3;
1094 }
1095 DECODE_TAIL;
1004} 1096}
1005 1097
1006static __be32 1098static __be32
@@ -2665,8 +2757,55 @@ static __be32
2665nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, 2757nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr,
2666 struct nfsd4_exchange_id *exid) 2758 struct nfsd4_exchange_id *exid)
2667{ 2759{
2668 /* stub */ 2760 ENCODE_HEAD;
2669 return nfserr; 2761 char *major_id;
2762 char *server_scope;
2763 int major_id_sz;
2764 int server_scope_sz;
2765 uint64_t minor_id = 0;
2766
2767 if (nfserr)
2768 return nfserr;
2769
2770 major_id = utsname()->nodename;
2771 major_id_sz = strlen(major_id);
2772 server_scope = utsname()->nodename;
2773 server_scope_sz = strlen(server_scope);
2774
2775 RESERVE_SPACE(
2776 8 /* eir_clientid */ +
2777 4 /* eir_sequenceid */ +
2778 4 /* eir_flags */ +
2779 4 /* spr_how (SP4_NONE) */ +
2780 8 /* so_minor_id */ +
2781 4 /* so_major_id.len */ +
2782 (XDR_QUADLEN(major_id_sz) * 4) +
2783 4 /* eir_server_scope.len */ +
2784 (XDR_QUADLEN(server_scope_sz) * 4) +
2785 4 /* eir_server_impl_id.count (0) */);
2786
2787 WRITEMEM(&exid->clientid, 8);
2788 WRITE32(exid->seqid);
2789 WRITE32(exid->flags);
2790
2791 /* state_protect4_r. Currently only support SP4_NONE */
2792 BUG_ON(exid->spa_how != SP4_NONE);
2793 WRITE32(exid->spa_how);
2794
2795 /* The server_owner struct */
2796 WRITE64(minor_id); /* Minor id */
2797 /* major id */
2798 WRITE32(major_id_sz);
2799 WRITEMEM(major_id, major_id_sz);
2800
2801 /* Server scope */
2802 WRITE32(server_scope_sz);
2803 WRITEMEM(server_scope, server_scope_sz);
2804
2805 /* Implementation id */
2806 WRITE32(0); /* zero length nfs_impl_id4 array */
2807 ADJUST_ARGS();
2808 return 0;
2670} 2809}
2671 2810
2672static __be32 2811static __be32