diff options
Diffstat (limited to 'fs/nfs/nfs2xdr.c')
-rw-r--r-- | fs/nfs/nfs2xdr.c | 113 |
1 files changed, 66 insertions, 47 deletions
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 1f7ea675e0c5..28bab67d1519 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -267,7 +267,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
267 | int status; | 267 | int status; |
268 | 268 | ||
269 | if ((status = ntohl(*p++))) | 269 | if ((status = ntohl(*p++))) |
270 | return -nfs_stat_to_errno(status); | 270 | return nfs_stat_to_errno(status); |
271 | p = xdr_decode_fattr(p, res->fattr); | 271 | p = xdr_decode_fattr(p, res->fattr); |
272 | 272 | ||
273 | count = ntohl(*p++); | 273 | count = ntohl(*p++); |
@@ -428,11 +428,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
428 | size_t hdrlen; | 428 | size_t hdrlen; |
429 | unsigned int pglen, recvd; | 429 | unsigned int pglen, recvd; |
430 | u32 len; | 430 | u32 len; |
431 | int status, nr; | 431 | int status, nr = 0; |
432 | __be32 *end, *entry, *kaddr; | 432 | __be32 *end, *entry, *kaddr; |
433 | 433 | ||
434 | if ((status = ntohl(*p++))) | 434 | if ((status = ntohl(*p++))) |
435 | return -nfs_stat_to_errno(status); | 435 | return nfs_stat_to_errno(status); |
436 | 436 | ||
437 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 437 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
438 | if (iov->iov_len < hdrlen) { | 438 | if (iov->iov_len < hdrlen) { |
@@ -452,7 +452,12 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
452 | kaddr = p = kmap_atomic(*page, KM_USER0); | 452 | kaddr = p = kmap_atomic(*page, KM_USER0); |
453 | end = (__be32 *)((char *)p + pglen); | 453 | end = (__be32 *)((char *)p + pglen); |
454 | entry = p; | 454 | entry = p; |
455 | for (nr = 0; *p++; nr++) { | 455 | |
456 | /* Make sure the packet actually has a value_follows and EOF entry */ | ||
457 | if ((entry + 1) > end) | ||
458 | goto short_pkt; | ||
459 | |||
460 | for (; *p++; nr++) { | ||
456 | if (p + 2 > end) | 461 | if (p + 2 > end) |
457 | goto short_pkt; | 462 | goto short_pkt; |
458 | p++; /* fileid */ | 463 | p++; /* fileid */ |
@@ -467,18 +472,32 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
467 | goto short_pkt; | 472 | goto short_pkt; |
468 | entry = p; | 473 | entry = p; |
469 | } | 474 | } |
470 | if (!nr && (entry[0] != 0 || entry[1] == 0)) | 475 | |
471 | goto short_pkt; | 476 | /* |
477 | * Apparently some server sends responses that are a valid size, but | ||
478 | * contain no entries, and have value_follows==0 and EOF==0. For | ||
479 | * those, just set the EOF marker. | ||
480 | */ | ||
481 | if (!nr && entry[1] == 0) { | ||
482 | dprintk("NFS: readdir reply truncated!\n"); | ||
483 | entry[1] = 1; | ||
484 | } | ||
472 | out: | 485 | out: |
473 | kunmap_atomic(kaddr, KM_USER0); | 486 | kunmap_atomic(kaddr, KM_USER0); |
474 | return nr; | 487 | return nr; |
475 | short_pkt: | 488 | short_pkt: |
489 | /* | ||
490 | * When we get a short packet there are 2 possibilities. We can | ||
491 | * return an error, or fix up the response to look like a valid | ||
492 | * response and return what we have so far. If there are no | ||
493 | * entries and the packet was short, then return -EIO. If there | ||
494 | * are valid entries in the response, return them and pretend that | ||
495 | * the call was successful, but incomplete. The caller can retry the | ||
496 | * readdir starting at the last cookie. | ||
497 | */ | ||
476 | entry[0] = entry[1] = 0; | 498 | entry[0] = entry[1] = 0; |
477 | /* truncate listing ? */ | 499 | if (!nr) |
478 | if (!nr) { | 500 | nr = -errno_NFSERR_IO; |
479 | dprintk("NFS: readdir reply truncated!\n"); | ||
480 | entry[1] = 1; | ||
481 | } | ||
482 | goto out; | 501 | goto out; |
483 | err_unmap: | 502 | err_unmap: |
484 | nr = -errno_NFSERR_IO; | 503 | nr = -errno_NFSERR_IO; |
@@ -518,7 +537,7 @@ nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
518 | int status; | 537 | int status; |
519 | 538 | ||
520 | if ((status = ntohl(*p++)) != 0) | 539 | if ((status = ntohl(*p++)) != 0) |
521 | status = -nfs_stat_to_errno(status); | 540 | status = nfs_stat_to_errno(status); |
522 | return status; | 541 | return status; |
523 | } | 542 | } |
524 | 543 | ||
@@ -532,7 +551,7 @@ nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
532 | int status; | 551 | int status; |
533 | 552 | ||
534 | if ((status = ntohl(*p++))) | 553 | if ((status = ntohl(*p++))) |
535 | return -nfs_stat_to_errno(status); | 554 | return nfs_stat_to_errno(status); |
536 | xdr_decode_fattr(p, fattr); | 555 | xdr_decode_fattr(p, fattr); |
537 | return 0; | 556 | return 0; |
538 | } | 557 | } |
@@ -547,7 +566,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res) | |||
547 | int status; | 566 | int status; |
548 | 567 | ||
549 | if ((status = ntohl(*p++))) | 568 | if ((status = ntohl(*p++))) |
550 | return -nfs_stat_to_errno(status); | 569 | return nfs_stat_to_errno(status); |
551 | p = xdr_decode_fhandle(p, res->fh); | 570 | p = xdr_decode_fhandle(p, res->fh); |
552 | xdr_decode_fattr(p, res->fattr); | 571 | xdr_decode_fattr(p, res->fattr); |
553 | return 0; | 572 | return 0; |
@@ -585,7 +604,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
585 | int status; | 604 | int status; |
586 | 605 | ||
587 | if ((status = ntohl(*p++))) | 606 | if ((status = ntohl(*p++))) |
588 | return -nfs_stat_to_errno(status); | 607 | return nfs_stat_to_errno(status); |
589 | /* Convert length of symlink */ | 608 | /* Convert length of symlink */ |
590 | len = ntohl(*p++); | 609 | len = ntohl(*p++); |
591 | if (len >= rcvbuf->page_len) { | 610 | if (len >= rcvbuf->page_len) { |
@@ -634,7 +653,7 @@ nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res) | |||
634 | int status; | 653 | int status; |
635 | 654 | ||
636 | if ((status = ntohl(*p++))) | 655 | if ((status = ntohl(*p++))) |
637 | return -nfs_stat_to_errno(status); | 656 | return nfs_stat_to_errno(status); |
638 | 657 | ||
639 | res->tsize = ntohl(*p++); | 658 | res->tsize = ntohl(*p++); |
640 | res->bsize = ntohl(*p++); | 659 | res->bsize = ntohl(*p++); |
@@ -653,39 +672,39 @@ static struct { | |||
653 | int errno; | 672 | int errno; |
654 | } nfs_errtbl[] = { | 673 | } nfs_errtbl[] = { |
655 | { NFS_OK, 0 }, | 674 | { NFS_OK, 0 }, |
656 | { NFSERR_PERM, EPERM }, | 675 | { NFSERR_PERM, -EPERM }, |
657 | { NFSERR_NOENT, ENOENT }, | 676 | { NFSERR_NOENT, -ENOENT }, |
658 | { NFSERR_IO, errno_NFSERR_IO }, | 677 | { NFSERR_IO, -errno_NFSERR_IO}, |
659 | { NFSERR_NXIO, ENXIO }, | 678 | { NFSERR_NXIO, -ENXIO }, |
660 | /* { NFSERR_EAGAIN, EAGAIN }, */ | 679 | /* { NFSERR_EAGAIN, -EAGAIN }, */ |
661 | { NFSERR_ACCES, EACCES }, | 680 | { NFSERR_ACCES, -EACCES }, |
662 | { NFSERR_EXIST, EEXIST }, | 681 | { NFSERR_EXIST, -EEXIST }, |
663 | { NFSERR_XDEV, EXDEV }, | 682 | { NFSERR_XDEV, -EXDEV }, |
664 | { NFSERR_NODEV, ENODEV }, | 683 | { NFSERR_NODEV, -ENODEV }, |
665 | { NFSERR_NOTDIR, ENOTDIR }, | 684 | { NFSERR_NOTDIR, -ENOTDIR }, |
666 | { NFSERR_ISDIR, EISDIR }, | 685 | { NFSERR_ISDIR, -EISDIR }, |
667 | { NFSERR_INVAL, EINVAL }, | 686 | { NFSERR_INVAL, -EINVAL }, |
668 | { NFSERR_FBIG, EFBIG }, | 687 | { NFSERR_FBIG, -EFBIG }, |
669 | { NFSERR_NOSPC, ENOSPC }, | 688 | { NFSERR_NOSPC, -ENOSPC }, |
670 | { NFSERR_ROFS, EROFS }, | 689 | { NFSERR_ROFS, -EROFS }, |
671 | { NFSERR_MLINK, EMLINK }, | 690 | { NFSERR_MLINK, -EMLINK }, |
672 | { NFSERR_NAMETOOLONG, ENAMETOOLONG }, | 691 | { NFSERR_NAMETOOLONG, -ENAMETOOLONG }, |
673 | { NFSERR_NOTEMPTY, ENOTEMPTY }, | 692 | { NFSERR_NOTEMPTY, -ENOTEMPTY }, |
674 | { NFSERR_DQUOT, EDQUOT }, | 693 | { NFSERR_DQUOT, -EDQUOT }, |
675 | { NFSERR_STALE, ESTALE }, | 694 | { NFSERR_STALE, -ESTALE }, |
676 | { NFSERR_REMOTE, EREMOTE }, | 695 | { NFSERR_REMOTE, -EREMOTE }, |
677 | #ifdef EWFLUSH | 696 | #ifdef EWFLUSH |
678 | { NFSERR_WFLUSH, EWFLUSH }, | 697 | { NFSERR_WFLUSH, -EWFLUSH }, |
679 | #endif | 698 | #endif |
680 | { NFSERR_BADHANDLE, EBADHANDLE }, | 699 | { NFSERR_BADHANDLE, -EBADHANDLE }, |
681 | { NFSERR_NOT_SYNC, ENOTSYNC }, | 700 | { NFSERR_NOT_SYNC, -ENOTSYNC }, |
682 | { NFSERR_BAD_COOKIE, EBADCOOKIE }, | 701 | { NFSERR_BAD_COOKIE, -EBADCOOKIE }, |
683 | { NFSERR_NOTSUPP, ENOTSUPP }, | 702 | { NFSERR_NOTSUPP, -ENOTSUPP }, |
684 | { NFSERR_TOOSMALL, ETOOSMALL }, | 703 | { NFSERR_TOOSMALL, -ETOOSMALL }, |
685 | { NFSERR_SERVERFAULT, ESERVERFAULT }, | 704 | { NFSERR_SERVERFAULT, -ESERVERFAULT }, |
686 | { NFSERR_BADTYPE, EBADTYPE }, | 705 | { NFSERR_BADTYPE, -EBADTYPE }, |
687 | { NFSERR_JUKEBOX, EJUKEBOX }, | 706 | { NFSERR_JUKEBOX, -EJUKEBOX }, |
688 | { -1, EIO } | 707 | { -1, -EIO } |
689 | }; | 708 | }; |
690 | 709 | ||
691 | /* | 710 | /* |