diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-11-26 17:30:30 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-11-26 17:30:30 -0500 |
| commit | 19650e8580987c0ffabc2fe2cbc16b944789df8b (patch) | |
| tree | cf0cfb390a128e3b2d47daa46f59de0a62a8ff04 | |
| parent | 1eb4c6362cb7d6a2f904c555c10dc45caeeefc31 (diff) | |
| parent | 0b26a0bf6ff398185546432420bb772bcfdf8d94 (diff) | |
Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
NFS: Ensure we return the dirent->d_type when it is known
NFS: Correct the array bound calculation in nfs_readdir_add_to_array
NFS: Don't ignore errors from nfs_do_filldir()
NFS: Fix the error handling in "uncached_readdir()"
NFS: Fix a page leak in uncached_readdir()
NFS: Fix a page leak in nfs_do_filldir()
NFS: Assume eof if the server returns no readdir records
NFS: Buffer overflow in ->decode_dirent() should not be fatal
Pure nfs client performance using odirect.
SUNRPC: Fix an infinite loop in call_refresh/call_refreshresult
| -rw-r--r-- | fs/nfs/dir.c | 62 | ||||
| -rw-r--r-- | fs/nfs/direct.c | 2 | ||||
| -rw-r--r-- | fs/nfs/internal.h | 9 | ||||
| -rw-r--r-- | fs/nfs/nfs2xdr.c | 4 | ||||
| -rw-r--r-- | fs/nfs/nfs3xdr.c | 4 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 6 | ||||
| -rw-r--r-- | include/linux/nfs_xdr.h | 1 | ||||
| -rw-r--r-- | net/sunrpc/clnt.c | 24 |
8 files changed, 71 insertions, 41 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 662df2a5fad5..8ea4a4180a87 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; |
| @@ -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); |
| 734 | out: | ||
| 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 | } |
