diff options
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 50 |
1 files changed, 36 insertions, 14 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 2ab9e8501bfe..59ec449b0c7f 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -969,20 +969,36 @@ static struct nfsd4_operation nfsd4_ops[]; | |||
969 | static const char *nfsd4_op_name(unsigned opnum); | 969 | static const char *nfsd4_op_name(unsigned opnum); |
970 | 970 | ||
971 | /* | 971 | /* |
972 | * Enforce NFSv4.1 COMPOUND ordering rules. | 972 | * Enforce NFSv4.1 COMPOUND ordering rules: |
973 | * | 973 | * |
974 | * TODO: | 974 | * Also note, enforced elsewhere: |
975 | * - enforce NFS4ERR_NOT_ONLY_OP, | 975 | * - SEQUENCE other than as first op results in |
976 | * - DESTROY_SESSION MUST be the final operation in the COMPOUND request. | 976 | * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().) |
977 | * - BIND_CONN_TO_SESSION must be the only op in its compound | ||
978 | * (Will be enforced in nfsd4_bind_conn_to_session().) | ||
979 | * - DESTROY_SESSION must be the final operation in a compound, if | ||
980 | * sessionid's in SEQUENCE and DESTROY_SESSION are the same. | ||
981 | * (Enforced in nfsd4_destroy_session().) | ||
977 | */ | 982 | */ |
978 | static bool nfs41_op_ordering_ok(struct nfsd4_compoundargs *args) | 983 | static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args) |
979 | { | 984 | { |
980 | if (args->minorversion && args->opcnt > 0) { | 985 | struct nfsd4_op *op = &args->ops[0]; |
981 | struct nfsd4_op *op = &args->ops[0]; | 986 | |
982 | return (op->status == nfserr_op_illegal) || | 987 | /* These ordering requirements don't apply to NFSv4.0: */ |
983 | (nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP); | 988 | if (args->minorversion == 0) |
984 | } | 989 | return nfs_ok; |
985 | return true; | 990 | /* This is weird, but OK, not our problem: */ |
991 | if (args->opcnt == 0) | ||
992 | return nfs_ok; | ||
993 | if (op->status == nfserr_op_illegal) | ||
994 | return nfs_ok; | ||
995 | if (!(nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP)) | ||
996 | return nfserr_op_not_in_session; | ||
997 | if (op->opnum == OP_SEQUENCE) | ||
998 | return nfs_ok; | ||
999 | if (args->opcnt != 1) | ||
1000 | return nfserr_not_only_op; | ||
1001 | return nfs_ok; | ||
986 | } | 1002 | } |
987 | 1003 | ||
988 | /* | 1004 | /* |
@@ -1012,6 +1028,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1012 | resp->rqstp = rqstp; | 1028 | resp->rqstp = rqstp; |
1013 | resp->cstate.minorversion = args->minorversion; | 1029 | resp->cstate.minorversion = args->minorversion; |
1014 | resp->cstate.replay_owner = NULL; | 1030 | resp->cstate.replay_owner = NULL; |
1031 | resp->cstate.session = NULL; | ||
1015 | fh_init(&resp->cstate.current_fh, NFS4_FHSIZE); | 1032 | fh_init(&resp->cstate.current_fh, NFS4_FHSIZE); |
1016 | fh_init(&resp->cstate.save_fh, NFS4_FHSIZE); | 1033 | fh_init(&resp->cstate.save_fh, NFS4_FHSIZE); |
1017 | /* Use the deferral mechanism only for NFSv4.0 compounds */ | 1034 | /* Use the deferral mechanism only for NFSv4.0 compounds */ |
@@ -1024,13 +1041,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1024 | if (args->minorversion > nfsd_supported_minorversion) | 1041 | if (args->minorversion > nfsd_supported_minorversion) |
1025 | goto out; | 1042 | goto out; |
1026 | 1043 | ||
1027 | if (!nfs41_op_ordering_ok(args)) { | 1044 | status = nfs41_check_op_ordering(args); |
1045 | if (status) { | ||
1028 | op = &args->ops[0]; | 1046 | op = &args->ops[0]; |
1029 | op->status = nfserr_sequence_pos; | 1047 | op->status = status; |
1030 | goto encode_op; | 1048 | goto encode_op; |
1031 | } | 1049 | } |
1032 | 1050 | ||
1033 | status = nfs_ok; | ||
1034 | while (!status && resp->opcnt < args->opcnt) { | 1051 | while (!status && resp->opcnt < args->opcnt) { |
1035 | op = &args->ops[resp->opcnt++]; | 1052 | op = &args->ops[resp->opcnt++]; |
1036 | 1053 | ||
@@ -1295,6 +1312,11 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1295 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, | 1312 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, |
1296 | .op_name = "OP_SEQUENCE", | 1313 | .op_name = "OP_SEQUENCE", |
1297 | }, | 1314 | }, |
1315 | [OP_RECLAIM_COMPLETE] = { | ||
1316 | .op_func = (nfsd4op_func)nfsd4_reclaim_complete, | ||
1317 | .op_flags = ALLOWED_WITHOUT_FH, | ||
1318 | .op_name = "OP_RECLAIM_COMPLETE", | ||
1319 | }, | ||
1298 | }; | 1320 | }; |
1299 | 1321 | ||
1300 | static const char *nfsd4_op_name(unsigned opnum) | 1322 | static const char *nfsd4_op_name(unsigned opnum) |