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.c68
1 files changed, 35 insertions, 33 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 662df2a5fad5..f0a384e2ae63 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;
@@ -392,13 +395,9 @@ int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct x
392static 395static
393int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) 396int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
394{ 397{
395 struct nfs_inode *node;
396 if (dentry->d_inode == NULL) 398 if (dentry->d_inode == NULL)
397 goto different; 399 goto different;
398 node = NFS_I(dentry->d_inode); 400 if (nfs_compare_fh(entry->fh, NFS_FH(dentry->d_inode)) != 0)
399 if (node->fh.size != entry->fh->size)
400 goto different;
401 if (strncmp(node->fh.data, entry->fh->data, node->fh.size) != 0)
402 goto different; 401 goto different;
403 return 1; 402 return 1;
404different: 403different:
@@ -466,8 +465,9 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
466 struct xdr_stream stream; 465 struct xdr_stream stream;
467 struct xdr_buf buf; 466 struct xdr_buf buf;
468 __be32 *ptr = xdr_page; 467 __be32 *ptr = xdr_page;
469 int status;
470 struct nfs_cache_array *array; 468 struct nfs_cache_array *array;
469 unsigned int count = 0;
470 int status;
471 471
472 buf.head->iov_base = xdr_page; 472 buf.head->iov_base = xdr_page;
473 buf.head->iov_len = buflen; 473 buf.head->iov_len = buflen;
@@ -488,6 +488,8 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
488 break; 488 break;
489 } 489 }
490 490
491 count++;
492
491 if (desc->plus == 1) 493 if (desc->plus == 1)
492 nfs_prime_dcache(desc->file->f_path.dentry, entry); 494 nfs_prime_dcache(desc->file->f_path.dentry, entry);
493 495
@@ -496,13 +498,14 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
496 break; 498 break;
497 } while (!entry->eof); 499 } while (!entry->eof);
498 500
499 if (status == -EBADCOOKIE && entry->eof) { 501 if (count == 0 || (status == -EBADCOOKIE && entry->eof == 1)) {
500 array = nfs_readdir_get_array(page); 502 array = nfs_readdir_get_array(page);
501 if (!IS_ERR(array)) { 503 if (!IS_ERR(array)) {
502 array->eof_index = array->size; 504 array->eof_index = array->size;
503 status = 0; 505 status = 0;
504 nfs_readdir_release_array(page); 506 nfs_readdir_release_array(page);
505 } 507 } else
508 status = PTR_ERR(array);
506 } 509 }
507 return status; 510 return status;
508} 511}
@@ -696,21 +699,23 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
696 int i = 0; 699 int i = 0;
697 int res = 0; 700 int res = 0;
698 struct nfs_cache_array *array = NULL; 701 struct nfs_cache_array *array = NULL;
699 unsigned int d_type = DT_UNKNOWN;
700 struct dentry *dentry = NULL;
701 702
702 array = nfs_readdir_get_array(desc->page); 703 array = nfs_readdir_get_array(desc->page);
703 if (IS_ERR(array)) 704 if (IS_ERR(array)) {
704 return PTR_ERR(array); 705 res = PTR_ERR(array);
706 goto out;
707 }
705 708
706 for (i = desc->cache_entry_index; i < array->size; i++) { 709 for (i = desc->cache_entry_index; i < array->size; i++) {
707 d_type = DT_UNKNOWN; 710 struct nfs_cache_array_entry *ent;
708 711
709 res = filldir(dirent, array->array[i].string.name, 712 ent = &array->array[i];
710 array->array[i].string.len, file->f_pos, 713 if (filldir(dirent, ent->string.name, ent->string.len,
711 nfs_compat_user_ino64(array->array[i].ino), d_type); 714 file->f_pos, nfs_compat_user_ino64(ent->ino),
712 if (res < 0) 715 ent->d_type) < 0) {
716 desc->eof = 1;
713 break; 717 break;
718 }
714 file->f_pos++; 719 file->f_pos++;
715 desc->cache_entry_index = i; 720 desc->cache_entry_index = i;
716 if (i < (array->size-1)) 721 if (i < (array->size-1))
@@ -722,9 +727,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
722 desc->eof = 1; 727 desc->eof = 1;
723 728
724 nfs_readdir_release_array(desc->page); 729 nfs_readdir_release_array(desc->page);
730out:
725 cache_page_release(desc); 731 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", 732 dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n",
729 (unsigned long long)*desc->dir_cookie, res); 733 (unsigned long long)*desc->dir_cookie, res);
730 return res; 734 return res;
@@ -759,13 +763,13 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
759 goto out; 763 goto out;
760 } 764 }
761 765
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; 766 desc->page_index = 0;
768 desc->page = page; 767 desc->page = page;
768
769 status = nfs_readdir_xdr_to_array(desc, page, inode);
770 if (status < 0)
771 goto out_release;
772
769 status = nfs_do_filldir(desc, dirent, filldir); 773 status = nfs_do_filldir(desc, dirent, filldir);
770 774
771 out: 775 out:
@@ -816,14 +820,14 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
816 res = readdir_search_pagecache(desc); 820 res = readdir_search_pagecache(desc);
817 821
818 if (res == -EBADCOOKIE) { 822 if (res == -EBADCOOKIE) {
823 res = 0;
819 /* This means either end of directory */ 824 /* This means either end of directory */
820 if (*desc->dir_cookie && desc->eof == 0) { 825 if (*desc->dir_cookie && desc->eof == 0) {
821 /* Or that the server has 'lost' a cookie */ 826 /* Or that the server has 'lost' a cookie */
822 res = uncached_readdir(desc, dirent, filldir); 827 res = uncached_readdir(desc, dirent, filldir);
823 if (res >= 0) 828 if (res == 0)
824 continue; 829 continue;
825 } 830 }
826 res = 0;
827 break; 831 break;
828 } 832 }
829 if (res == -ETOOSMALL && desc->plus) { 833 if (res == -ETOOSMALL && desc->plus) {
@@ -838,10 +842,8 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
838 break; 842 break;
839 843
840 res = nfs_do_filldir(desc, dirent, filldir); 844 res = nfs_do_filldir(desc, dirent, filldir);
841 if (res < 0) { 845 if (res < 0)
842 res = 0;
843 break; 846 break;
844 }
845 } 847 }
846out: 848out:
847 nfs_unblock_sillyrename(dentry); 849 nfs_unblock_sillyrename(dentry);