diff options
-rw-r--r-- | fs/nfs/nfs4xdr.c | 166 | ||||
-rw-r--r-- | include/linux/sunrpc/xdr.h | 63 |
2 files changed, 135 insertions, 94 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 6b08f6b1addf..80c5b519fd6a 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -958,6 +958,35 @@ static void encode_uint64(struct xdr_stream *xdr, u64 n) | |||
958 | WARN_ON_ONCE(xdr_stream_encode_u64(xdr, n) < 0); | 958 | WARN_ON_ONCE(xdr_stream_encode_u64(xdr, n) < 0); |
959 | } | 959 | } |
960 | 960 | ||
961 | static ssize_t xdr_encode_bitmap4(struct xdr_stream *xdr, | ||
962 | const __u32 *bitmap, size_t len) | ||
963 | { | ||
964 | ssize_t ret; | ||
965 | |||
966 | /* Trim empty words */ | ||
967 | while (len > 0 && bitmap[len-1] == 0) | ||
968 | len--; | ||
969 | ret = xdr_stream_encode_uint32_array(xdr, bitmap, len); | ||
970 | if (WARN_ON_ONCE(ret < 0)) | ||
971 | return ret; | ||
972 | return len; | ||
973 | } | ||
974 | |||
975 | static size_t mask_bitmap4(const __u32 *bitmap, const __u32 *mask, | ||
976 | __u32 *res, size_t len) | ||
977 | { | ||
978 | size_t i; | ||
979 | __u32 tmp; | ||
980 | |||
981 | while (len > 0 && (bitmap[len-1] == 0 || mask[len-1] == 0)) | ||
982 | len--; | ||
983 | for (i = len; i-- > 0;) { | ||
984 | tmp = bitmap[i] & mask[i]; | ||
985 | res[i] = tmp; | ||
986 | } | ||
987 | return len; | ||
988 | } | ||
989 | |||
961 | static void encode_nfs4_seqid(struct xdr_stream *xdr, | 990 | static void encode_nfs4_seqid(struct xdr_stream *xdr, |
962 | const struct nfs_seqid *seqid) | 991 | const struct nfs_seqid *seqid) |
963 | { | 992 | { |
@@ -1200,85 +1229,45 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * | |||
1200 | create->server, create->server->attr_bitmask); | 1229 | create->server, create->server->attr_bitmask); |
1201 | } | 1230 | } |
1202 | 1231 | ||
1203 | static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr) | 1232 | static void encode_getattr(struct xdr_stream *xdr, |
1204 | { | 1233 | const __u32 *bitmap, const __u32 *mask, size_t len, |
1205 | __be32 *p; | 1234 | struct compound_hdr *hdr) |
1206 | |||
1207 | encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr); | ||
1208 | p = reserve_space(xdr, 8); | ||
1209 | *p++ = cpu_to_be32(1); | ||
1210 | *p = cpu_to_be32(bitmap); | ||
1211 | } | ||
1212 | |||
1213 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) | ||
1214 | { | ||
1215 | __be32 *p; | ||
1216 | |||
1217 | encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr); | ||
1218 | p = reserve_space(xdr, 12); | ||
1219 | *p++ = cpu_to_be32(2); | ||
1220 | *p++ = cpu_to_be32(bm0); | ||
1221 | *p = cpu_to_be32(bm1); | ||
1222 | } | ||
1223 | |||
1224 | static void | ||
1225 | encode_getattr_three(struct xdr_stream *xdr, | ||
1226 | uint32_t bm0, uint32_t bm1, uint32_t bm2, | ||
1227 | struct compound_hdr *hdr) | ||
1228 | { | 1235 | { |
1229 | __be32 *p; | 1236 | __u32 masked_bitmap[nfs4_fattr_bitmap_maxsz]; |
1230 | 1237 | ||
1231 | encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr); | 1238 | encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr); |
1232 | if (bm2) { | 1239 | if (mask) { |
1233 | p = reserve_space(xdr, 16); | 1240 | if (WARN_ON_ONCE(len > ARRAY_SIZE(masked_bitmap))) |
1234 | *p++ = cpu_to_be32(3); | 1241 | len = ARRAY_SIZE(masked_bitmap); |
1235 | *p++ = cpu_to_be32(bm0); | 1242 | len = mask_bitmap4(bitmap, mask, masked_bitmap, len); |
1236 | *p++ = cpu_to_be32(bm1); | 1243 | bitmap = masked_bitmap; |
1237 | *p = cpu_to_be32(bm2); | ||
1238 | } else if (bm1) { | ||
1239 | p = reserve_space(xdr, 12); | ||
1240 | *p++ = cpu_to_be32(2); | ||
1241 | *p++ = cpu_to_be32(bm0); | ||
1242 | *p = cpu_to_be32(bm1); | ||
1243 | } else { | ||
1244 | p = reserve_space(xdr, 8); | ||
1245 | *p++ = cpu_to_be32(1); | ||
1246 | *p = cpu_to_be32(bm0); | ||
1247 | } | 1244 | } |
1245 | xdr_encode_bitmap4(xdr, bitmap, len); | ||
1248 | } | 1246 | } |
1249 | 1247 | ||
1250 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) | 1248 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
1251 | { | 1249 | { |
1252 | encode_getattr_three(xdr, bitmask[0] & nfs4_fattr_bitmap[0], | 1250 | encode_getattr(xdr, nfs4_fattr_bitmap, bitmask, |
1253 | bitmask[1] & nfs4_fattr_bitmap[1], | 1251 | ARRAY_SIZE(nfs4_fattr_bitmap), hdr); |
1254 | bitmask[2] & nfs4_fattr_bitmap[2], | ||
1255 | hdr); | ||
1256 | } | 1252 | } |
1257 | 1253 | ||
1258 | static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask, | 1254 | static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask, |
1259 | const u32 *open_bitmap, | 1255 | const u32 *open_bitmap, |
1260 | struct compound_hdr *hdr) | 1256 | struct compound_hdr *hdr) |
1261 | { | 1257 | { |
1262 | encode_getattr_three(xdr, | 1258 | encode_getattr(xdr, open_bitmap, bitmask, 3, hdr); |
1263 | bitmask[0] & open_bitmap[0], | ||
1264 | bitmask[1] & open_bitmap[1], | ||
1265 | bitmask[2] & open_bitmap[2], | ||
1266 | hdr); | ||
1267 | } | 1259 | } |
1268 | 1260 | ||
1269 | static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) | 1261 | static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
1270 | { | 1262 | { |
1271 | encode_getattr_three(xdr, | 1263 | encode_getattr(xdr, nfs4_fsinfo_bitmap, bitmask, |
1272 | bitmask[0] & nfs4_fsinfo_bitmap[0], | 1264 | ARRAY_SIZE(nfs4_fsinfo_bitmap), hdr); |
1273 | bitmask[1] & nfs4_fsinfo_bitmap[1], | ||
1274 | bitmask[2] & nfs4_fsinfo_bitmap[2], | ||
1275 | hdr); | ||
1276 | } | 1265 | } |
1277 | 1266 | ||
1278 | static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) | 1267 | static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
1279 | { | 1268 | { |
1280 | encode_getattr_two(xdr, bitmask[0] & nfs4_fs_locations_bitmap[0], | 1269 | encode_getattr(xdr, nfs4_fs_locations_bitmap, bitmask, |
1281 | bitmask[1] & nfs4_fs_locations_bitmap[1], hdr); | 1270 | ARRAY_SIZE(nfs4_fs_locations_bitmap), hdr); |
1282 | } | 1271 | } |
1283 | 1272 | ||
1284 | static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | 1273 | static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
@@ -2559,13 +2548,17 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
2559 | struct compound_hdr hdr = { | 2548 | struct compound_hdr hdr = { |
2560 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | 2549 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
2561 | }; | 2550 | }; |
2551 | const __u32 nfs4_acl_bitmap[1] = { | ||
2552 | [0] = FATTR4_WORD0_ACL, | ||
2553 | }; | ||
2562 | uint32_t replen; | 2554 | uint32_t replen; |
2563 | 2555 | ||
2564 | encode_compound_hdr(xdr, req, &hdr); | 2556 | encode_compound_hdr(xdr, req, &hdr); |
2565 | encode_sequence(xdr, &args->seq_args, &hdr); | 2557 | encode_sequence(xdr, &args->seq_args, &hdr); |
2566 | encode_putfh(xdr, args->fh, &hdr); | 2558 | encode_putfh(xdr, args->fh, &hdr); |
2567 | replen = hdr.replen + op_decode_hdr_maxsz; | 2559 | replen = hdr.replen + op_decode_hdr_maxsz; |
2568 | encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr); | 2560 | encode_getattr(xdr, nfs4_acl_bitmap, NULL, |
2561 | ARRAY_SIZE(nfs4_acl_bitmap), &hdr); | ||
2569 | 2562 | ||
2570 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, | 2563 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, |
2571 | args->acl_pages, 0, args->acl_len); | 2564 | args->acl_pages, 0, args->acl_len); |
@@ -2644,8 +2637,8 @@ static void nfs4_xdr_enc_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
2644 | encode_compound_hdr(xdr, req, &hdr); | 2637 | encode_compound_hdr(xdr, req, &hdr); |
2645 | encode_sequence(xdr, &args->seq_args, &hdr); | 2638 | encode_sequence(xdr, &args->seq_args, &hdr); |
2646 | encode_putfh(xdr, args->fh, &hdr); | 2639 | encode_putfh(xdr, args->fh, &hdr); |
2647 | encode_getattr_one(xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], | 2640 | encode_getattr(xdr, nfs4_pathconf_bitmap, args->bitmask, |
2648 | &hdr); | 2641 | ARRAY_SIZE(nfs4_pathconf_bitmap), &hdr); |
2649 | encode_nops(&hdr); | 2642 | encode_nops(&hdr); |
2650 | } | 2643 | } |
2651 | 2644 | ||
@@ -2663,8 +2656,8 @@ static void nfs4_xdr_enc_statfs(struct rpc_rqst *req, struct xdr_stream *xdr, | |||
2663 | encode_compound_hdr(xdr, req, &hdr); | 2656 | encode_compound_hdr(xdr, req, &hdr); |
2664 | encode_sequence(xdr, &args->seq_args, &hdr); | 2657 | encode_sequence(xdr, &args->seq_args, &hdr); |
2665 | encode_putfh(xdr, args->fh, &hdr); | 2658 | encode_putfh(xdr, args->fh, &hdr); |
2666 | encode_getattr_two(xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], | 2659 | encode_getattr(xdr, nfs4_statfs_bitmap, args->bitmask, |
2667 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); | 2660 | ARRAY_SIZE(nfs4_statfs_bitmap), &hdr); |
2668 | encode_nops(&hdr); | 2661 | encode_nops(&hdr); |
2669 | } | 2662 | } |
2670 | 2663 | ||
@@ -2684,7 +2677,7 @@ static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req, | |||
2684 | encode_compound_hdr(xdr, req, &hdr); | 2677 | encode_compound_hdr(xdr, req, &hdr); |
2685 | encode_sequence(xdr, &args->seq_args, &hdr); | 2678 | encode_sequence(xdr, &args->seq_args, &hdr); |
2686 | encode_putfh(xdr, args->fhandle, &hdr); | 2679 | encode_putfh(xdr, args->fhandle, &hdr); |
2687 | encode_getattr_three(xdr, bitmask[0], bitmask[1], bitmask[2], &hdr); | 2680 | encode_getattr(xdr, bitmask, NULL, 3, &hdr); |
2688 | encode_nops(&hdr); | 2681 | encode_nops(&hdr); |
2689 | } | 2682 | } |
2690 | 2683 | ||
@@ -3218,34 +3211,27 @@ static int decode_ace(struct xdr_stream *xdr, void *ace) | |||
3218 | return -EIO; | 3211 | return -EIO; |
3219 | } | 3212 | } |
3220 | 3213 | ||
3221 | static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) | 3214 | static ssize_t |
3215 | decode_bitmap4(struct xdr_stream *xdr, uint32_t *bitmap, size_t sz) | ||
3222 | { | 3216 | { |
3223 | uint32_t bmlen; | 3217 | ssize_t ret; |
3224 | __be32 *p; | ||
3225 | |||
3226 | p = xdr_inline_decode(xdr, 4); | ||
3227 | if (unlikely(!p)) | ||
3228 | goto out_overflow; | ||
3229 | bmlen = be32_to_cpup(p); | ||
3230 | 3218 | ||
3231 | bitmap[0] = bitmap[1] = bitmap[2] = 0; | 3219 | ret = xdr_stream_decode_uint32_array(xdr, bitmap, sz); |
3232 | p = xdr_inline_decode(xdr, (bmlen << 2)); | 3220 | if (likely(ret >= 0)) |
3233 | if (unlikely(!p)) | 3221 | return ret; |
3234 | goto out_overflow; | 3222 | if (ret == -EMSGSIZE) |
3235 | if (bmlen > 0) { | 3223 | return sz; |
3236 | bitmap[0] = be32_to_cpup(p++); | ||
3237 | if (bmlen > 1) { | ||
3238 | bitmap[1] = be32_to_cpup(p++); | ||
3239 | if (bmlen > 2) | ||
3240 | bitmap[2] = be32_to_cpup(p); | ||
3241 | } | ||
3242 | } | ||
3243 | return 0; | ||
3244 | out_overflow: | ||
3245 | print_overflow_msg(__func__, xdr); | 3224 | print_overflow_msg(__func__, xdr); |
3246 | return -EIO; | 3225 | return -EIO; |
3247 | } | 3226 | } |
3248 | 3227 | ||
3228 | static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) | ||
3229 | { | ||
3230 | ssize_t ret; | ||
3231 | ret = decode_bitmap4(xdr, bitmap, 3); | ||
3232 | return ret < 0 ? ret : 0; | ||
3233 | } | ||
3234 | |||
3249 | static int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, unsigned int *savep) | 3235 | static int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, unsigned int *savep) |
3250 | { | 3236 | { |
3251 | __be32 *p; | 3237 | __be32 *p; |
@@ -5471,21 +5457,13 @@ decode_savefh(struct xdr_stream *xdr) | |||
5471 | 5457 | ||
5472 | static int decode_setattr(struct xdr_stream *xdr) | 5458 | static int decode_setattr(struct xdr_stream *xdr) |
5473 | { | 5459 | { |
5474 | __be32 *p; | ||
5475 | uint32_t bmlen; | ||
5476 | int status; | 5460 | int status; |
5477 | 5461 | ||
5478 | status = decode_op_hdr(xdr, OP_SETATTR); | 5462 | status = decode_op_hdr(xdr, OP_SETATTR); |
5479 | if (status) | 5463 | if (status) |
5480 | return status; | 5464 | return status; |
5481 | p = xdr_inline_decode(xdr, 4); | 5465 | if (decode_bitmap4(xdr, NULL, 0) >= 0) |
5482 | if (unlikely(!p)) | ||
5483 | goto out_overflow; | ||
5484 | bmlen = be32_to_cpup(p); | ||
5485 | p = xdr_inline_decode(xdr, bmlen << 2); | ||
5486 | if (likely(p)) | ||
5487 | return 0; | 5466 | return 0; |
5488 | out_overflow: | ||
5489 | print_overflow_msg(__func__, xdr); | 5467 | print_overflow_msg(__func__, xdr); |
5490 | return -EIO; | 5468 | return -EIO; |
5491 | } | 5469 | } |
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index a43c3b6455b6..2bd68177a442 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h | |||
@@ -387,6 +387,31 @@ xdr_stream_encode_opaque(struct xdr_stream *xdr, const void *ptr, size_t len) | |||
387 | } | 387 | } |
388 | 388 | ||
389 | /** | 389 | /** |
390 | * xdr_stream_encode_uint32_array - Encode variable length array of integers | ||
391 | * @xdr: pointer to xdr_stream | ||
392 | * @array: array of integers | ||
393 | * @array_size: number of elements in @array | ||
394 | * | ||
395 | * Return values: | ||
396 | * On success, returns length in bytes of XDR buffer consumed | ||
397 | * %-EMSGSIZE on XDR buffer overflow | ||
398 | */ | ||
399 | static inline ssize_t | ||
400 | xdr_stream_encode_uint32_array(struct xdr_stream *xdr, | ||
401 | const __u32 *array, size_t array_size) | ||
402 | { | ||
403 | ssize_t ret = (array_size+1) * sizeof(__u32); | ||
404 | __be32 *p = xdr_reserve_space(xdr, ret); | ||
405 | |||
406 | if (unlikely(!p)) | ||
407 | return -EMSGSIZE; | ||
408 | *p++ = cpu_to_be32(array_size); | ||
409 | for (; array_size > 0; p++, array++, array_size--) | ||
410 | *p = cpu_to_be32p(array); | ||
411 | return ret; | ||
412 | } | ||
413 | |||
414 | /** | ||
390 | * xdr_stream_decode_u32 - Decode a 32-bit integer | 415 | * xdr_stream_decode_u32 - Decode a 32-bit integer |
391 | * @xdr: pointer to xdr_stream | 416 | * @xdr: pointer to xdr_stream |
392 | * @ptr: location to store integer | 417 | * @ptr: location to store integer |
@@ -463,6 +488,44 @@ xdr_stream_decode_opaque_inline(struct xdr_stream *xdr, void **ptr, size_t maxle | |||
463 | } | 488 | } |
464 | return len; | 489 | return len; |
465 | } | 490 | } |
491 | |||
492 | /** | ||
493 | * xdr_stream_decode_uint32_array - Decode variable length array of integers | ||
494 | * @xdr: pointer to xdr_stream | ||
495 | * @array: location to store the integer array or NULL | ||
496 | * @array_size: number of elements to store | ||
497 | * | ||
498 | * Return values: | ||
499 | * On success, returns number of elements stored in @array | ||
500 | * %-EBADMSG on XDR buffer overflow | ||
501 | * %-EMSGSIZE if the size of the array exceeds @array_size | ||
502 | */ | ||
503 | static inline ssize_t | ||
504 | xdr_stream_decode_uint32_array(struct xdr_stream *xdr, | ||
505 | __u32 *array, size_t array_size) | ||
506 | { | ||
507 | __be32 *p; | ||
508 | __u32 len; | ||
509 | ssize_t retval; | ||
510 | |||
511 | if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0)) | ||
512 | return -EBADMSG; | ||
513 | p = xdr_inline_decode(xdr, len * sizeof(*p)); | ||
514 | if (unlikely(!p)) | ||
515 | return -EBADMSG; | ||
516 | if (array == NULL) | ||
517 | return len; | ||
518 | if (len <= array_size) { | ||
519 | if (len < array_size) | ||
520 | memset(array+len, 0, (array_size-len)*sizeof(*array)); | ||
521 | array_size = len; | ||
522 | retval = len; | ||
523 | } else | ||
524 | retval = -EMSGSIZE; | ||
525 | for (; array_size > 0; p++, array++, array_size--) | ||
526 | *array = be32_to_cpup(p); | ||
527 | return retval; | ||
528 | } | ||
466 | #endif /* __KERNEL__ */ | 529 | #endif /* __KERNEL__ */ |
467 | 530 | ||
468 | #endif /* _SUNRPC_XDR_H_ */ | 531 | #endif /* _SUNRPC_XDR_H_ */ |