diff options
author | Bryan Schumaker <bjschuma@netapp.com> | 2010-10-20 15:44:37 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-10-23 15:27:35 -0400 |
commit | 56e4ebf877b6043c289bda32a5a7385b80c17dee (patch) | |
tree | 160ae8d5b5ee3871d02a9f5283187430c9ec5ffe /fs/nfs/dir.c | |
parent | afa8ccc978c24d8ab22e3b3b8cbd1054c84c070b (diff) |
NFS: readdir with vmapped pages
We can use vmapped pages to read more information from the network at once.
This will reduce the number of calls needed to complete a readdir.
Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
[trondmy: Added #include for linux/vmalloc.h> in fs/nfs/dir.c]
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 66 |
1 files changed, 54 insertions, 12 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 88cbcda76856..5d7da3ad4e85 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -33,6 +33,7 @@ | |||
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> | ||
36 | 37 | ||
37 | #include "delegation.h" | 38 | #include "delegation.h" |
38 | #include "iostat.h" | 39 | #include "iostat.h" |
@@ -327,7 +328,7 @@ out: | |||
327 | 328 | ||
328 | /* Fill a page with xdr information before transferring to the cache page */ | 329 | /* Fill a page with xdr information before transferring to the cache page */ |
329 | static | 330 | static |
330 | int nfs_readdir_xdr_filler(struct page *xdr_page, nfs_readdir_descriptor_t *desc, | 331 | int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc, |
331 | struct nfs_entry *entry, struct file *file, struct inode *inode) | 332 | struct nfs_entry *entry, struct file *file, struct inode *inode) |
332 | { | 333 | { |
333 | struct rpc_cred *cred = nfs_file_cred(file); | 334 | struct rpc_cred *cred = nfs_file_cred(file); |
@@ -337,7 +338,7 @@ int nfs_readdir_xdr_filler(struct page *xdr_page, nfs_readdir_descriptor_t *desc | |||
337 | again: | 338 | again: |
338 | timestamp = jiffies; | 339 | timestamp = jiffies; |
339 | gencount = nfs_inc_attr_generation_counter(); | 340 | gencount = nfs_inc_attr_generation_counter(); |
340 | error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, entry->cookie, xdr_page, | 341 | error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, entry->cookie, pages, |
341 | NFS_SERVER(inode)->dtsize, desc->plus); | 342 | NFS_SERVER(inode)->dtsize, desc->plus); |
342 | if (error < 0) { | 343 | if (error < 0) { |
343 | /* We requested READDIRPLUS, but the server doesn't grok it */ | 344 | /* We requested READDIRPLUS, but the server doesn't grok it */ |
@@ -436,11 +437,11 @@ out: | |||
436 | /* Perform conversion from xdr to cache array */ | 437 | /* Perform conversion from xdr to cache array */ |
437 | static | 438 | static |
438 | void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, | 439 | void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, |
439 | struct page *xdr_page, struct page *page, unsigned int buflen) | 440 | void *xdr_page, struct page *page, unsigned int buflen) |
440 | { | 441 | { |
441 | struct xdr_stream stream; | 442 | struct xdr_stream stream; |
442 | struct xdr_buf buf; | 443 | struct xdr_buf buf; |
443 | __be32 *ptr = kmap(xdr_page); | 444 | __be32 *ptr = xdr_page; |
444 | 445 | ||
445 | buf.head->iov_base = xdr_page; | 446 | buf.head->iov_base = xdr_page; |
446 | buf.head->iov_len = buflen; | 447 | buf.head->iov_len = buflen; |
@@ -458,18 +459,59 @@ void nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *e | |||
458 | if (desc->plus == 1) | 459 | if (desc->plus == 1) |
459 | nfs_prime_dcache(desc->file->f_path.dentry, entry); | 460 | nfs_prime_dcache(desc->file->f_path.dentry, entry); |
460 | } | 461 | } |
461 | kunmap(xdr_page); | 462 | } |
463 | |||
464 | static | ||
465 | void nfs_readdir_free_pagearray(struct page **pages, unsigned int npages) | ||
466 | { | ||
467 | unsigned int i; | ||
468 | for (i = 0; i < npages; i++) | ||
469 | put_page(pages[i]); | ||
470 | } | ||
471 | |||
472 | static | ||
473 | void nfs_readdir_free_large_page(void *ptr, struct page **pages, | ||
474 | unsigned int npages) | ||
475 | { | ||
476 | vm_unmap_ram(ptr, npages); | ||
477 | nfs_readdir_free_pagearray(pages, npages); | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * nfs_readdir_large_page will allocate pages that must be freed with a call | ||
482 | * to nfs_readdir_free_large_page | ||
483 | */ | ||
484 | static | ||
485 | void *nfs_readdir_large_page(struct page **pages, unsigned int npages) | ||
486 | { | ||
487 | void *ptr; | ||
488 | unsigned int i; | ||
489 | |||
490 | for (i = 0; i < npages; i++) { | ||
491 | struct page *page = alloc_page(GFP_KERNEL); | ||
492 | if (page == NULL) | ||
493 | goto out_freepages; | ||
494 | pages[i] = page; | ||
495 | } | ||
496 | |||
497 | ptr = vm_map_ram(pages, NFS_MAX_READDIR_PAGES, 0, PAGE_KERNEL); | ||
498 | if (!IS_ERR_OR_NULL(ptr)) | ||
499 | return ptr; | ||
500 | out_freepages: | ||
501 | nfs_readdir_free_pagearray(pages, i); | ||
502 | return NULL; | ||
462 | } | 503 | } |
463 | 504 | ||
464 | static | 505 | static |
465 | int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, struct inode *inode) | 506 | int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, struct inode *inode) |
466 | { | 507 | { |
467 | struct page *xdr_page; | 508 | struct page *pages[NFS_MAX_READDIR_PAGES]; |
509 | void *pages_ptr = NULL; | ||
468 | struct nfs_entry entry; | 510 | struct nfs_entry entry; |
469 | struct file *file = desc->file; | 511 | struct file *file = desc->file; |
470 | struct nfs_cache_array *array; | 512 | struct nfs_cache_array *array; |
471 | int status = 0; | 513 | int status = 0; |
472 | unsigned int array_size = 1; | 514 | unsigned int array_size = ARRAY_SIZE(pages); |
473 | 515 | ||
474 | entry.prev_cookie = 0; | 516 | entry.prev_cookie = 0; |
475 | entry.cookie = *desc->dir_cookie; | 517 | entry.cookie = *desc->dir_cookie; |
@@ -483,18 +525,18 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, | |||
483 | memset(array, 0, sizeof(struct nfs_cache_array)); | 525 | memset(array, 0, sizeof(struct nfs_cache_array)); |
484 | array->eof_index = -1; | 526 | array->eof_index = -1; |
485 | 527 | ||
486 | xdr_page = alloc_page(GFP_KERNEL); | 528 | pages_ptr = nfs_readdir_large_page(pages, array_size); |
487 | if (!xdr_page) | 529 | if (!pages_ptr) |
488 | goto out_release_array; | 530 | goto out_release_array; |
489 | do { | 531 | do { |
490 | status = nfs_readdir_xdr_filler(xdr_page, desc, &entry, file, inode); | 532 | status = nfs_readdir_xdr_filler(pages, desc, &entry, file, inode); |
491 | 533 | ||
492 | if (status < 0) | 534 | if (status < 0) |
493 | break; | 535 | break; |
494 | nfs_readdir_page_filler(desc, &entry, xdr_page, page, array_size * PAGE_SIZE); | 536 | nfs_readdir_page_filler(desc, &entry, pages_ptr, page, array_size * PAGE_SIZE); |
495 | } while (array->eof_index < 0 && array->size < MAX_READDIR_ARRAY); | 537 | } while (array->eof_index < 0 && array->size < MAX_READDIR_ARRAY); |
496 | 538 | ||
497 | put_page(xdr_page); | 539 | nfs_readdir_free_large_page(pages_ptr, pages, array_size); |
498 | out_release_array: | 540 | out_release_array: |
499 | nfs_readdir_release_array(page); | 541 | nfs_readdir_release_array(page); |
500 | out: | 542 | out: |