Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFSD: Update XDR decoders in NFSv4 callback client

Clean up.

Remove old-style NFSv4 XDR macros in favor of the style now used in
fs/nfs/nfs4xdr.c. These were forgotten during the recent nfs4xdr.c
rewrite.

Additional whitespace cleanup adds to the size of this patch.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Tested-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

authored by

Chuck Lever and committed by
Trond Myklebust
85a56480 a033db48

+239 -176
+239 -176
fs/nfsd/nfs4callback.c
··· 74 74 cb_sequence_dec_sz + \ 75 75 op_dec_sz) 76 76 77 - /* 78 - * Generic decode routines from fs/nfs/nfs4xdr.c 79 - */ 80 - #define DECODE_TAIL \ 81 - status = 0; \ 82 - out: \ 83 - return status; \ 84 - xdr_error: \ 85 - dprintk("NFSD: xdr error! (%s:%d)\n", __FILE__, __LINE__); \ 86 - status = -EIO; \ 87 - goto out 88 - 89 - #define READ32(x) (x) = ntohl(*p++) 90 - #define READ64(x) do { \ 91 - (x) = (u64)ntohl(*p++) << 32; \ 92 - (x) |= ntohl(*p++); \ 93 - } while (0) 94 - #define READTIME(x) do { \ 95 - p++; \ 96 - (x.tv_sec) = ntohl(*p++); \ 97 - (x.tv_nsec) = ntohl(*p++); \ 98 - } while (0) 99 - #define READ_BUF(nbytes) do { \ 100 - p = xdr_inline_decode(xdr, nbytes); \ 101 - if (!p) { \ 102 - dprintk("NFSD: %s: reply buffer overflowed in line %d.\n", \ 103 - __func__, __LINE__); \ 104 - return -EIO; \ 105 - } \ 106 - } while (0) 107 - 108 77 struct nfs4_cb_compound_hdr { 109 78 /* args */ 110 79 u32 ident; /* minorversion 0 only */ ··· 84 115 int status; 85 116 }; 86 117 87 - static struct { 88 - int stat; 89 - int errno; 90 - } nfs_cb_errtbl[] = { 91 - { NFS4_OK, 0 }, 92 - { NFS4ERR_PERM, EPERM }, 93 - { NFS4ERR_NOENT, ENOENT }, 94 - { NFS4ERR_IO, EIO }, 95 - { NFS4ERR_NXIO, ENXIO }, 96 - { NFS4ERR_ACCESS, EACCES }, 97 - { NFS4ERR_EXIST, EEXIST }, 98 - { NFS4ERR_XDEV, EXDEV }, 99 - { NFS4ERR_NOTDIR, ENOTDIR }, 100 - { NFS4ERR_ISDIR, EISDIR }, 101 - { NFS4ERR_INVAL, EINVAL }, 102 - { NFS4ERR_FBIG, EFBIG }, 103 - { NFS4ERR_NOSPC, ENOSPC }, 104 - { NFS4ERR_ROFS, EROFS }, 105 - { NFS4ERR_MLINK, EMLINK }, 106 - { NFS4ERR_NAMETOOLONG, ENAMETOOLONG }, 107 - { NFS4ERR_NOTEMPTY, ENOTEMPTY }, 108 - { NFS4ERR_DQUOT, EDQUOT }, 109 - { NFS4ERR_STALE, ESTALE }, 110 - { NFS4ERR_BADHANDLE, EBADHANDLE }, 111 - { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, 112 - { NFS4ERR_NOTSUPP, ENOTSUPP }, 113 - { NFS4ERR_TOOSMALL, ETOOSMALL }, 114 - { NFS4ERR_SERVERFAULT, ESERVERFAULT }, 115 - { NFS4ERR_BADTYPE, EBADTYPE }, 116 - { NFS4ERR_LOCKED, EAGAIN }, 117 - { NFS4ERR_RESOURCE, EREMOTEIO }, 118 - { NFS4ERR_SYMLINK, ELOOP }, 119 - { NFS4ERR_OP_ILLEGAL, EOPNOTSUPP }, 120 - { NFS4ERR_DEADLOCK, EDEADLK }, 121 - { -1, EIO } 122 - }; 123 - 124 - static int 125 - nfs_cb_stat_to_errno(int stat) 118 + /* 119 + * Handle decode buffer overflows out-of-line. 120 + */ 121 + static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) 126 122 { 127 - int i; 128 - for (i = 0; nfs_cb_errtbl[i].stat != -1; i++) { 129 - if (nfs_cb_errtbl[i].stat == stat) 130 - return nfs_cb_errtbl[i].errno; 131 - } 132 - /* If we cannot translate the error, the recovery routines should 133 - * handle it. 134 - * Note: remaining NFSv4 error codes have values > 10000, so should 135 - * not conflict with native Linux error codes. 136 - */ 137 - return stat; 123 + dprintk("NFS: %s prematurely hit the end of our receive buffer. " 124 + "Remaining buffer length is %tu words.\n", 125 + func, xdr->end - xdr->p); 138 126 } 139 127 140 128 static __be32 *xdr_encode_empty_array(__be32 *p) ··· 189 263 } 190 264 191 265 /* 266 + * nfsstat4 267 + */ 268 + static const struct { 269 + int stat; 270 + int errno; 271 + } nfs_cb_errtbl[] = { 272 + { NFS4_OK, 0 }, 273 + { NFS4ERR_PERM, -EPERM }, 274 + { NFS4ERR_NOENT, -ENOENT }, 275 + { NFS4ERR_IO, -EIO }, 276 + { NFS4ERR_NXIO, -ENXIO }, 277 + { NFS4ERR_ACCESS, -EACCES }, 278 + { NFS4ERR_EXIST, -EEXIST }, 279 + { NFS4ERR_XDEV, -EXDEV }, 280 + { NFS4ERR_NOTDIR, -ENOTDIR }, 281 + { NFS4ERR_ISDIR, -EISDIR }, 282 + { NFS4ERR_INVAL, -EINVAL }, 283 + { NFS4ERR_FBIG, -EFBIG }, 284 + { NFS4ERR_NOSPC, -ENOSPC }, 285 + { NFS4ERR_ROFS, -EROFS }, 286 + { NFS4ERR_MLINK, -EMLINK }, 287 + { NFS4ERR_NAMETOOLONG, -ENAMETOOLONG }, 288 + { NFS4ERR_NOTEMPTY, -ENOTEMPTY }, 289 + { NFS4ERR_DQUOT, -EDQUOT }, 290 + { NFS4ERR_STALE, -ESTALE }, 291 + { NFS4ERR_BADHANDLE, -EBADHANDLE }, 292 + { NFS4ERR_BAD_COOKIE, -EBADCOOKIE }, 293 + { NFS4ERR_NOTSUPP, -ENOTSUPP }, 294 + { NFS4ERR_TOOSMALL, -ETOOSMALL }, 295 + { NFS4ERR_SERVERFAULT, -ESERVERFAULT }, 296 + { NFS4ERR_BADTYPE, -EBADTYPE }, 297 + { NFS4ERR_LOCKED, -EAGAIN }, 298 + { NFS4ERR_RESOURCE, -EREMOTEIO }, 299 + { NFS4ERR_SYMLINK, -ELOOP }, 300 + { NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP }, 301 + { NFS4ERR_DEADLOCK, -EDEADLK }, 302 + { -1, -EIO } 303 + }; 304 + 305 + /* 306 + * If we cannot translate the error, the recovery routines should 307 + * handle it. 308 + * 309 + * Note: remaining NFSv4 error codes have values > 10000, so should 310 + * not conflict with native Linux error codes. 311 + */ 312 + static int nfs_cb_stat_to_errno(int status) 313 + { 314 + int i; 315 + 316 + for (i = 0; nfs_cb_errtbl[i].stat != -1; i++) { 317 + if (nfs_cb_errtbl[i].stat == status) 318 + return nfs_cb_errtbl[i].errno; 319 + } 320 + 321 + dprintk("NFSD: Unrecognized NFS CB status value: %u\n", status); 322 + return -status; 323 + } 324 + 325 + static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected, 326 + enum nfsstat4 *status) 327 + { 328 + __be32 *p; 329 + u32 op; 330 + 331 + p = xdr_inline_decode(xdr, 4 + 4); 332 + if (unlikely(p == NULL)) 333 + goto out_overflow; 334 + op = be32_to_cpup(p++); 335 + if (unlikely(op != expected)) 336 + goto out_unexpected; 337 + *status = be32_to_cpup(p); 338 + return 0; 339 + out_overflow: 340 + print_overflow_msg(__func__, xdr); 341 + return -EIO; 342 + out_unexpected: 343 + dprintk("NFSD: Callback server returned operation %d but " 344 + "we issued a request for %d\n", op, expected); 345 + return -EIO; 346 + } 347 + 348 + /* 192 349 * CB_COMPOUND4args 193 350 * 194 351 * struct CB_COMPOUND4args { ··· 302 293 { 303 294 BUG_ON(hdr->nops > NFS4_MAX_BACK_CHANNEL_OPS); 304 295 *hdr->nops_p = cpu_to_be32(hdr->nops); 296 + } 297 + 298 + /* 299 + * CB_COMPOUND4res 300 + * 301 + * struct CB_COMPOUND4res { 302 + * nfsstat4 status; 303 + * utf8str_cs tag; 304 + * nfs_cb_resop4 resarray<>; 305 + * }; 306 + */ 307 + static int decode_cb_compound4res(struct xdr_stream *xdr, 308 + struct nfs4_cb_compound_hdr *hdr) 309 + { 310 + u32 length; 311 + __be32 *p; 312 + 313 + p = xdr_inline_decode(xdr, 4 + 4); 314 + if (unlikely(p == NULL)) 315 + goto out_overflow; 316 + hdr->status = be32_to_cpup(p++); 317 + /* Ignore the tag */ 318 + length = be32_to_cpup(p++); 319 + p = xdr_inline_decode(xdr, length + 4); 320 + if (unlikely(p == NULL)) 321 + goto out_overflow; 322 + hdr->nops = be32_to_cpup(p); 323 + return 0; 324 + out_overflow: 325 + print_overflow_msg(__func__, xdr); 326 + return -EIO; 305 327 } 306 328 307 329 /* ··· 397 357 } 398 358 399 359 /* 360 + * CB_SEQUENCE4resok 361 + * 362 + * struct CB_SEQUENCE4resok { 363 + * sessionid4 csr_sessionid; 364 + * sequenceid4 csr_sequenceid; 365 + * slotid4 csr_slotid; 366 + * slotid4 csr_highest_slotid; 367 + * slotid4 csr_target_highest_slotid; 368 + * }; 369 + * 370 + * union CB_SEQUENCE4res switch (nfsstat4 csr_status) { 371 + * case NFS4_OK: 372 + * CB_SEQUENCE4resok csr_resok4; 373 + * default: 374 + * void; 375 + * }; 376 + * 377 + * Our current back channel implmentation supports a single backchannel 378 + * with a single slot. 379 + */ 380 + static int decode_cb_sequence4resok(struct xdr_stream *xdr, 381 + struct nfsd4_callback *cb) 382 + { 383 + struct nfsd4_session *session = cb->cb_clp->cl_cb_session; 384 + struct nfs4_sessionid id; 385 + int status; 386 + __be32 *p; 387 + u32 dummy; 388 + 389 + status = -ESERVERFAULT; 390 + 391 + /* 392 + * If the server returns different values for sessionID, slotID or 393 + * sequence number, the server is looney tunes. 394 + */ 395 + p = xdr_inline_decode(xdr, NFS4_MAX_SESSIONID_LEN + 4 + 4); 396 + if (unlikely(p == NULL)) 397 + goto out_overflow; 398 + memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN); 399 + if (memcmp(id.data, session->se_sessionid.data, 400 + NFS4_MAX_SESSIONID_LEN) != 0) { 401 + dprintk("NFS: %s Invalid session id\n", __func__); 402 + goto out; 403 + } 404 + p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN); 405 + 406 + dummy = be32_to_cpup(p++); 407 + if (dummy != session->se_cb_seq_nr) { 408 + dprintk("NFS: %s Invalid sequence number\n", __func__); 409 + goto out; 410 + } 411 + 412 + dummy = be32_to_cpup(p++); 413 + if (dummy != 0) { 414 + dprintk("NFS: %s Invalid slotid\n", __func__); 415 + goto out; 416 + } 417 + 418 + /* 419 + * FIXME: process highest slotid and target highest slotid 420 + */ 421 + status = 0; 422 + out: 423 + return status; 424 + out_overflow: 425 + print_overflow_msg(__func__, xdr); 426 + return -EIO; 427 + } 428 + 429 + static int decode_cb_sequence4res(struct xdr_stream *xdr, 430 + struct nfsd4_callback *cb) 431 + { 432 + enum nfsstat4 nfserr; 433 + int status; 434 + 435 + if (cb->cb_minorversion == 0) 436 + return 0; 437 + 438 + status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &nfserr); 439 + if (unlikely(status)) 440 + goto out; 441 + if (unlikely(nfserr != NFS4_OK)) 442 + goto out_default; 443 + status = decode_cb_sequence4resok(xdr, cb); 444 + out: 445 + return status; 446 + out_default: 447 + return nfs_cb_stat_to_errno(status); 448 + } 449 + 450 + /* 400 451 * NFSv4.0 and NFSv4.1 XDR encode functions 401 452 * 402 453 * NFSv4.0 callback argument types are defined in section 15 of RFC ··· 530 399 } 531 400 532 401 533 - static int 534 - decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){ 535 - __be32 *p; 536 - u32 taglen; 402 + /* 403 + * NFSv4.0 and NFSv4.1 XDR decode functions 404 + * 405 + * NFSv4.0 callback result types are defined in section 15 of RFC 406 + * 3530: "Network File System (NFS) version 4 Protocol" and section 20 407 + * of RFC 5661: "Network File System (NFS) Version 4 Minor Version 1 408 + * Protocol". 409 + */ 537 410 538 - READ_BUF(8); 539 - READ32(hdr->status); 540 - /* We've got no use for the tag; ignore it: */ 541 - READ32(taglen); 542 - READ_BUF(taglen + 4); 543 - p += XDR_QUADLEN(taglen); 544 - READ32(hdr->nops); 545 - return 0; 546 - } 547 - 548 - static int 549 - decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) 411 + static int nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p, void *__unused) 550 412 { 551 - __be32 *p; 552 - u32 op; 553 - int32_t nfserr; 554 - 555 - READ_BUF(8); 556 - READ32(op); 557 - if (op != expected) { 558 - dprintk("NFSD: decode_cb_op_hdr: Callback server returned " 559 - " operation %d but we issued a request for %d\n", 560 - op, expected); 561 - return -EIO; 562 - } 563 - READ32(nfserr); 564 - if (nfserr != NFS_OK) 565 - return -nfs_cb_stat_to_errno(nfserr); 566 413 return 0; 567 414 } 568 415 569 416 /* 570 - * Our current back channel implmentation supports a single backchannel 571 - * with a single slot. 417 + * 20.2. Operation 4: CB_RECALL - Recall a Delegation 572 418 */ 573 - static int 574 - decode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_callback *cb, 575 - struct rpc_rqst *rqstp) 576 - { 577 - struct nfsd4_session *ses = cb->cb_clp->cl_cb_session; 578 - struct nfs4_sessionid id; 579 - int status; 580 - u32 dummy; 581 - __be32 *p; 582 - 583 - if (cb->cb_minorversion == 0) 584 - return 0; 585 - 586 - status = decode_cb_op_hdr(xdr, OP_CB_SEQUENCE); 587 - if (status) 588 - return status; 589 - 590 - /* 591 - * If the server returns different values for sessionID, slotID or 592 - * sequence number, the server is looney tunes. 593 - */ 594 - status = -ESERVERFAULT; 595 - 596 - READ_BUF(NFS4_MAX_SESSIONID_LEN + 16); 597 - memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN); 598 - p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN); 599 - if (memcmp(id.data, ses->se_sessionid.data, NFS4_MAX_SESSIONID_LEN)) { 600 - dprintk("%s Invalid session id\n", __func__); 601 - goto out; 602 - } 603 - READ32(dummy); 604 - if (dummy != ses->se_cb_seq_nr) { 605 - dprintk("%s Invalid sequence number\n", __func__); 606 - goto out; 607 - } 608 - READ32(dummy); /* slotid must be 0 */ 609 - if (dummy != 0) { 610 - dprintk("%s Invalid slotid\n", __func__); 611 - goto out; 612 - } 613 - /* FIXME: process highest slotid and target highest slotid */ 614 - status = 0; 615 - out: 616 - return status; 617 - } 618 - 619 - 620 - static int 621 - nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p) 622 - { 623 - return 0; 624 - } 625 - 626 - static int 627 - nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p, 628 - struct nfsd4_callback *cb) 419 + static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p, 420 + struct nfsd4_callback *cb) 629 421 { 630 422 struct xdr_stream xdr; 631 423 struct nfs4_cb_compound_hdr hdr; 424 + enum nfsstat4 nfserr; 632 425 int status; 633 426 634 427 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); 635 - status = decode_cb_compound_hdr(&xdr, &hdr); 636 - if (status) 428 + status = decode_cb_compound4res(&xdr, &hdr); 429 + if (unlikely(status)) 637 430 goto out; 638 - if (cb) { 639 - status = decode_cb_sequence(&xdr, cb, rqstp); 640 - if (status) 431 + 432 + if (cb != NULL) { 433 + status = decode_cb_sequence4res(&xdr, cb); 434 + if (unlikely(status)) 641 435 goto out; 642 436 } 643 - status = decode_cb_op_hdr(&xdr, OP_CB_RECALL); 437 + 438 + status = decode_cb_op_status(&xdr, OP_CB_RECALL, &nfserr); 439 + if (unlikely(status)) 440 + goto out; 441 + if (unlikely(nfserr != NFS4_OK)) 442 + goto out_default; 644 443 out: 645 444 return status; 445 + out_default: 446 + return nfs_cb_stat_to_errno(status); 646 447 } 647 448 648 449 /*