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

+72 -42
+35 -29
fs/nfs/dir.c
··· 162 u64 cookie; 163 u64 ino; 164 struct qstr string; 165 }; 166 167 struct nfs_cache_array { ··· 171 u64 last_cookie; 172 struct nfs_cache_array_entry array[0]; 173 }; 174 - 175 - #define MAX_READDIR_ARRAY ((PAGE_SIZE - sizeof(struct nfs_cache_array)) / sizeof(struct nfs_cache_array_entry)) 176 177 typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); 178 typedef struct { ··· 256 257 if (IS_ERR(array)) 258 return PTR_ERR(array); 259 - ret = -ENOSPC; 260 - if (array->size >= MAX_READDIR_ARRAY) 261 - goto out; 262 263 cache_entry = &array->array[array->size]; 264 cache_entry->cookie = entry->prev_cookie; 265 cache_entry->ino = entry->ino; 266 ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len); 267 if (ret) 268 goto out; ··· 469 struct xdr_stream stream; 470 struct xdr_buf buf; 471 __be32 *ptr = xdr_page; 472 - int status; 473 struct nfs_cache_array *array; 474 475 buf.head->iov_base = xdr_page; 476 buf.head->iov_len = buflen; ··· 492 break; 493 } 494 495 if (desc->plus == 1) 496 nfs_prime_dcache(desc->file->f_path.dentry, entry); 497 ··· 502 break; 503 } while (!entry->eof); 504 505 - if (status == -EBADCOOKIE && entry->eof) { 506 array = nfs_readdir_get_array(page); 507 if (!IS_ERR(array)) { 508 array->eof_index = array->size; 509 status = 0; 510 nfs_readdir_release_array(page); 511 - } 512 } 513 return status; 514 } ··· 703 int i = 0; 704 int res = 0; 705 struct nfs_cache_array *array = NULL; 706 - unsigned int d_type = DT_UNKNOWN; 707 - struct dentry *dentry = NULL; 708 709 array = nfs_readdir_get_array(desc->page); 710 - if (IS_ERR(array)) 711 - return PTR_ERR(array); 712 713 for (i = desc->cache_entry_index; i < array->size; i++) { 714 - d_type = DT_UNKNOWN; 715 716 - res = filldir(dirent, array->array[i].string.name, 717 - array->array[i].string.len, file->f_pos, 718 - nfs_compat_user_ino64(array->array[i].ino), d_type); 719 - if (res < 0) 720 break; 721 file->f_pos++; 722 desc->cache_entry_index = i; 723 if (i < (array->size-1)) ··· 731 desc->eof = 1; 732 733 nfs_readdir_release_array(desc->page); 734 cache_page_release(desc); 735 - if (dentry != NULL) 736 - dput(dentry); 737 dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", 738 (unsigned long long)*desc->dir_cookie, res); 739 return res; ··· 767 goto out; 768 } 769 770 - if (nfs_readdir_xdr_to_array(desc, page, inode) == -1) { 771 - status = -EIO; 772 - goto out_release; 773 - } 774 - 775 desc->page_index = 0; 776 desc->page = page; 777 status = nfs_do_filldir(desc, dirent, filldir); 778 779 out: ··· 824 res = readdir_search_pagecache(desc); 825 826 if (res == -EBADCOOKIE) { 827 /* This means either end of directory */ 828 if (*desc->dir_cookie && desc->eof == 0) { 829 /* Or that the server has 'lost' a cookie */ 830 res = uncached_readdir(desc, dirent, filldir); 831 - if (res >= 0) 832 continue; 833 } 834 - res = 0; 835 break; 836 } 837 if (res == -ETOOSMALL && desc->plus) { ··· 846 break; 847 848 res = nfs_do_filldir(desc, dirent, filldir); 849 - if (res < 0) { 850 - res = 0; 851 break; 852 - } 853 } 854 out: 855 nfs_unblock_sillyrename(dentry);
··· 162 u64 cookie; 163 u64 ino; 164 struct qstr string; 165 + unsigned char d_type; 166 }; 167 168 struct nfs_cache_array { ··· 170 u64 last_cookie; 171 struct nfs_cache_array_entry array[0]; 172 }; 173 174 typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int); 175 typedef struct { ··· 257 258 if (IS_ERR(array)) 259 return PTR_ERR(array); 260 261 cache_entry = &array->array[array->size]; 262 + 263 + /* Check that this entry lies within the page bounds */ 264 + ret = -ENOSPC; 265 + if ((char *)&cache_entry[1] - (char *)page_address(page) > PAGE_SIZE) 266 + goto out; 267 + 268 cache_entry->cookie = entry->prev_cookie; 269 cache_entry->ino = entry->ino; 270 + cache_entry->d_type = entry->d_type; 271 ret = nfs_readdir_make_qstr(&cache_entry->string, entry->name, entry->len); 272 if (ret) 273 goto out; ··· 466 struct xdr_stream stream; 467 struct xdr_buf buf; 468 __be32 *ptr = xdr_page; 469 struct nfs_cache_array *array; 470 + unsigned int count = 0; 471 + int status; 472 473 buf.head->iov_base = xdr_page; 474 buf.head->iov_len = buflen; ··· 488 break; 489 } 490 491 + count++; 492 + 493 if (desc->plus == 1) 494 nfs_prime_dcache(desc->file->f_path.dentry, entry); 495 ··· 496 break; 497 } while (!entry->eof); 498 499 + if (count == 0 || (status == -EBADCOOKIE && entry->eof == 1)) { 500 array = nfs_readdir_get_array(page); 501 if (!IS_ERR(array)) { 502 array->eof_index = array->size; 503 status = 0; 504 nfs_readdir_release_array(page); 505 + } else 506 + status = PTR_ERR(array); 507 } 508 return status; 509 } ··· 696 int i = 0; 697 int res = 0; 698 struct nfs_cache_array *array = NULL; 699 700 array = nfs_readdir_get_array(desc->page); 701 + if (IS_ERR(array)) { 702 + res = PTR_ERR(array); 703 + goto out; 704 + } 705 706 for (i = desc->cache_entry_index; i < array->size; i++) { 707 + struct nfs_cache_array_entry *ent; 708 709 + ent = &array->array[i]; 710 + if (filldir(dirent, ent->string.name, ent->string.len, 711 + file->f_pos, nfs_compat_user_ino64(ent->ino), 712 + ent->d_type) < 0) { 713 + desc->eof = 1; 714 break; 715 + } 716 file->f_pos++; 717 desc->cache_entry_index = i; 718 if (i < (array->size-1)) ··· 722 desc->eof = 1; 723 724 nfs_readdir_release_array(desc->page); 725 + out: 726 cache_page_release(desc); 727 dfprintk(DIRCACHE, "NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n", 728 (unsigned long long)*desc->dir_cookie, res); 729 return res; ··· 759 goto out; 760 } 761 762 desc->page_index = 0; 763 desc->page = page; 764 + 765 + status = nfs_readdir_xdr_to_array(desc, page, inode); 766 + if (status < 0) 767 + goto out_release; 768 + 769 status = nfs_do_filldir(desc, dirent, filldir); 770 771 out: ··· 816 res = readdir_search_pagecache(desc); 817 818 if (res == -EBADCOOKIE) { 819 + res = 0; 820 /* This means either end of directory */ 821 if (*desc->dir_cookie && desc->eof == 0) { 822 /* Or that the server has 'lost' a cookie */ 823 res = uncached_readdir(desc, dirent, filldir); 824 + if (res == 0) 825 continue; 826 } 827 break; 828 } 829 if (res == -ETOOSMALL && desc->plus) { ··· 838 break; 839 840 res = nfs_do_filldir(desc, dirent, filldir); 841 + if (res < 0) 842 break; 843 } 844 out: 845 nfs_unblock_sillyrename(dentry);
+1 -1
fs/nfs/direct.c
··· 867 goto out; 868 nfs_alloc_commit_data(dreq); 869 870 - if (dreq->commit_data == NULL || count < wsize) 871 sync = NFS_FILE_SYNC; 872 873 dreq->inode = inode;
··· 867 goto out; 868 nfs_alloc_commit_data(dreq); 869 870 + if (dreq->commit_data == NULL || count <= wsize) 871 sync = NFS_FILE_SYNC; 872 873 dreq->inode = inode;
+9
fs/nfs/internal.h
··· 362 } 363 364 /* 365 * Determine the number of pages in an array of length 'len' and 366 * with a base offset of 'base' 367 */
··· 362 } 363 364 /* 365 + * Convert a umode to a dirent->d_type 366 + */ 367 + static inline 368 + unsigned char nfs_umode_to_dtype(umode_t mode) 369 + { 370 + return (mode >> 12) & 15; 371 + } 372 + 373 + /* 374 * Determine the number of pages in an array of length 'len' and 375 * with a base offset of 'base' 376 */
+3 -1
fs/nfs/nfs2xdr.c
··· 485 entry->prev_cookie = entry->cookie; 486 entry->cookie = ntohl(*p++); 487 488 p = xdr_inline_peek(xdr, 8); 489 if (p != NULL) 490 entry->eof = !p[0] && p[1]; ··· 497 498 out_overflow: 499 print_overflow_msg(__func__, xdr); 500 - return ERR_PTR(-EIO); 501 } 502 503 /*
··· 485 entry->prev_cookie = entry->cookie; 486 entry->cookie = ntohl(*p++); 487 488 + entry->d_type = DT_UNKNOWN; 489 + 490 p = xdr_inline_peek(xdr, 8); 491 if (p != NULL) 492 entry->eof = !p[0] && p[1]; ··· 495 496 out_overflow: 497 print_overflow_msg(__func__, xdr); 498 + return ERR_PTR(-EAGAIN); 499 } 500 501 /*
+3 -1
fs/nfs/nfs3xdr.c
··· 622 entry->prev_cookie = entry->cookie; 623 p = xdr_decode_hyper(p, &entry->cookie); 624 625 if (plus) { 626 entry->fattr->valid = 0; 627 p = xdr_decode_post_op_attr_stream(xdr, entry->fattr); 628 if (IS_ERR(p)) 629 goto out_overflow_exit; 630 /* In fact, a post_op_fh3: */ 631 p = xdr_inline_decode(xdr, 4); 632 if (unlikely(!p)) ··· 658 out_overflow: 659 print_overflow_msg(__func__, xdr); 660 out_overflow_exit: 661 - return ERR_PTR(-EIO); 662 } 663 664 /*
··· 622 entry->prev_cookie = entry->cookie; 623 p = xdr_decode_hyper(p, &entry->cookie); 624 625 + entry->d_type = DT_UNKNOWN; 626 if (plus) { 627 entry->fattr->valid = 0; 628 p = xdr_decode_post_op_attr_stream(xdr, entry->fattr); 629 if (IS_ERR(p)) 630 goto out_overflow_exit; 631 + entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); 632 /* In fact, a post_op_fh3: */ 633 p = xdr_inline_decode(xdr, 4); 634 if (unlikely(!p)) ··· 656 out_overflow: 657 print_overflow_msg(__func__, xdr); 658 out_overflow_exit: 659 + return ERR_PTR(-EAGAIN); 660 } 661 662 /*
+5 -1
fs/nfs/nfs4xdr.c
··· 6208 if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) 6209 entry->ino = entry->fattr->fileid; 6210 6211 if (verify_attr_len(xdr, p, len) < 0) 6212 goto out_overflow; 6213 ··· 6225 6226 out_overflow: 6227 print_overflow_msg(__func__, xdr); 6228 - return ERR_PTR(-EIO); 6229 } 6230 6231 /*
··· 6208 if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) 6209 entry->ino = entry->fattr->fileid; 6210 6211 + entry->d_type = DT_UNKNOWN; 6212 + if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE) 6213 + entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); 6214 + 6215 if (verify_attr_len(xdr, p, len) < 0) 6216 goto out_overflow; 6217 ··· 6221 6222 out_overflow: 6223 print_overflow_msg(__func__, xdr); 6224 + return ERR_PTR(-EAGAIN); 6225 } 6226 6227 /*
+1
include/linux/nfs_xdr.h
··· 483 int eof; 484 struct nfs_fh * fh; 485 struct nfs_fattr * fattr; 486 }; 487 488 /*
··· 483 int eof; 484 struct nfs_fh * fh; 485 struct nfs_fattr * fattr; 486 + unsigned char d_type; 487 }; 488 489 /*
+15 -9
net/sunrpc/clnt.c
··· 989 dprint_status(task); 990 991 task->tk_status = 0; 992 - task->tk_action = call_allocate; 993 - if (status >= 0 && rpcauth_uptodatecred(task)) 994 - return; 995 switch (status) { 996 - case -EACCES: 997 - rpc_exit(task, -EACCES); 998 - return; 999 - case -ENOMEM: 1000 - rpc_exit(task, -ENOMEM); 1001 return; 1002 case -ETIMEDOUT: 1003 rpc_delay(task, 3*HZ); 1004 } 1005 - task->tk_action = call_refresh; 1006 } 1007 1008 /*
··· 989 dprint_status(task); 990 991 task->tk_status = 0; 992 + task->tk_action = call_refresh; 993 switch (status) { 994 + case 0: 995 + if (rpcauth_uptodatecred(task)) 996 + task->tk_action = call_allocate; 997 return; 998 case -ETIMEDOUT: 999 rpc_delay(task, 3*HZ); 1000 + case -EAGAIN: 1001 + status = -EACCES; 1002 + if (!task->tk_cred_retry) 1003 + break; 1004 + task->tk_cred_retry--; 1005 + dprintk("RPC: %5u %s: retry refresh creds\n", 1006 + task->tk_pid, __func__); 1007 + return; 1008 } 1009 + dprintk("RPC: %5u %s: refresh creds failed with error %d\n", 1010 + task->tk_pid, __func__, status); 1011 + rpc_exit(task, status); 1012 } 1013 1014 /*