aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r--fs/nfs/dir.c62
1 files changed, 34 insertions, 28 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 662df2a5fad..8ea4a4180a8 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -162,6 +162,7 @@ struct nfs_cache_array_entry {
162 u64 cookie; 162 u64 cookie;
163 u64 ino; 163 u64 ino;
164 struct qstr string; 164 struct qstr string;
165 unsigned char d_type;
165}; 166};
166 167
167struct nfs_cache_array { 168struct nfs_cache_array {
@@ -171,8 +172,6 @@ struct nfs_cache_array {
171 struct nfs_cache_array_entry array[0]; 172 struct nfs_cache_array_entry array[0];
172}; 173};
173 174
174#define MAX_READDIR_ARRAY ((PAGE_SIZE - sizeof(struct nfs_cache_array)) / sizeof(struct nfs_cache_array_entry))
175
176typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); 175typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
177typedef struct { 176typedef struct {
178 struct file *file; 177 struct file *file;
@@ -257,13 +256,17 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
257 256
258 if (IS_ERR(array)) 257 if (IS_ERR(array))
259 return PTR_ERR(array); 258 return PTR_ERR(array);
259
260 cache_entry = &array->array[array->size];
261
262 /* Check that this entry lies within the page bounds */
260 ret = -ENOSPC; 263 ret = -ENOSPC;
261 if (array->size >= MAX_READDIR_ARRAY) 264 if ((char *)&cache_entry[1] - (char *)page_address(page) > PAGE_SIZE)
262 goto out; 265 goto out;
263 266
264 cache_entry = &array->array[array->size];
265 cache_entry->cookie = entry->prev_cookie; 267 cache_entry->cookie = entry->prev_cookie;
266 cache_entry->ino = entry->ino; 268 cache_entry->ino = entry->ino;
269 cache_entry->d_type = entry->d_type;
267 ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len); 270 ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len);
268 if (ret) 271 if (ret)
269 goto out; 272 goto out;
@@ -466,8 +469,9 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
466 struct xdr_stream stream; 469 struct xdr_stream stream;
467 struct xdr_buf buf; 470 struct xdr_buf buf;
468 __be32 *ptr = xdr_page; 471 __be32 *ptr = xdr_page;
469 int status;
470 struct nfs_cache_array *array; 472 struct nfs_cache_array *array;
473 unsigned int count = 0;
474 int status;
471 475
472 buf.head->iov_base = xdr_page; 476 buf.head->iov_base = xdr_page;
473 buf.head->iov_len = buflen; 477 buf.head->iov_len = buflen;
@@ -488,6 +492,8 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
488 break; 492 break;
489 } 493 }
490 494
495 count++;
496
491 if (desc->plus == 1) 497 if (desc->plus == 1)
492 nfs_prime_dcache(desc->file->f_path.dentry, entry); 498 nfs_prime_dcache(desc->file->f_path.dentry, entry);
493 499
@@ -496,13 +502,14 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
496 break; 502 break;
497 } while (!entry->eof); 503 } while (!entry->eof);
498 504
499 if (status == -EBADCOOKIE && entry->eof) { 505 if (count == 0 || (status == -EBADCOOKIE && entry->eof == 1)) {
500 array = nfs_readdir_get_array(page); 506 array = nfs_readdir_get_array(page);
501 if (!IS_ERR(array)) { 507 if (!IS_ERR(array)) {
502 array->eof_index = array->size; 508 array->eof_index = array->size;
503 status = 0; 509 status = 0;
504 nfs_readdir_release_array(page); 510 nfs_readdir_release_array(page);
505 } 511 } else
512 status = PTR_ERR(array);
506 } 513 }
507 return status; 514 return status;
508} 515}
@@ -696,21 +703,23 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
696 int i = 0; 703 int i = 0;
697 int res = 0; 704 int res = 0;
698 struct nfs_cache_array *array = NULL; 705 struct nfs_cache_array *array = NULL;
699 unsigned int d_type = DT_UNKNOWN;
700 struct dentry *dentry = NULL;
701 706
702 array = nfs_readdir_get_array(desc->page); 707 array = nfs_readdir_get_array(desc->page);
703 if (IS_ERR(array)) 708 if (IS_ERR(array)) {
704 return PTR_ERR(array); 709 res = PTR_ERR(array);
710 goto out;
711 }
705 712
706 for (i = desc->cache_entry_index; i < array->size; i++) { 713 for (i = desc->cache_entry_index; i < array->size; i++) {
707 d_type = DT_UNKNOWN; 714 struct nfs_cache_array_entry *ent;
708 715
709 res = filldir(dirent, array->array[i].string.name, 716 ent = &array->array[i];
710 array->array[i].string.len, file->f_pos, 717 if (filldir(dirent, ent->string.name, ent->string.len,
711 nfs_compat_user_ino64(array->array[i].ino), d_type); 718 file->f_pos, nfs_compat_user_ino64(ent->ino),
712 if (res < 0) 719 ent->d_type) < 0) {
720 desc->eof = 1;
713 break; 721 break;
722 }
714 file->f_pos++; 723 file->f_pos++;
715 desc->cache_entry_index = i; 724 desc->cache_entry_index = i;
716 if (i < (array->size-1)) 725 if (i < (array->size-1))
@@ -722,9 +731,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
722 desc->eof = 1; 731 desc->eof = 1;
723 732
724 nfs_readdir_release_array(desc->page); 733 nfs_readdir_release_array(desc->page);
734out:
725 cache_page_release(desc); 735 cache_page_release(desc);
726 if (dentry != NULL)
727 dput(dentry);
728 dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", 736 dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n",
729 (unsigned long long)*desc->dir_cookie, res); 737 (unsigned long long)*desc->dir_cookie, res);
730 return res; 738 return res;
@@ -759,13 +767,13 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
759 goto out; 767 goto out;
760 } 768 }
761 769
762 if (nfs_readdir_xdr_to_array(desc, page, inode) == -1) {
763 status = -EIO;
764 goto out_release;
765 }
766
767 desc->page_index = 0; 770 desc->page_index = 0;
768 desc->page = page; 771 desc->page = page;
772
773 status = nfs_readdir_xdr_to_array(desc, page, inode);
774 if (status < 0)
775 goto out_release;
776
769 status = nfs_do_filldir(desc, dirent, filldir); 777 status = nfs_do_filldir(desc, dirent, filldir);
770 778
771 out: 779 out:
@@ -816,14 +824,14 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
816 res = readdir_search_pagecache(desc); 824 res = readdir_search_pagecache(desc);
817 825
818 if (res == -EBADCOOKIE) { 826 if (res == -EBADCOOKIE) {
827 res = 0;
819 /* This means either end of directory */ 828 /* This means either end of directory */
820 if (*desc->dir_cookie && desc->eof == 0) { 829 if (*desc->dir_cookie && desc->eof == 0) {
821 /* Or that the server has 'lost' a cookie */ 830 /* Or that the server has 'lost' a cookie */
822 res = uncached_readdir(desc, dirent, filldir); 831 res = uncached_readdir(desc, dirent, filldir);
823 if (res >= 0) 832 if (res == 0)
824 continue; 833 continue;
825 } 834 }
826 res = 0;
827 break; 835 break;
828 } 836 }
829 if (res == -ETOOSMALL && desc->plus) { 837 if (res == -ETOOSMALL && desc->plus) {
@@ -838,10 +846,8 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
838 break; 846 break;
839 847
840 res = nfs_do_filldir(desc, dirent, filldir); 848 res = nfs_do_filldir(desc, dirent, filldir);
841 if (res < 0) { 849 if (res < 0)
842 res = 0;
843 break; 850 break;
844 }
845 } 851 }
846out: 852out:
847 nfs_unblock_sillyrename(dentry); 853 nfs_unblock_sillyrename(dentry);