|
45 | 45 | #define encode_deallocate_maxsz (op_encode_hdr_maxsz + \
|
46 | 46 | encode_fallocate_maxsz)
|
47 | 47 | #define decode_deallocate_maxsz (op_decode_hdr_maxsz)
|
| 48 | +#define encode_read_plus_maxsz (op_encode_hdr_maxsz + \ |
| 49 | + encode_stateid_maxsz + 3) |
| 50 | +#define NFS42_READ_PLUS_SEGMENT_SIZE (1 /* data_content4 */ + \ |
| 51 | + 2 /* data_info4.di_offset */ + \ |
| 52 | + 2 /* data_info4.di_length */) |
| 53 | +#define decode_read_plus_maxsz (op_decode_hdr_maxsz + \ |
| 54 | + 1 /* rpr_eof */ + \ |
| 55 | + 1 /* rpr_contents count */ + \ |
| 56 | + NFS42_READ_PLUS_SEGMENT_SIZE) |
48 | 57 | #define encode_seek_maxsz (op_encode_hdr_maxsz + \
|
49 | 58 | encode_stateid_maxsz + \
|
50 | 59 | 2 /* offset */ + \
|
|
128 | 137 | decode_putfh_maxsz + \
|
129 | 138 | decode_deallocate_maxsz + \
|
130 | 139 | decode_getattr_maxsz)
|
| 140 | +#define NFS4_enc_read_plus_sz (compound_encode_hdr_maxsz + \ |
| 141 | + encode_sequence_maxsz + \ |
| 142 | + encode_putfh_maxsz + \ |
| 143 | + encode_read_plus_maxsz) |
| 144 | +#define NFS4_dec_read_plus_sz (compound_decode_hdr_maxsz + \ |
| 145 | + decode_sequence_maxsz + \ |
| 146 | + decode_putfh_maxsz + \ |
| 147 | + decode_read_plus_maxsz) |
131 | 148 | #define NFS4_enc_seek_sz (compound_encode_hdr_maxsz + \
|
132 | 149 | encode_sequence_maxsz + \
|
133 | 150 | encode_putfh_maxsz + \
|
@@ -324,6 +341,16 @@ static void encode_deallocate(struct xdr_stream *xdr,
|
324 | 341 | encode_fallocate(xdr, args);
|
325 | 342 | }
|
326 | 343 |
|
| 344 | +static void encode_read_plus(struct xdr_stream *xdr, |
| 345 | + const struct nfs_pgio_args *args, |
| 346 | + struct compound_hdr *hdr) |
| 347 | +{ |
| 348 | + encode_op_hdr(xdr, OP_READ_PLUS, decode_read_plus_maxsz, hdr); |
| 349 | + encode_nfs4_stateid(xdr, &args->stateid); |
| 350 | + encode_uint64(xdr, args->offset); |
| 351 | + encode_uint32(xdr, args->count); |
| 352 | +} |
| 353 | + |
327 | 354 | static void encode_seek(struct xdr_stream *xdr,
|
328 | 355 | const struct nfs42_seek_args *args,
|
329 | 356 | struct compound_hdr *hdr)
|
@@ -722,6 +749,28 @@ static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req,
|
722 | 749 | encode_nops(&hdr);
|
723 | 750 | }
|
724 | 751 |
|
| 752 | +/* |
| 753 | + * Encode READ_PLUS request |
| 754 | + */ |
| 755 | +static void nfs4_xdr_enc_read_plus(struct rpc_rqst *req, |
| 756 | + struct xdr_stream *xdr, |
| 757 | + const void *data) |
| 758 | +{ |
| 759 | + const struct nfs_pgio_args *args = data; |
| 760 | + struct compound_hdr hdr = { |
| 761 | + .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| 762 | + }; |
| 763 | + |
| 764 | + encode_compound_hdr(xdr, req, &hdr); |
| 765 | + encode_sequence(xdr, &args->seq_args, &hdr); |
| 766 | + encode_putfh(xdr, args->fh, &hdr); |
| 767 | + encode_read_plus(xdr, args, &hdr); |
| 768 | + |
| 769 | + rpc_prepare_reply_pages(req, args->pages, args->pgbase, |
| 770 | + args->count, hdr.replen); |
| 771 | + encode_nops(&hdr); |
| 772 | +} |
| 773 | + |
725 | 774 | /*
|
726 | 775 | * Encode SEEK request
|
727 | 776 | */
|
@@ -970,6 +1019,71 @@ static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *re
|
970 | 1019 | return decode_op_hdr(xdr, OP_DEALLOCATE);
|
971 | 1020 | }
|
972 | 1021 |
|
| 1022 | +static int decode_read_plus_data(struct xdr_stream *xdr, struct nfs_pgio_res *res, |
| 1023 | + uint32_t *eof) |
| 1024 | +{ |
| 1025 | + uint32_t count, recvd; |
| 1026 | + uint64_t offset; |
| 1027 | + __be32 *p; |
| 1028 | + |
| 1029 | + p = xdr_inline_decode(xdr, 8 + 4); |
| 1030 | + if (unlikely(!p)) |
| 1031 | + return -EIO; |
| 1032 | + |
| 1033 | + p = xdr_decode_hyper(p, &offset); |
| 1034 | + count = be32_to_cpup(p); |
| 1035 | + recvd = xdr_read_pages(xdr, count); |
| 1036 | + res->count += recvd; |
| 1037 | + |
| 1038 | + if (count > recvd) { |
| 1039 | + dprintk("NFS: server cheating in read reply: " |
| 1040 | + "count %u > recvd %u\n", count, recvd); |
| 1041 | + *eof = 0; |
| 1042 | + return 1; |
| 1043 | + } |
| 1044 | + |
| 1045 | + return 0; |
| 1046 | +} |
| 1047 | + |
| 1048 | +static int decode_read_plus(struct xdr_stream *xdr, struct nfs_pgio_res *res) |
| 1049 | +{ |
| 1050 | + uint32_t eof, segments, type; |
| 1051 | + int status; |
| 1052 | + __be32 *p; |
| 1053 | + |
| 1054 | + status = decode_op_hdr(xdr, OP_READ_PLUS); |
| 1055 | + if (status) |
| 1056 | + return status; |
| 1057 | + |
| 1058 | + p = xdr_inline_decode(xdr, 4 + 4); |
| 1059 | + if (unlikely(!p)) |
| 1060 | + return -EIO; |
| 1061 | + |
| 1062 | + eof = be32_to_cpup(p++); |
| 1063 | + segments = be32_to_cpup(p++); |
| 1064 | + if (segments == 0) |
| 1065 | + goto out; |
| 1066 | + |
| 1067 | + p = xdr_inline_decode(xdr, 4); |
| 1068 | + if (unlikely(!p)) |
| 1069 | + return -EIO; |
| 1070 | + |
| 1071 | + type = be32_to_cpup(p++); |
| 1072 | + if (type == NFS4_CONTENT_DATA) |
| 1073 | + status = decode_read_plus_data(xdr, res, &eof); |
| 1074 | + else |
| 1075 | + return -EINVAL; |
| 1076 | + |
| 1077 | + if (status) |
| 1078 | + return status; |
| 1079 | + if (segments > 1) |
| 1080 | + eof = 0; |
| 1081 | + |
| 1082 | +out: |
| 1083 | + res->eof = eof; |
| 1084 | + return 0; |
| 1085 | +} |
| 1086 | + |
973 | 1087 | static int decode_seek(struct xdr_stream *xdr, struct nfs42_seek_res *res)
|
974 | 1088 | {
|
975 | 1089 | int status;
|
@@ -1146,6 +1260,33 @@ static int nfs4_xdr_dec_deallocate(struct rpc_rqst *rqstp,
|
1146 | 1260 | return status;
|
1147 | 1261 | }
|
1148 | 1262 |
|
| 1263 | +/* |
| 1264 | + * Decode READ_PLUS request |
| 1265 | + */ |
| 1266 | +static int nfs4_xdr_dec_read_plus(struct rpc_rqst *rqstp, |
| 1267 | + struct xdr_stream *xdr, |
| 1268 | + void *data) |
| 1269 | +{ |
| 1270 | + struct nfs_pgio_res *res = data; |
| 1271 | + struct compound_hdr hdr; |
| 1272 | + int status; |
| 1273 | + |
| 1274 | + status = decode_compound_hdr(xdr, &hdr); |
| 1275 | + if (status) |
| 1276 | + goto out; |
| 1277 | + status = decode_sequence(xdr, &res->seq_res, rqstp); |
| 1278 | + if (status) |
| 1279 | + goto out; |
| 1280 | + status = decode_putfh(xdr); |
| 1281 | + if (status) |
| 1282 | + goto out; |
| 1283 | + status = decode_read_plus(xdr, res); |
| 1284 | + if (!status) |
| 1285 | + status = res->count; |
| 1286 | +out: |
| 1287 | + return status; |
| 1288 | +} |
| 1289 | + |
1149 | 1290 | /*
|
1150 | 1291 | * Decode SEEK request
|
1151 | 1292 | */
|
|
0 commit comments