diff options
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 68 |
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 | ||
167 | struct nfs_cache_array { | 168 | struct 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 | |||
176 | typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); | 175 | typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); |
177 | typedef struct { | 176 | typedef 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 | |||
392 | static | 395 | static |
393 | int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) | 396 | int 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; |
404 | different: | 403 | different: |
@@ -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); |
730 | out: | ||
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 | } |
846 | out: | 848 | out: |
847 | nfs_unblock_sillyrename(dentry); | 849 | nfs_unblock_sillyrename(dentry); |