diff options
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 76 |
1 files changed, 35 insertions, 41 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f0a384e2ae63..996dd8989a91 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -57,7 +57,7 @@ static int nfs_rename(struct inode *, struct dentry *, | |||
57 | struct inode *, struct dentry *); | 57 | struct inode *, struct dentry *); |
58 | static int nfs_fsync_dir(struct file *, int); | 58 | static int nfs_fsync_dir(struct file *, int); |
59 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | 59 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); |
60 | static int nfs_readdir_clear_array(struct page*, gfp_t); | 60 | static void nfs_readdir_clear_array(struct page*); |
61 | 61 | ||
62 | const struct file_operations nfs_dir_operations = { | 62 | const struct file_operations nfs_dir_operations = { |
63 | .llseek = nfs_llseek_dir, | 63 | .llseek = nfs_llseek_dir, |
@@ -83,8 +83,8 @@ const struct inode_operations nfs_dir_inode_operations = { | |||
83 | .setattr = nfs_setattr, | 83 | .setattr = nfs_setattr, |
84 | }; | 84 | }; |
85 | 85 | ||
86 | const struct address_space_operations nfs_dir_addr_space_ops = { | 86 | const struct address_space_operations nfs_dir_aops = { |
87 | .releasepage = nfs_readdir_clear_array, | 87 | .freepage = nfs_readdir_clear_array, |
88 | }; | 88 | }; |
89 | 89 | ||
90 | #ifdef CONFIG_NFS_V3 | 90 | #ifdef CONFIG_NFS_V3 |
@@ -178,6 +178,7 @@ typedef struct { | |||
178 | struct page *page; | 178 | struct page *page; |
179 | unsigned long page_index; | 179 | unsigned long page_index; |
180 | u64 *dir_cookie; | 180 | u64 *dir_cookie; |
181 | u64 last_cookie; | ||
181 | loff_t current_index; | 182 | loff_t current_index; |
182 | decode_dirent_t decode; | 183 | decode_dirent_t decode; |
183 | 184 | ||
@@ -213,17 +214,15 @@ void nfs_readdir_release_array(struct page *page) | |||
213 | * we are freeing strings created by nfs_add_to_readdir_array() | 214 | * we are freeing strings created by nfs_add_to_readdir_array() |
214 | */ | 215 | */ |
215 | static | 216 | static |
216 | int nfs_readdir_clear_array(struct page *page, gfp_t mask) | 217 | void nfs_readdir_clear_array(struct page *page) |
217 | { | 218 | { |
218 | struct nfs_cache_array *array = nfs_readdir_get_array(page); | 219 | struct nfs_cache_array *array; |
219 | int i; | 220 | int i; |
220 | 221 | ||
221 | if (IS_ERR(array)) | 222 | array = kmap_atomic(page, KM_USER0); |
222 | return PTR_ERR(array); | ||
223 | for (i = 0; i < array->size; i++) | 223 | for (i = 0; i < array->size; i++) |
224 | kfree(array->array[i].string.name); | 224 | kfree(array->array[i].string.name); |
225 | nfs_readdir_release_array(page); | 225 | kunmap_atomic(array, KM_USER0); |
226 | return 0; | ||
227 | } | 226 | } |
228 | 227 | ||
229 | /* | 228 | /* |
@@ -272,7 +271,7 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page) | |||
272 | goto out; | 271 | goto out; |
273 | array->last_cookie = entry->cookie; | 272 | array->last_cookie = entry->cookie; |
274 | array->size++; | 273 | array->size++; |
275 | if (entry->eof == 1) | 274 | if (entry->eof != 0) |
276 | array->eof_index = array->size; | 275 | array->eof_index = array->size; |
277 | out: | 276 | out: |
278 | nfs_readdir_release_array(page); | 277 | nfs_readdir_release_array(page); |
@@ -312,15 +311,14 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des | |||
312 | for (i = 0; i < array->size; i++) { | 311 | for (i = 0; i < array->size; i++) { |
313 | if (array->array[i].cookie == *desc->dir_cookie) { | 312 | if (array->array[i].cookie == *desc->dir_cookie) { |
314 | desc->cache_entry_index = i; | 313 | desc->cache_entry_index = i; |
315 | status = 0; | 314 | return 0; |
316 | goto out; | ||
317 | } | 315 | } |
318 | } | 316 | } |
319 | if (i == array->eof_index) { | 317 | if (array->eof_index >= 0) { |
320 | desc->eof = 1; | ||
321 | status = -EBADCOOKIE; | 318 | status = -EBADCOOKIE; |
319 | if (*desc->dir_cookie == array->last_cookie) | ||
320 | desc->eof = 1; | ||
322 | } | 321 | } |
323 | out: | ||
324 | return status; | 322 | return status; |
325 | } | 323 | } |
326 | 324 | ||
@@ -328,10 +326,7 @@ static | |||
328 | int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) | 326 | int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) |
329 | { | 327 | { |
330 | struct nfs_cache_array *array; | 328 | struct nfs_cache_array *array; |
331 | int status = -EBADCOOKIE; | 329 | int status; |
332 | |||
333 | if (desc->dir_cookie == NULL) | ||
334 | goto out; | ||
335 | 330 | ||
336 | array = nfs_readdir_get_array(desc->page); | 331 | array = nfs_readdir_get_array(desc->page); |
337 | if (IS_ERR(array)) { | 332 | if (IS_ERR(array)) { |
@@ -344,6 +339,10 @@ int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) | |||
344 | else | 339 | else |
345 | status = nfs_readdir_search_for_cookie(array, desc); | 340 | status = nfs_readdir_search_for_cookie(array, desc); |
346 | 341 | ||
342 | if (status == -EAGAIN) { | ||
343 | desc->last_cookie = array->last_cookie; | ||
344 | desc->page_index++; | ||
345 | } | ||
347 | nfs_readdir_release_array(desc->page); | 346 | nfs_readdir_release_array(desc->page); |
348 | out: | 347 | out: |
349 | return status; | 348 | return status; |
@@ -490,7 +489,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en | |||
490 | 489 | ||
491 | count++; | 490 | count++; |
492 | 491 | ||
493 | if (desc->plus == 1) | 492 | if (desc->plus != 0) |
494 | nfs_prime_dcache(desc->file->f_path.dentry, entry); | 493 | nfs_prime_dcache(desc->file->f_path.dentry, entry); |
495 | 494 | ||
496 | status = nfs_readdir_add_to_array(entry, page); | 495 | status = nfs_readdir_add_to_array(entry, page); |
@@ -498,7 +497,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en | |||
498 | break; | 497 | break; |
499 | } while (!entry->eof); | 498 | } while (!entry->eof); |
500 | 499 | ||
501 | if (count == 0 || (status == -EBADCOOKIE && entry->eof == 1)) { | 500 | if (count == 0 || (status == -EBADCOOKIE && entry->eof != 0)) { |
502 | array = nfs_readdir_get_array(page); | 501 | array = nfs_readdir_get_array(page); |
503 | if (!IS_ERR(array)) { | 502 | if (!IS_ERR(array)) { |
504 | array->eof_index = array->size; | 503 | array->eof_index = array->size; |
@@ -563,7 +562,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, | |||
563 | unsigned int array_size = ARRAY_SIZE(pages); | 562 | unsigned int array_size = ARRAY_SIZE(pages); |
564 | 563 | ||
565 | entry.prev_cookie = 0; | 564 | entry.prev_cookie = 0; |
566 | entry.cookie = *desc->dir_cookie; | 565 | entry.cookie = desc->last_cookie; |
567 | entry.eof = 0; | 566 | entry.eof = 0; |
568 | entry.fh = nfs_alloc_fhandle(); | 567 | entry.fh = nfs_alloc_fhandle(); |
569 | entry.fattr = nfs_alloc_fattr(); | 568 | entry.fattr = nfs_alloc_fattr(); |
@@ -636,6 +635,8 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page) | |||
636 | static | 635 | static |
637 | void cache_page_release(nfs_readdir_descriptor_t *desc) | 636 | void cache_page_release(nfs_readdir_descriptor_t *desc) |
638 | { | 637 | { |
638 | if (!desc->page->mapping) | ||
639 | nfs_readdir_clear_array(desc->page); | ||
639 | page_cache_release(desc->page); | 640 | page_cache_release(desc->page); |
640 | desc->page = NULL; | 641 | desc->page = NULL; |
641 | } | 642 | } |
@@ -660,9 +661,8 @@ int find_cache_page(nfs_readdir_descriptor_t *desc) | |||
660 | return PTR_ERR(desc->page); | 661 | return PTR_ERR(desc->page); |
661 | 662 | ||
662 | res = nfs_readdir_search_array(desc); | 663 | res = nfs_readdir_search_array(desc); |
663 | if (res == 0) | 664 | if (res != 0) |
664 | return 0; | 665 | cache_page_release(desc); |
665 | cache_page_release(desc); | ||
666 | return res; | 666 | return res; |
667 | } | 667 | } |
668 | 668 | ||
@@ -672,22 +672,16 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | |||
672 | { | 672 | { |
673 | int res; | 673 | int res; |
674 | 674 | ||
675 | if (desc->page_index == 0) | 675 | if (desc->page_index == 0) { |
676 | desc->current_index = 0; | 676 | desc->current_index = 0; |
677 | while (1) { | 677 | desc->last_cookie = 0; |
678 | res = find_cache_page(desc); | ||
679 | if (res != -EAGAIN) | ||
680 | break; | ||
681 | desc->page_index++; | ||
682 | } | 678 | } |
679 | do { | ||
680 | res = find_cache_page(desc); | ||
681 | } while (res == -EAGAIN); | ||
683 | return res; | 682 | return res; |
684 | } | 683 | } |
685 | 684 | ||
686 | static inline unsigned int dt_type(struct inode *inode) | ||
687 | { | ||
688 | return (inode->i_mode >> 12) & 15; | ||
689 | } | ||
690 | |||
691 | /* | 685 | /* |
692 | * Once we've found the start of the dirent within a page: fill 'er up... | 686 | * Once we've found the start of the dirent within a page: fill 'er up... |
693 | */ | 687 | */ |
@@ -717,13 +711,12 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
717 | break; | 711 | break; |
718 | } | 712 | } |
719 | file->f_pos++; | 713 | file->f_pos++; |
720 | desc->cache_entry_index = i; | ||
721 | if (i < (array->size-1)) | 714 | if (i < (array->size-1)) |
722 | *desc->dir_cookie = array->array[i+1].cookie; | 715 | *desc->dir_cookie = array->array[i+1].cookie; |
723 | else | 716 | else |
724 | *desc->dir_cookie = array->last_cookie; | 717 | *desc->dir_cookie = array->last_cookie; |
725 | } | 718 | } |
726 | if (i == array->eof_index) | 719 | if (array->eof_index >= 0) |
727 | desc->eof = 1; | 720 | desc->eof = 1; |
728 | 721 | ||
729 | nfs_readdir_release_array(desc->page); | 722 | nfs_readdir_release_array(desc->page); |
@@ -764,6 +757,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
764 | } | 757 | } |
765 | 758 | ||
766 | desc->page_index = 0; | 759 | desc->page_index = 0; |
760 | desc->last_cookie = *desc->dir_cookie; | ||
767 | desc->page = page; | 761 | desc->page = page; |
768 | 762 | ||
769 | status = nfs_readdir_xdr_to_array(desc, page, inode); | 763 | status = nfs_readdir_xdr_to_array(desc, page, inode); |
@@ -791,7 +785,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
791 | struct inode *inode = dentry->d_inode; | 785 | struct inode *inode = dentry->d_inode; |
792 | nfs_readdir_descriptor_t my_desc, | 786 | nfs_readdir_descriptor_t my_desc, |
793 | *desc = &my_desc; | 787 | *desc = &my_desc; |
794 | int res = -ENOMEM; | 788 | int res; |
795 | 789 | ||
796 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", | 790 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", |
797 | dentry->d_parent->d_name.name, dentry->d_name.name, | 791 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -816,7 +810,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
816 | if (res < 0) | 810 | if (res < 0) |
817 | goto out; | 811 | goto out; |
818 | 812 | ||
819 | while (desc->eof != 1) { | 813 | do { |
820 | res = readdir_search_pagecache(desc); | 814 | res = readdir_search_pagecache(desc); |
821 | 815 | ||
822 | if (res == -EBADCOOKIE) { | 816 | if (res == -EBADCOOKIE) { |
@@ -844,7 +838,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
844 | res = nfs_do_filldir(desc, dirent, filldir); | 838 | res = nfs_do_filldir(desc, dirent, filldir); |
845 | if (res < 0) | 839 | if (res < 0) |
846 | break; | 840 | break; |
847 | } | 841 | } while (!desc->eof); |
848 | out: | 842 | out: |
849 | nfs_unblock_sillyrename(dentry); | 843 | nfs_unblock_sillyrename(dentry); |
850 | if (res > 0) | 844 | if (res > 0) |