aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs2xdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs2xdr.c')
-rw-r--r--fs/nfs/nfs2xdr.c113
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;
483err_unmap: 502err_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/*