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.c142
1 files changed, 69 insertions, 73 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 662df2a5fad5..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 *);
58static int nfs_fsync_dir(struct file *, int); 58static int nfs_fsync_dir(struct file *, int);
59static loff_t nfs_llseek_dir(struct file *, loff_t, int); 59static loff_t nfs_llseek_dir(struct file *, loff_t, int);
60static int nfs_readdir_clear_array(struct page*, gfp_t); 60static void nfs_readdir_clear_array(struct page*);
61 61
62const struct file_operations nfs_dir_operations = { 62const 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
86const struct address_space_operations nfs_dir_addr_space_ops = { 86const 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
@@ -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,14 +172,13 @@ 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;
179 struct page *page; 178 struct page *page;
180 unsigned long page_index; 179 unsigned long page_index;
181 u64 *dir_cookie; 180 u64 *dir_cookie;
181 u64 last_cookie;
182 loff_t current_index; 182 loff_t current_index;
183 decode_dirent_t decode; 183 decode_dirent_t decode;
184 184
@@ -214,17 +214,15 @@ void nfs_readdir_release_array(struct page *page)
214 * we are freeing strings created by nfs_add_to_readdir_array() 214 * we are freeing strings created by nfs_add_to_readdir_array()
215 */ 215 */
216static 216static
217int nfs_readdir_clear_array(struct page *page, gfp_t mask) 217void nfs_readdir_clear_array(struct page *page)
218{ 218{
219 struct nfs_cache_array *array = nfs_readdir_get_array(page); 219 struct nfs_cache_array *array;
220 int i; 220 int i;
221 221
222 if (IS_ERR(array)) 222 array = kmap_atomic(page, KM_USER0);
223 return PTR_ERR(array);
224 for (i = 0; i < array->size; i++) 223 for (i = 0; i < array->size; i++)
225 kfree(array->array[i].string.name); 224 kfree(array->array[i].string.name);
226 nfs_readdir_release_array(page); 225 kunmap_atomic(array, KM_USER0);
227 return 0;
228} 226}
229 227
230/* 228/*
@@ -257,19 +255,23 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
257 255
258 if (IS_ERR(array)) 256 if (IS_ERR(array))
259 return PTR_ERR(array); 257 return PTR_ERR(array);
258
259 cache_entry = &array->array[array->size];
260
261 /* Check that this entry lies within the page bounds */
260 ret = -ENOSPC; 262 ret = -ENOSPC;
261 if (array->size >= MAX_READDIR_ARRAY) 263 if ((char *)&cache_entry[1] - (char *)page_address(page) > PAGE_SIZE)
262 goto out; 264 goto out;
263 265
264 cache_entry = &array->array[array->size];
265 cache_entry->cookie = entry->prev_cookie; 266 cache_entry->cookie = entry->prev_cookie;
266 cache_entry->ino = entry->ino; 267 cache_entry->ino = entry->ino;
268 cache_entry->d_type = entry->d_type;
267 ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len); 269 ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len);
268 if (ret) 270 if (ret)
269 goto out; 271 goto out;
270 array->last_cookie = entry->cookie; 272 array->last_cookie = entry->cookie;
271 array->size++; 273 array->size++;
272 if (entry->eof == 1) 274 if (entry->eof != 0)
273 array->eof_index = array->size; 275 array->eof_index = array->size;
274out: 276out:
275 nfs_readdir_release_array(page); 277 nfs_readdir_release_array(page);
@@ -309,15 +311,14 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
309 for (i = 0; i < array->size; i++) { 311 for (i = 0; i < array->size; i++) {
310 if (array->array[i].cookie == *desc->dir_cookie) { 312 if (array->array[i].cookie == *desc->dir_cookie) {
311 desc->cache_entry_index = i; 313 desc->cache_entry_index = i;
312 status = 0; 314 return 0;
313 goto out;
314 } 315 }
315 } 316 }
316 if (i == array->eof_index) { 317 if (array->eof_index >= 0) {
317 desc->eof = 1;
318 status = -EBADCOOKIE; 318 status = -EBADCOOKIE;
319 if (*desc->dir_cookie == array->last_cookie)
320 desc->eof = 1;
319 } 321 }
320out:
321 return status; 322 return status;
322} 323}
323 324
@@ -325,10 +326,7 @@ static
325int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) 326int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc)
326{ 327{
327 struct nfs_cache_array *array; 328 struct nfs_cache_array *array;
328 int status = -EBADCOOKIE; 329 int status;
329
330 if (desc->dir_cookie == NULL)
331 goto out;
332 330
333 array = nfs_readdir_get_array(desc->page); 331 array = nfs_readdir_get_array(desc->page);
334 if (IS_ERR(array)) { 332 if (IS_ERR(array)) {
@@ -341,6 +339,10 @@ int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc)
341 else 339 else
342 status = nfs_readdir_search_for_cookie(array, desc); 340 status = nfs_readdir_search_for_cookie(array, desc);
343 341
342 if (status == -EAGAIN) {
343 desc->last_cookie = array->last_cookie;
344 desc->page_index++;
345 }
344 nfs_readdir_release_array(desc->page); 346 nfs_readdir_release_array(desc->page);
345out: 347out:
346 return status; 348 return status;
@@ -392,13 +394,9 @@ int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct x
392static 394static
393int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry) 395int nfs_same_file(struct dentry *dentry, struct nfs_entry *entry)
394{ 396{
395 struct nfs_inode *node;
396 if (dentry->d_inode == NULL) 397 if (dentry->d_inode == NULL)
397 goto different; 398 goto different;
398 node = NFS_I(dentry->d_inode); 399 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; 400 goto different;
403 return 1; 401 return 1;
404different: 402different:
@@ -466,8 +464,9 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
466 struct xdr_stream stream; 464 struct xdr_stream stream;
467 struct xdr_buf buf; 465 struct xdr_buf buf;
468 __be32 *ptr = xdr_page; 466 __be32 *ptr = xdr_page;
469 int status;
470 struct nfs_cache_array *array; 467 struct nfs_cache_array *array;
468 unsigned int count = 0;
469 int status;
471 470
472 buf.head->iov_base = xdr_page; 471 buf.head->iov_base = xdr_page;
473 buf.head->iov_len = buflen; 472 buf.head->iov_len = buflen;
@@ -488,7 +487,9 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
488 break; 487 break;
489 } 488 }
490 489
491 if (desc->plus == 1) 490 count++;
491
492 if (desc->plus != 0)
492 nfs_prime_dcache(desc->file->f_path.dentry, entry); 493 nfs_prime_dcache(desc->file->f_path.dentry, entry);
493 494
494 status = nfs_readdir_add_to_array(entry, page); 495 status = nfs_readdir_add_to_array(entry, page);
@@ -496,13 +497,14 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
496 break; 497 break;
497 } while (!entry->eof); 498 } while (!entry->eof);
498 499
499 if (status == -EBADCOOKIE && entry->eof) { 500 if (count == 0 || (status == -EBADCOOKIE && entry->eof != 0)) {
500 array = nfs_readdir_get_array(page); 501 array = nfs_readdir_get_array(page);
501 if (!IS_ERR(array)) { 502 if (!IS_ERR(array)) {
502 array->eof_index = array->size; 503 array->eof_index = array->size;
503 status = 0; 504 status = 0;
504 nfs_readdir_release_array(page); 505 nfs_readdir_release_array(page);
505 } 506 } else
507 status = PTR_ERR(array);
506 } 508 }
507 return status; 509 return status;
508} 510}
@@ -560,7 +562,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
560 unsigned int array_size = ARRAY_SIZE(pages); 562 unsigned int array_size = ARRAY_SIZE(pages);
561 563
562 entry.prev_cookie = 0; 564 entry.prev_cookie = 0;
563 entry.cookie = *desc->dir_cookie; 565 entry.cookie = desc->last_cookie;
564 entry.eof = 0; 566 entry.eof = 0;
565 entry.fh = nfs_alloc_fhandle(); 567 entry.fh = nfs_alloc_fhandle();
566 entry.fattr = nfs_alloc_fattr(); 568 entry.fattr = nfs_alloc_fattr();
@@ -633,6 +635,8 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page)
633static 635static
634void cache_page_release(nfs_readdir_descriptor_t *desc) 636void cache_page_release(nfs_readdir_descriptor_t *desc)
635{ 637{
638 if (!desc->page->mapping)
639 nfs_readdir_clear_array(desc->page);
636 page_cache_release(desc->page); 640 page_cache_release(desc->page);
637 desc->page = NULL; 641 desc->page = NULL;
638} 642}
@@ -657,9 +661,8 @@ int find_cache_page(nfs_readdir_descriptor_t *desc)
657 return PTR_ERR(desc->page); 661 return PTR_ERR(desc->page);
658 662
659 res = nfs_readdir_search_array(desc); 663 res = nfs_readdir_search_array(desc);
660 if (res == 0) 664 if (res != 0)
661 return 0; 665 cache_page_release(desc);
662 cache_page_release(desc);
663 return res; 666 return res;
664} 667}
665 668
@@ -669,22 +672,16 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
669{ 672{
670 int res; 673 int res;
671 674
672 if (desc->page_index == 0) 675 if (desc->page_index == 0) {
673 desc->current_index = 0; 676 desc->current_index = 0;
674 while (1) { 677 desc->last_cookie = 0;
675 res = find_cache_page(desc);
676 if (res != -EAGAIN)
677 break;
678 desc->page_index++;
679 } 678 }
679 do {
680 res = find_cache_page(desc);
681 } while (res == -EAGAIN);
680 return res; 682 return res;
681} 683}
682 684
683static inline unsigned int dt_type(struct inode *inode)
684{
685 return (inode->i_mode >> 12) & 15;
686}
687
688/* 685/*
689 * 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...
690 */ 687 */
@@ -696,35 +693,35 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
696 int i = 0; 693 int i = 0;
697 int res = 0; 694 int res = 0;
698 struct nfs_cache_array *array = NULL; 695 struct nfs_cache_array *array = NULL;
699 unsigned int d_type = DT_UNKNOWN;
700 struct dentry *dentry = NULL;
701 696
702 array = nfs_readdir_get_array(desc->page); 697 array = nfs_readdir_get_array(desc->page);
703 if (IS_ERR(array)) 698 if (IS_ERR(array)) {
704 return PTR_ERR(array); 699 res = PTR_ERR(array);
700 goto out;
701 }
705 702
706 for (i = desc->cache_entry_index; i < array->size; i++) { 703 for (i = desc->cache_entry_index; i < array->size; i++) {
707 d_type = DT_UNKNOWN; 704 struct nfs_cache_array_entry *ent;
708 705
709 res = filldir(dirent, array->array[i].string.name, 706 ent = &array->array[i];
710 array->array[i].string.len, file->f_pos, 707 if (filldir(dirent, ent->string.name, ent->string.len,
711 nfs_compat_user_ino64(array->array[i].ino), d_type); 708 file->f_pos, nfs_compat_user_ino64(ent->ino),
712 if (res < 0) 709 ent->d_type) < 0) {
710 desc->eof = 1;
713 break; 711 break;
712 }
714 file->f_pos++; 713 file->f_pos++;
715 desc->cache_entry_index = i;
716 if (i < (array->size-1)) 714 if (i < (array->size-1))
717 *desc->dir_cookie = array->array[i+1].cookie; 715 *desc->dir_cookie = array->array[i+1].cookie;
718 else 716 else
719 *desc->dir_cookie = array->last_cookie; 717 *desc->dir_cookie = array->last_cookie;
720 } 718 }
721 if (i == array->eof_index) 719 if (array->eof_index >= 0)
722 desc->eof = 1; 720 desc->eof = 1;
723 721
724 nfs_readdir_release_array(desc->page); 722 nfs_readdir_release_array(desc->page);
723out:
725 cache_page_release(desc); 724 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", 725 dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n",
729 (unsigned long long)*desc->dir_cookie, res); 726 (unsigned long long)*desc->dir_cookie, res);
730 return res; 727 return res;
@@ -759,13 +756,14 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
759 goto out; 756 goto out;
760 } 757 }
761 758
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; 759 desc->page_index = 0;
760 desc->last_cookie = *desc->dir_cookie;
768 desc->page = page; 761 desc->page = page;
762
763 status = nfs_readdir_xdr_to_array(desc, page, inode);
764 if (status < 0)
765 goto out_release;
766
769 status = nfs_do_filldir(desc, dirent, filldir); 767 status = nfs_do_filldir(desc, dirent, filldir);
770 768
771 out: 769 out:
@@ -787,7 +785,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
787 struct inode *inode = dentry->d_inode; 785 struct inode *inode = dentry->d_inode;
788 nfs_readdir_descriptor_t my_desc, 786 nfs_readdir_descriptor_t my_desc,
789 *desc = &my_desc; 787 *desc = &my_desc;
790 int res = -ENOMEM; 788 int res;
791 789
792 dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", 790 dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n",
793 dentry->d_parent->d_name.name, dentry->d_name.name, 791 dentry->d_parent->d_name.name, dentry->d_name.name,
@@ -812,18 +810,18 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
812 if (res < 0) 810 if (res < 0)
813 goto out; 811 goto out;
814 812
815 while (desc->eof != 1) { 813 do {
816 res = readdir_search_pagecache(desc); 814 res = readdir_search_pagecache(desc);
817 815
818 if (res == -EBADCOOKIE) { 816 if (res == -EBADCOOKIE) {
817 res = 0;
819 /* This means either end of directory */ 818 /* This means either end of directory */
820 if (*desc->dir_cookie && desc->eof == 0) { 819 if (*desc->dir_cookie && desc->eof == 0) {
821 /* Or that the server has 'lost' a cookie */ 820 /* Or that the server has 'lost' a cookie */
822 res = uncached_readdir(desc, dirent, filldir); 821 res = uncached_readdir(desc, dirent, filldir);
823 if (res >= 0) 822 if (res == 0)
824 continue; 823 continue;
825 } 824 }
826 res = 0;
827 break; 825 break;
828 } 826 }
829 if (res == -ETOOSMALL && desc->plus) { 827 if (res == -ETOOSMALL && desc->plus) {
@@ -838,11 +836,9 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
838 break; 836 break;
839 837
840 res = nfs_do_filldir(desc, dirent, filldir); 838 res = nfs_do_filldir(desc, dirent, filldir);
841 if (res < 0) { 839 if (res < 0)
842 res = 0;
843 break; 840 break;
844 } 841 } while (!desc->eof);
845 }
846out: 842out:
847 nfs_unblock_sillyrename(dentry); 843 nfs_unblock_sillyrename(dentry);
848 if (res > 0) 844 if (res > 0)