|
169 | 169 | decode_clone_maxsz + \
|
170 | 170 | decode_getattr_maxsz)
|
171 | 171 |
|
172 |
| -#ifdef CONFIG_NFS_V4_2 |
173 | 172 | /* Not limited by NFS itself, limited by the generic xattr code */
|
174 | 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 +
|
241 | 240 | compound_decode_hdr_maxsz +
|
242 | 241 | decode_sequence_maxsz +
|
243 | 242 | decode_putfh_maxsz + 3) * XDR_UNIT);
|
244 |
| -#endif |
245 | 243 |
|
246 | 244 | static void encode_fallocate(struct xdr_stream *xdr,
|
247 | 245 | const struct nfs42_falloc_args *args)
|
@@ -407,6 +405,210 @@ static void encode_layouterror(struct xdr_stream *xdr,
|
407 | 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 | 613 | * Encode ALLOCATE request
|
412 | 614 | */
|
@@ -1062,4 +1264,166 @@ static int nfs4_xdr_dec_layouterror(struct rpc_rqst *rqstp,
|
1062 | 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 | 1429 | #endif /* __LINUX_FS_NFS_NFS4_2XDR_H */
|
0 commit comments