aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorBryan Schumaker <bjschuma@netapp.com>2010-10-20 15:44:31 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-10-23 15:27:34 -0400
commitafa8ccc978c24d8ab22e3b3b8cbd1054c84c070b (patch)
tree77a05498dd1decb19f296f0e9f60da0916a40bbd /fs/nfs
parentbabddc72a9468884ce1a23db3c3d54b0afa299f0 (diff)
NFS: remove page size checking code
Remove the page size checking code for a readdir decode. This is now done by decode_dirent with xdr_streams. Signed-off-by: Bryan Schumaker <bjschuma@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs2xdr.c54
-rw-r--r--fs/nfs/nfs3xdr.c78
-rw-r--r--fs/nfs/nfs4xdr.c68
3 files changed, 2 insertions, 198 deletions
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 0210c752e743..82f026422424 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -423,9 +423,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
423 struct page **page; 423 struct page **page;
424 size_t hdrlen; 424 size_t hdrlen;
425 unsigned int pglen, recvd; 425 unsigned int pglen, recvd;
426 u32 len;
427 int status, nr = 0; 426 int status, nr = 0;
428 __be32 *end, *entry, *kaddr;
429 427
430 if ((status = ntohl(*p++))) 428 if ((status = ntohl(*p++)))
431 return nfs_stat_to_errno(status); 429 return nfs_stat_to_errno(status);
@@ -445,59 +443,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
445 if (pglen > recvd) 443 if (pglen > recvd)
446 pglen = recvd; 444 pglen = recvd;
447 page = rcvbuf->pages; 445 page = rcvbuf->pages;
448 kaddr = p = kmap_atomic(*page, KM_USER0);
449 end = (__be32 *)((char *)p + pglen);
450 entry = p;
451
452 /* Make sure the packet actually has a value_follows and EOF entry */
453 if ((entry + 1) > end)
454 goto short_pkt;
455
456 for (; *p++; nr++) {
457 if (p + 2 > end)
458 goto short_pkt;
459 p++; /* fileid */
460 len = ntohl(*p++);
461 p += XDR_QUADLEN(len) + 1; /* name plus cookie */
462 if (len > NFS2_MAXNAMLEN) {
463 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
464 len);
465 goto err_unmap;
466 }
467 if (p + 2 > end)
468 goto short_pkt;
469 entry = p;
470 }
471
472 /*
473 * Apparently some server sends responses that are a valid size, but
474 * contain no entries, and have value_follows==0 and EOF==0. For
475 * those, just set the EOF marker.
476 */
477 if (!nr && entry[1] == 0) {
478 dprintk("NFS: readdir reply truncated!\n");
479 entry[1] = 1;
480 }
481 out:
482 kunmap_atomic(kaddr, KM_USER0);
483 return nr; 446 return nr;
484 short_pkt:
485 /*
486 * When we get a short packet there are 2 possibilities. We can
487 * return an error, or fix up the response to look like a valid
488 * response and return what we have so far. If there are no
489 * entries and the packet was short, then return -EIO. If there
490 * are valid entries in the response, return them and pretend that
491 * the call was successful, but incomplete. The caller can retry the
492 * readdir starting at the last cookie.
493 */
494 entry[0] = entry[1] = 0;
495 if (!nr)
496 nr = -errno_NFSERR_IO;
497 goto out;
498err_unmap:
499 nr = -errno_NFSERR_IO;
500 goto out;
501} 447}
502 448
503static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) 449static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index d562c8d9d56e..dc98eb7976c3 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -554,9 +554,8 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
554 struct kvec *iov = rcvbuf->head; 554 struct kvec *iov = rcvbuf->head;
555 struct page **page; 555 struct page **page;
556 size_t hdrlen; 556 size_t hdrlen;
557 u32 len, recvd, pglen; 557 u32 recvd, pglen;
558 int status, nr = 0; 558 int status, nr = 0;
559 __be32 *entry, *end, *kaddr;
560 559
561 status = ntohl(*p++); 560 status = ntohl(*p++);
562 /* Decode post_op_attrs */ 561 /* Decode post_op_attrs */
@@ -586,83 +585,8 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
586 if (pglen > recvd) 585 if (pglen > recvd)
587 pglen = recvd; 586 pglen = recvd;
588 page = rcvbuf->pages; 587 page = rcvbuf->pages;
589 kaddr = p = kmap_atomic(*page, KM_USER0);
590 end = (__be32 *)((char *)p + pglen);
591 entry = p;
592
593 /* Make sure the packet actually has a value_follows and EOF entry */
594 if ((entry + 1) > end)
595 goto short_pkt;
596
597 for (; *p++; nr++) {
598 if (p + 3 > end)
599 goto short_pkt;
600 p += 2; /* inode # */
601 len = ntohl(*p++); /* string length */
602 p += XDR_QUADLEN(len) + 2; /* name + cookie */
603 if (len > NFS3_MAXNAMLEN) {
604 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
605 len);
606 goto err_unmap;
607 }
608
609 if (res->plus) {
610 /* post_op_attr */
611 if (p + 2 > end)
612 goto short_pkt;
613 if (*p++) {
614 p += 21;
615 if (p + 1 > end)
616 goto short_pkt;
617 }
618 /* post_op_fh3 */
619 if (*p++) {
620 if (p + 1 > end)
621 goto short_pkt;
622 len = ntohl(*p++);
623 if (len > NFS3_FHSIZE) {
624 dprintk("NFS: giant filehandle in "
625 "readdir (len 0x%x)!\n", len);
626 goto err_unmap;
627 }
628 p += XDR_QUADLEN(len);
629 }
630 }
631
632 if (p + 2 > end)
633 goto short_pkt;
634 entry = p;
635 }
636 588
637 /*
638 * Apparently some server sends responses that are a valid size, but
639 * contain no entries, and have value_follows==0 and EOF==0. For
640 * those, just set the EOF marker.
641 */
642 if (!nr && entry[1] == 0) {
643 dprintk("NFS: readdir reply truncated!\n");
644 entry[1] = 1;
645 }
646 out:
647 kunmap_atomic(kaddr, KM_USER0);
648 return nr; 589 return nr;
649 short_pkt:
650 /*
651 * When we get a short packet there are 2 possibilities. We can
652 * return an error, or fix up the response to look like a valid
653 * response and return what we have so far. If there are no
654 * entries and the packet was short, then return -EIO. If there
655 * are valid entries in the response, return them and pretend that
656 * the call was successful, but incomplete. The caller can retry the
657 * readdir starting at the last cookie.
658 */
659 entry[0] = entry[1] = 0;
660 if (!nr)
661 nr = -errno_NFSERR_IO;
662 goto out;
663err_unmap:
664 nr = -errno_NFSERR_IO;
665 goto out;
666} 590}
667 591
668__be32 * 592__be32 *
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index a4919e999354..8346e977d837 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -4200,12 +4200,9 @@ out_overflow:
4200static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) 4200static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
4201{ 4201{
4202 struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 4202 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
4203 struct page *page = *rcvbuf->pages;
4204 struct kvec *iov = rcvbuf->head; 4203 struct kvec *iov = rcvbuf->head;
4205 size_t hdrlen; 4204 size_t hdrlen;
4206 u32 recvd, pglen = rcvbuf->page_len; 4205 u32 recvd, pglen = rcvbuf->page_len;
4207 __be32 *end, *entry, *p, *kaddr;
4208 unsigned int nr = 0;
4209 int status; 4206 int status;
4210 4207
4211 status = decode_op_hdr(xdr, OP_READDIR); 4208 status = decode_op_hdr(xdr, OP_READDIR);
@@ -4225,71 +4222,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
4225 pglen = recvd; 4222 pglen = recvd;
4226 xdr_read_pages(xdr, pglen); 4223 xdr_read_pages(xdr, pglen);
4227 4224
4228 BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE); 4225
4229 kaddr = p = kmap_atomic(page, KM_USER0);
4230 end = p + ((pglen + readdir->pgbase) >> 2);
4231 entry = p;
4232
4233 /* Make sure the packet actually has a value_follows and EOF entry */
4234 if ((entry + 1) > end)
4235 goto short_pkt;
4236
4237 for (; *p++; nr++) {
4238 u32 len, attrlen, xlen;
4239 if (end - p < 3)
4240 goto short_pkt;
4241 dprintk("cookie = %Lu, ", *((unsigned long long *)p));
4242 p += 2; /* cookie */
4243 len = ntohl(*p++); /* filename length */
4244 if (len > NFS4_MAXNAMLEN) {
4245 dprintk("NFS: giant filename in readdir (len 0x%x)\n",
4246 len);
4247 goto err_unmap;
4248 }
4249 xlen = XDR_QUADLEN(len);
4250 if (end - p < xlen + 1)
4251 goto short_pkt;
4252 dprintk("filename = %*s\n", len, (char *)p);
4253 p += xlen;
4254 len = ntohl(*p++); /* bitmap length */
4255 if (end - p < len + 1)
4256 goto short_pkt;
4257 p += len;
4258 attrlen = XDR_QUADLEN(ntohl(*p++));
4259 if (end - p < attrlen + 2)
4260 goto short_pkt;
4261 p += attrlen; /* attributes */
4262 entry = p;
4263 }
4264 /*
4265 * Apparently some server sends responses that are a valid size, but
4266 * contain no entries, and have value_follows==0 and EOF==0. For
4267 * those, just set the EOF marker.
4268 */
4269 if (!nr && entry[1] == 0) {
4270 dprintk("NFS: readdir reply truncated!\n");
4271 entry[1] = 1;
4272 }
4273out:
4274 kunmap_atomic(kaddr, KM_USER0);
4275 return 0; 4226 return 0;
4276short_pkt:
4277 /*
4278 * When we get a short packet there are 2 possibilities. We can
4279 * return an error, or fix up the response to look like a valid
4280 * response and return what we have so far. If there are no
4281 * entries and the packet was short, then return -EIO. If there
4282 * are valid entries in the response, return them and pretend that
4283 * the call was successful, but incomplete. The caller can retry the
4284 * readdir starting at the last cookie.
4285 */
4286 dprintk("%s: short packet at entry %d\n", __func__, nr);
4287 entry[0] = entry[1] = 0;
4288 if (nr)
4289 goto out;
4290err_unmap:
4291 kunmap_atomic(kaddr, KM_USER0);
4292 return -errno_NFSERR_IO;
4293} 4227}
4294 4228
4295static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) 4229static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)