diff options
author | J. Bruce Fields <bfields@citi.umich.edu> | 2010-04-21 12:27:19 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2010-04-22 11:35:14 -0400 |
commit | 5771635592267758e7dc5647f2a0088aa6244159 (patch) | |
tree | 71ffa3a85fe311d5eef591ba69e0bbe7d0b17edc /fs/nfsd/nfs4proc.c | |
parent | 4b21d0defcc9680da8a694e92d5fe8eb668c2c0b (diff) |
nfsd4: complete enforcement of 4.1 op ordering
Enforce the rules about compound op ordering.
Motivated by implementing RECLAIM_COMPLETE, for which the client is
implicit in the current session, so it is important to ensure a
succesful SEQUENCE proceeds the RECLAIM_COMPLETE.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 37514c469846..e147dbcb7ef7 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -968,20 +968,36 @@ static struct nfsd4_operation nfsd4_ops[]; | |||
968 | static const char *nfsd4_op_name(unsigned opnum); | 968 | static const char *nfsd4_op_name(unsigned opnum); |
969 | 969 | ||
970 | /* | 970 | /* |
971 | * Enforce NFSv4.1 COMPOUND ordering rules. | 971 | * Enforce NFSv4.1 COMPOUND ordering rules: |
972 | * | 972 | * |
973 | * TODO: | 973 | * Also note, enforced elsewhere: |
974 | * - enforce NFS4ERR_NOT_ONLY_OP, | 974 | * - SEQUENCE other than as first op results in |
975 | * - DESTROY_SESSION MUST be the final operation in the COMPOUND request. | 975 | * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().) |
976 | * - BIND_CONN_TO_SESSION must be the only op in its compound | ||
977 | * (Will be enforced in nfsd4_bind_conn_to_session().) | ||
978 | * - DESTROY_SESSION must be the final operation in a compound, if | ||
979 | * sessionid's in SEQUENCE and DESTROY_SESSION are the same. | ||
980 | * (Enforced in nfsd4_destroy_session().) | ||
976 | */ | 981 | */ |
977 | static bool nfs41_op_ordering_ok(struct nfsd4_compoundargs *args) | 982 | static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args) |
978 | { | 983 | { |
979 | if (args->minorversion && args->opcnt > 0) { | 984 | struct nfsd4_op *op = &args->ops[0]; |
980 | struct nfsd4_op *op = &args->ops[0]; | 985 | |
981 | return (op->status == nfserr_op_illegal) || | 986 | /* These ordering requirements don't apply to NFSv4.0: */ |
982 | (nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP); | 987 | if (args->minorversion == 0) |
983 | } | 988 | return nfs_ok; |
984 | return true; | 989 | /* This is weird, but OK, not our problem: */ |
990 | if (args->opcnt == 0) | ||
991 | return nfs_ok; | ||
992 | if (op->status == nfserr_op_illegal) | ||
993 | return nfs_ok; | ||
994 | if (!(nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP)) | ||
995 | return nfserr_op_not_in_session; | ||
996 | if (op->opnum == OP_SEQUENCE) | ||
997 | return nfs_ok; | ||
998 | if (args->opcnt != 1) | ||
999 | return nfserr_not_only_op; | ||
1000 | return nfs_ok; | ||
985 | } | 1001 | } |
986 | 1002 | ||
987 | /* | 1003 | /* |
@@ -1023,13 +1039,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1023 | if (args->minorversion > nfsd_supported_minorversion) | 1039 | if (args->minorversion > nfsd_supported_minorversion) |
1024 | goto out; | 1040 | goto out; |
1025 | 1041 | ||
1026 | if (!nfs41_op_ordering_ok(args)) { | 1042 | status = nfs41_check_op_ordering(args); |
1043 | if (status) { | ||
1027 | op = &args->ops[0]; | 1044 | op = &args->ops[0]; |
1028 | op->status = nfserr_sequence_pos; | 1045 | op->status = status; |
1029 | goto encode_op; | 1046 | goto encode_op; |
1030 | } | 1047 | } |
1031 | 1048 | ||
1032 | status = nfs_ok; | ||
1033 | while (!status && resp->opcnt < args->opcnt) { | 1049 | while (!status && resp->opcnt < args->opcnt) { |
1034 | op = &args->ops[resp->opcnt++]; | 1050 | op = &args->ops[resp->opcnt++]; |
1035 | 1051 | ||