aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/dir.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2011-01-08 17:45:38 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2011-01-10 14:45:01 -0500
commit6650239a4b01077e80d5a4468562756d77afaa59 (patch)
tree505c9a1dc26c26608ce6a5981093a6357d4f3638 /fs/nfs/dir.c
parent3c0eee3fe6a3a1c745379547c7e7c904aa64f6d5 (diff)
NFS: Don't use vm_map_ram() in readdir
vm_map_ram() is not available on NOMMU platforms, and causes trouble on incoherrent architectures such as ARM when we access the page data through both the direct and the virtual mapping. The alternative is to use the direct mapping to access page data for the case when we are not crossing a page boundary, but to copy the data into a linear scratch buffer when we are accessing data that spans page boundaries. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Tested-by: Marc Kleine-Budde <mkl@pengutronix.de> Cc: stable@kernel.org [2.6.37]
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r--fs/nfs/dir.c44
1 files changed, 21 insertions, 23 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 996dd8989a91..0108cf4f3403 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -33,7 +33,6 @@
33#include <linux/namei.h> 33#include <linux/namei.h>
34#include <linux/mount.h> 34#include <linux/mount.h>
35#include <linux/sched.h> 35#include <linux/sched.h>
36#include <linux/vmalloc.h>
37#include <linux/kmemleak.h> 36#include <linux/kmemleak.h>
38 37
39#include "delegation.h" 38#include "delegation.h"
@@ -459,25 +458,26 @@ out:
459/* Perform conversion from xdr to cache array */ 458/* Perform conversion from xdr to cache array */
460static 459static
461int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, 460int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
462 void *xdr_page, struct page *page, unsigned int buflen) 461 struct page **xdr_pages, struct page *page, unsigned int buflen)
463{ 462{
464 struct xdr_stream stream; 463 struct xdr_stream stream;
465 struct xdr_buf buf; 464 struct xdr_buf buf = {
466 __be32 *ptr = xdr_page; 465 .pages = xdr_pages,
466 .page_len = buflen,
467 .buflen = buflen,
468 .len = buflen,
469 };
470 struct page *scratch;
467 struct nfs_cache_array *array; 471 struct nfs_cache_array *array;
468 unsigned int count = 0; 472 unsigned int count = 0;
469 int status; 473 int status;
470 474
471 buf.head->iov_base = xdr_page; 475 scratch = alloc_page(GFP_KERNEL);
472 buf.head->iov_len = buflen; 476 if (scratch == NULL)
473 buf.tail->iov_len = 0; 477 return -ENOMEM;
474 buf.page_base = 0;
475 buf.page_len = 0;
476 buf.buflen = buf.head->iov_len;
477 buf.len = buf.head->iov_len;
478
479 xdr_init_decode(&stream, &buf, ptr);
480 478
479 xdr_init_decode(&stream, &buf, NULL);
480 xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
481 481
482 do { 482 do {
483 status = xdr_decode(desc, entry, &stream); 483 status = xdr_decode(desc, entry, &stream);
@@ -506,6 +506,8 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
506 } else 506 } else
507 status = PTR_ERR(array); 507 status = PTR_ERR(array);
508 } 508 }
509
510 put_page(scratch);
509 return status; 511 return status;
510} 512}
511 513
@@ -521,7 +523,6 @@ static
521void nfs_readdir_free_large_page(void *ptr, struct page **pages, 523void nfs_readdir_free_large_page(void *ptr, struct page **pages,
522 unsigned int npages) 524 unsigned int npages)
523{ 525{
524 vm_unmap_ram(ptr, npages);
525 nfs_readdir_free_pagearray(pages, npages); 526 nfs_readdir_free_pagearray(pages, npages);
526} 527}
527 528
@@ -530,9 +531,8 @@ void nfs_readdir_free_large_page(void *ptr, struct page **pages,
530 * to nfs_readdir_free_large_page 531 * to nfs_readdir_free_large_page
531 */ 532 */
532static 533static
533void *nfs_readdir_large_page(struct page **pages, unsigned int npages) 534int nfs_readdir_large_page(struct page **pages, unsigned int npages)
534{ 535{
535 void *ptr;
536 unsigned int i; 536 unsigned int i;
537 537
538 for (i = 0; i < npages; i++) { 538 for (i = 0; i < npages; i++) {
@@ -541,13 +541,11 @@ void *nfs_readdir_large_page(struct page **pages, unsigned int npages)
541 goto out_freepages; 541 goto out_freepages;
542 pages[i] = page; 542 pages[i] = page;
543 } 543 }
544 return 0;
544 545
545 ptr = vm_map_ram(pages, npages, 0, PAGE_KERNEL);
546 if (!IS_ERR_OR_NULL(ptr))
547 return ptr;
548out_freepages: 546out_freepages:
549 nfs_readdir_free_pagearray(pages, i); 547 nfs_readdir_free_pagearray(pages, i);
550 return NULL; 548 return -ENOMEM;
551} 549}
552 550
553static 551static
@@ -577,8 +575,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
577 memset(array, 0, sizeof(struct nfs_cache_array)); 575 memset(array, 0, sizeof(struct nfs_cache_array));
578 array->eof_index = -1; 576 array->eof_index = -1;
579 577
580 pages_ptr = nfs_readdir_large_page(pages, array_size); 578 status = nfs_readdir_large_page(pages, array_size);
581 if (!pages_ptr) 579 if (status < 0)
582 goto out_release_array; 580 goto out_release_array;
583 do { 581 do {
584 unsigned int pglen; 582 unsigned int pglen;
@@ -587,7 +585,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
587 if (status < 0) 585 if (status < 0)
588 break; 586 break;
589 pglen = status; 587 pglen = status;
590 status = nfs_readdir_page_filler(desc, &entry, pages_ptr, page, pglen); 588 status = nfs_readdir_page_filler(desc, &entry, pages, page, pglen);
591 if (status < 0) { 589 if (status < 0) {
592 if (status == -ENOSPC) 590 if (status == -ENOSPC)
593 status = 0; 591 status = 0;