diff options
| author | Bryan Schumaker <bjschuma@netapp.com> | 2010-10-20 15:44:31 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-10-23 15:27:34 -0400 |
| commit | afa8ccc978c24d8ab22e3b3b8cbd1054c84c070b (patch) | |
| tree | 77a05498dd1decb19f296f0e9f60da0916a40bbd | |
| parent | babddc72a9468884ce1a23db3c3d54b0afa299f0 (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>
| -rw-r--r-- | fs/nfs/nfs2xdr.c | 54 | ||||
| -rw-r--r-- | fs/nfs/nfs3xdr.c | 78 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 68 |
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; | ||
| 498 | err_unmap: | ||
| 499 | nr = -errno_NFSERR_IO; | ||
| 500 | goto out; | ||
| 501 | } | 447 | } |
| 502 | 448 | ||
| 503 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | 449 | static 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; | ||
| 663 | err_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: | |||
| 4200 | static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) | 4200 | static 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 | } | ||
| 4273 | out: | ||
| 4274 | kunmap_atomic(kaddr, KM_USER0); | ||
| 4275 | return 0; | 4226 | return 0; |
| 4276 | short_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; | ||
| 4290 | err_unmap: | ||
| 4291 | kunmap_atomic(kaddr, KM_USER0); | ||
| 4292 | return -errno_NFSERR_IO; | ||
| 4293 | } | 4227 | } |
| 4294 | 4228 | ||
| 4295 | static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) | 4229 | static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) |
