| @@ -169,7 +169,6 @@ · 168 unmodified lines |
| 169 | decode_clone_maxsz + \ | 169 | decode_clone_maxsz + \ |
| 170 | decode_getattr_maxsz) | 170 | decode_getattr_maxsz) |
| 171 | | 171 | |
| 172 | #ifdef CONFIG_NFS_V4_2 | | |
| 173 | /* Not limited by NFS itself, limited by the generic xattr code */ | 172 | /* Not limited by NFS itself, limited by the generic xattr code */ |
| 174 | #define nfs4_xattr_name_maxsz XDR_QUADLEN(XATTR_NAME_MAX) | 173 | #define nfs4_xattr_name_maxsz XDR_QUADLEN(XATTR_NAME_MAX) |
| 175 | | 174 | |
| @@ -241,7 +240,6 @@ const u32 nfs42_maxlistxattrs_overhead = ((RPC_MAX_HEADER_WITH_AUTH + · 65 unmodified lines |
| 241 | compound_decode_hdr_maxsz + | 240 | compound_decode_hdr_maxsz + |
| 242 | decode_sequence_maxsz + | 241 | decode_sequence_maxsz + |
| 243 | decode_putfh_maxsz + 3) * XDR_UNIT); | 242 | decode_putfh_maxsz + 3) * XDR_UNIT); |
| 244 | #endif | | |
| 245 | | 243 | |
| 246 | static void encode_fallocate(struct xdr_stream *xdr, | 244 | static void encode_fallocate(struct xdr_stream *xdr, |
| 247 | const struct nfs42_falloc_args *args) | 245 | const struct nfs42_falloc_args *args) |
| @@ -407,6 +405,210 @@ static void encode_layouterror(struct xdr_stream *xdr, · 159 unmodified lines |
| 407 | encode_device_error(xdr, &args->errors[0]); | 405 | encode_device_error(xdr, &args->errors[0]); |
| 408 | } | 406 | } |
| 409 | | 407 | |
| | 408 | static void encode_setxattr(struct xdr_stream *xdr, |
| | 409 | const struct nfs42_setxattrargs *arg, |
| | 410 | struct compound_hdr *hdr) |
| | 411 | { |
| | 412 | __be32 *p; |
| | 413 | |
| | 414 | BUILD_BUG_ON(XATTR_CREATE != SETXATTR4_CREATE); |
| | 415 | BUILD_BUG_ON(XATTR_REPLACE != SETXATTR4_REPLACE); |
| | 416 | |
| | 417 | encode_op_hdr(xdr, OP_SETXATTR, decode_setxattr_maxsz, hdr); |
| | 418 | p = reserve_space(xdr, 4); |
| | 419 | *p = cpu_to_be32(arg->xattr_flags); |
| | 420 | encode_string(xdr, strlen(arg->xattr_name), arg->xattr_name); |
| | 421 | p = reserve_space(xdr, 4); |
| | 422 | *p = cpu_to_be32(arg->xattr_len); |
| | 423 | if (arg->xattr_len) |
| | 424 | xdr_write_pages(xdr, arg->xattr_pages, 0, arg->xattr_len); |
| | 425 | } |
| | 426 | |
| | 427 | static int decode_setxattr(struct xdr_stream *xdr, |
| | 428 | struct nfs4_change_info *cinfo) |
| | 429 | { |
| | 430 | int status; |
| | 431 | |
| | 432 | status = decode_op_hdr(xdr, OP_SETXATTR); |
| | 433 | if (status) |
| | 434 | goto out; |
| | 435 | status = decode_change_info(xdr, cinfo); |
| | 436 | out: |
| | 437 | return status; |
| | 438 | } |
| | 439 | |
| | 440 | |
| | 441 | static void encode_getxattr(struct xdr_stream *xdr, const char *name, |
| | 442 | struct compound_hdr *hdr) |
| | 443 | { |
| | 444 | encode_op_hdr(xdr, OP_GETXATTR, decode_getxattr_maxsz, hdr); |
| | 445 | encode_string(xdr, strlen(name), name); |
| | 446 | } |
| | 447 | |
| | 448 | static int decode_getxattr(struct xdr_stream *xdr, |
| | 449 | struct nfs42_getxattrres *res, |
| | 450 | struct rpc_rqst *req) |
| | 451 | { |
| | 452 | int status; |
| | 453 | __be32 *p; |
| | 454 | u32 len, rdlen; |
| | 455 | |
| | 456 | status = decode_op_hdr(xdr, OP_GETXATTR); |
| | 457 | if (status) |
| | 458 | return status; |
| | 459 | |
| | 460 | p = xdr_inline_decode(xdr, 4); |
| | 461 | if (unlikely(!p)) |
| | 462 | return -EIO; |
| | 463 | |
| | 464 | len = be32_to_cpup(p); |
| | 465 | if (len > req->rq_rcv_buf.page_len) |
| | 466 | return -ERANGE; |
| | 467 | |
| | 468 | res->xattr_len = len; |
| | 469 | |
| | 470 | if (len > 0) { |
| | 471 | rdlen = xdr_read_pages(xdr, len); |
| | 472 | if (rdlen < len) |
| | 473 | return -EIO; |
| | 474 | } |
| | 475 | |
| | 476 | return 0; |
| | 477 | } |
| | 478 | |
| | 479 | static void encode_removexattr(struct xdr_stream *xdr, const char *name, |
| | 480 | struct compound_hdr *hdr) |
| | 481 | { |
| | 482 | encode_op_hdr(xdr, OP_REMOVEXATTR, decode_removexattr_maxsz, hdr); |
| | 483 | encode_string(xdr, strlen(name), name); |
| | 484 | } |
| | 485 | |
| | 486 | |
| | 487 | static int decode_removexattr(struct xdr_stream *xdr, |
| | 488 | struct nfs4_change_info *cinfo) |
| | 489 | { |
| | 490 | int status; |
| | 491 | |
| | 492 | status = decode_op_hdr(xdr, OP_REMOVEXATTR); |
| | 493 | if (status) |
| | 494 | goto out; |
| | 495 | |
| | 496 | status = decode_change_info(xdr, cinfo); |
| | 497 | out: |
| | 498 | return status; |
| | 499 | } |
| | 500 | |
| | 501 | static void encode_listxattrs(struct xdr_stream *xdr, |
| | 502 | const struct nfs42_listxattrsargs *arg, |
| | 503 | struct compound_hdr *hdr) |
| | 504 | { |
| | 505 | __be32 *p; |
| | 506 | |
| | 507 | encode_op_hdr(xdr, OP_LISTXATTRS, decode_listxattrs_maxsz + 1, hdr); |
| | 508 | |
| | 509 | p = reserve_space(xdr, 12); |
| | 510 | if (unlikely(!p)) |
| | 511 | return; |
| | 512 | |
| | 513 | p = xdr_encode_hyper(p, arg->cookie); |
| | 514 | /* |
| | 515 | * RFC 8276 says to specify the full max length of the LISTXATTRS |
| | 516 | * XDR reply. Count is set to the XDR length of the names array |
| | 517 | * plus the EOF marker. So, add the cookie and the names count. |
| | 518 | */ |
| | 519 | *p = cpu_to_be32(arg->count + 8 + 4); |
| | 520 | } |
| | 521 | |
| | 522 | static int decode_listxattrs(struct xdr_stream *xdr, |
| | 523 | struct nfs42_listxattrsres *res) |
| | 524 | { |
| | 525 | int status; |
| | 526 | __be32 *p; |
| | 527 | u32 count, len, ulen; |
| | 528 | size_t left, copied; |
| | 529 | char *buf; |
| | 530 | |
| | 531 | status = decode_op_hdr(xdr, OP_LISTXATTRS); |
| | 532 | if (status) { |
| | 533 | /* |
| | 534 | * Special case: for LISTXATTRS, NFS4ERR_TOOSMALL |
| | 535 | * should be translated to ERANGE. |
| | 536 | */ |
| | 537 | if (status == -ETOOSMALL) |
| | 538 | status = -ERANGE; |
| | 539 | goto out; |
| | 540 | } |
| | 541 | |
| | 542 | p = xdr_inline_decode(xdr, 8); |
| | 543 | if (unlikely(!p)) |
| | 544 | return -EIO; |
| | 545 | |
| | 546 | xdr_decode_hyper(p, &res->cookie); |
| | 547 | |
| | 548 | p = xdr_inline_decode(xdr, 4); |
| | 549 | if (unlikely(!p)) |
| | 550 | return -EIO; |
| | 551 | |
| | 552 | left = res->xattr_len; |
| | 553 | buf = res->xattr_buf; |
| | 554 | |
| | 555 | count = be32_to_cpup(p); |
| | 556 | copied = 0; |
| | 557 | |
| | 558 | /* |
| | 559 | * We have asked for enough room to encode the maximum number |
| | 560 | * of possible attribute names, so everything should fit. |
| | 561 | * |
| | 562 | * But, don't rely on that assumption. Just decode entries |
| | 563 | * until they don't fit anymore, just in case the server did |
| | 564 | * something odd. |
| | 565 | */ |
| | 566 | while (count--) { |
| | 567 | p = xdr_inline_decode(xdr, 4); |
| | 568 | if (unlikely(!p)) |
| | 569 | return -EIO; |
| | 570 | |
| | 571 | len = be32_to_cpup(p); |
| | 572 | if (len > (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) { |
| | 573 | status = -ERANGE; |
| | 574 | goto out; |
| | 575 | } |
| | 576 | |
| | 577 | p = xdr_inline_decode(xdr, len); |
| | 578 | if (unlikely(!p)) |
| | 579 | return -EIO; |
| | 580 | |
| | 581 | ulen = len + XATTR_USER_PREFIX_LEN + 1; |
| | 582 | if (buf) { |
| | 583 | if (ulen > left) { |
| | 584 | status = -ERANGE; |
| | 585 | goto out; |
| | 586 | } |
| | 587 | |
| | 588 | memcpy(buf, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); |
| | 589 | memcpy(buf + XATTR_USER_PREFIX_LEN, p, len); |
| | 590 | |
| | 591 | buf[ulen - 1] = 0; |
| | 592 | buf += ulen; |
| | 593 | left -= ulen; |
| | 594 | } |
| | 595 | copied += ulen; |
| | 596 | } |
| | 597 | |
| | 598 | p = xdr_inline_decode(xdr, 4); |
| | 599 | if (unlikely(!p)) |
| | 600 | return -EIO; |
| | 601 | |
| | 602 | res->eof = be32_to_cpup(p); |
| | 603 | res->copied = copied; |
| | 604 | |
| | 605 | out: |
| | 606 | if (status == -ERANGE && res->xattr_len == XATTR_LIST_MAX) |
| | 607 | status = -E2BIG; |
| | 608 | |
| | 609 | return status; |
| | 610 | } |
| | 611 | |
| 410 | /* | 612 | /* |
| 411 | * Encode ALLOCATE request | 613 | * Encode ALLOCATE request |
| 412 | */ | 614 | */ |
| @@ -1062,4 +1264,166 @@ out: · 649 unmodified lines |
| 1062 | return status; | 1264 | return status; |
| 1063 | } | 1265 | } |
| 1064 | | 1266 | |
| | 1267 | #ifdef CONFIG_NFS_V4_2 |
| | 1268 | static void nfs4_xdr_enc_setxattr(struct rpc_rqst *req, struct xdr_stream *xdr, |
| | 1269 | const void *data) |
| | 1270 | { |
| | 1271 | const struct nfs42_setxattrargs *args = data; |
| | 1272 | struct compound_hdr hdr = { |
| | 1273 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| | 1274 | }; |
| | 1275 | |
| | 1276 | encode_compound_hdr(xdr, req, &hdr); |
| | 1277 | encode_sequence(xdr, &args->seq_args, &hdr); |
| | 1278 | encode_putfh(xdr, args->fh, &hdr); |
| | 1279 | encode_setxattr(xdr, args, &hdr); |
| | 1280 | encode_nops(&hdr); |
| | 1281 | } |
| | 1282 | |
| | 1283 | static int nfs4_xdr_dec_setxattr(struct rpc_rqst *req, struct xdr_stream *xdr, |
| | 1284 | void *data) |
| | 1285 | { |
| | 1286 | struct nfs42_setxattrres *res = data; |
| | 1287 | struct compound_hdr hdr; |
| | 1288 | int status; |
| | 1289 | |
| | 1290 | status = decode_compound_hdr(xdr, &hdr); |
| | 1291 | if (status) |
| | 1292 | goto out; |
| | 1293 | status = decode_sequence(xdr, &res->seq_res, req); |
| | 1294 | if (status) |
| | 1295 | goto out; |
| | 1296 | status = decode_putfh(xdr); |
| | 1297 | if (status) |
| | 1298 | goto out; |
| | 1299 | |
| | 1300 | status = decode_setxattr(xdr, &res->cinfo); |
| | 1301 | out: |
| | 1302 | return status; |
| | 1303 | } |
| | 1304 | |
| | 1305 | static void nfs4_xdr_enc_getxattr(struct rpc_rqst *req, struct xdr_stream *xdr, |
| | 1306 | const void *data) |
| | 1307 | { |
| | 1308 | const struct nfs42_getxattrargs *args = data; |
| | 1309 | struct compound_hdr hdr = { |
| | 1310 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| | 1311 | }; |
| | 1312 | size_t plen; |
| | 1313 | |
| | 1314 | encode_compound_hdr(xdr, req, &hdr); |
| | 1315 | encode_sequence(xdr, &args->seq_args, &hdr); |
| | 1316 | encode_putfh(xdr, args->fh, &hdr); |
| | 1317 | encode_getxattr(xdr, args->xattr_name, &hdr); |
| | 1318 | |
| | 1319 | plen = args->xattr_len ? args->xattr_len : XATTR_SIZE_MAX; |
| | 1320 | |
| | 1321 | rpc_prepare_reply_pages(req, args->xattr_pages, 0, plen, |
| | 1322 | hdr.replen); |
| | 1323 | req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES; |
| | 1324 | |
| | 1325 | encode_nops(&hdr); |
| | 1326 | } |
| | 1327 | |
| | 1328 | static int nfs4_xdr_dec_getxattr(struct rpc_rqst *rqstp, |
| | 1329 | struct xdr_stream *xdr, void *data) |
| | 1330 | { |
| | 1331 | struct nfs42_getxattrres *res = data; |
| | 1332 | struct compound_hdr hdr; |
| | 1333 | int status; |
| | 1334 | |
| | 1335 | status = decode_compound_hdr(xdr, &hdr); |
| | 1336 | if (status) |
| | 1337 | goto out; |
| | 1338 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
| | 1339 | if (status) |
| | 1340 | goto out; |
| | 1341 | status = decode_putfh(xdr); |
| | 1342 | if (status) |
| | 1343 | goto out; |
| | 1344 | status = decode_getxattr(xdr, res, rqstp); |
| | 1345 | out: |
| | 1346 | return status; |
| | 1347 | } |
| | 1348 | |
| | 1349 | static void nfs4_xdr_enc_listxattrs(struct rpc_rqst *req, |
| | 1350 | struct xdr_stream *xdr, const void *data) |
| | 1351 | { |
| | 1352 | const struct nfs42_listxattrsargs *args = data; |
| | 1353 | struct compound_hdr hdr = { |
| | 1354 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| | 1355 | }; |
| | 1356 | |
| | 1357 | encode_compound_hdr(xdr, req, &hdr); |
| | 1358 | encode_sequence(xdr, &args->seq_args, &hdr); |
| | 1359 | encode_putfh(xdr, args->fh, &hdr); |
| | 1360 | encode_listxattrs(xdr, args, &hdr); |
| | 1361 | |
| | 1362 | rpc_prepare_reply_pages(req, args->xattr_pages, 0, args->count, |
| | 1363 | hdr.replen); |
| | 1364 | req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES; |
| | 1365 | |
| | 1366 | encode_nops(&hdr); |
| | 1367 | } |
| | 1368 | |
| | 1369 | static int nfs4_xdr_dec_listxattrs(struct rpc_rqst *rqstp, |
| | 1370 | struct xdr_stream *xdr, void *data) |
| | 1371 | { |
| | 1372 | struct nfs42_listxattrsres *res = data; |
| | 1373 | struct compound_hdr hdr; |
| | 1374 | int status; |
| | 1375 | |
| | 1376 | xdr_set_scratch_buffer(xdr, page_address(res->scratch), PAGE_SIZE); |
| | 1377 | |
| | 1378 | status = decode_compound_hdr(xdr, &hdr); |
| | 1379 | if (status) |
| | 1380 | goto out; |
| | 1381 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
| | 1382 | if (status) |
| | 1383 | goto out; |
| | 1384 | status = decode_putfh(xdr); |
| | 1385 | if (status) |
| | 1386 | goto out; |
| | 1387 | status = decode_listxattrs(xdr, res); |
| | 1388 | out: |
| | 1389 | return status; |
| | 1390 | } |
| | 1391 | |
| | 1392 | static void nfs4_xdr_enc_removexattr(struct rpc_rqst *req, |
| | 1393 | struct xdr_stream *xdr, const void *data) |
| | 1394 | { |
| | 1395 | const struct nfs42_removexattrargs *args = data; |
| | 1396 | struct compound_hdr hdr = { |
| | 1397 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
| | 1398 | }; |
| | 1399 | |
| | 1400 | encode_compound_hdr(xdr, req, &hdr); |
| | 1401 | encode_sequence(xdr, &args->seq_args, &hdr); |
| | 1402 | encode_putfh(xdr, args->fh, &hdr); |
| | 1403 | encode_removexattr(xdr, args->xattr_name, &hdr); |
| | 1404 | encode_nops(&hdr); |
| | 1405 | } |
| | 1406 | |
| | 1407 | static int nfs4_xdr_dec_removexattr(struct rpc_rqst *req, |
| | 1408 | struct xdr_stream *xdr, void *data) |
| | 1409 | { |
| | 1410 | struct nfs42_removexattrres *res = data; |
| | 1411 | struct compound_hdr hdr; |
| | 1412 | int status; |
| | 1413 | |
| | 1414 | status = decode_compound_hdr(xdr, &hdr); |
| | 1415 | if (status) |
| | 1416 | goto out; |
| | 1417 | status = decode_sequence(xdr, &res->seq_res, req); |
| | 1418 | if (status) |
| | 1419 | goto out; |
| | 1420 | status = decode_putfh(xdr); |
| | 1421 | if (status) |
| | 1422 | goto out; |
| | 1423 | |
| | 1424 | status = decode_removexattr(xdr, &res->cinfo); |
| | 1425 | out: |
| | 1426 | return status; |
| | 1427 | } |
| | 1428 | #endif |
| 1065 | #endif /* __LINUX_FS_NFS_NFS4_2XDR_H */ | 1429 | #endif /* __LINUX_FS_NFS_NFS4_2XDR_H */ |