diff options
| -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 | } |
| 829 | if (res == -ETOOSMALL && desc->plus) { | 837 | if (res == -ETOOSMALL && desc->plus) { |
| @@ -838,10 +846,8 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 838 | break; | 846 | break; |
| 839 | 847 | ||
| 840 | res = nfs_do_filldir(desc, dirent, filldir); | 848 | res = nfs_do_filldir(desc, dirent, filldir); |
| 841 | if (res < 0) { | 849 | if (res < 0) |
| 842 | res = 0; | ||
| 843 | break; | 850 | break; |
| 844 | } | ||
| 845 | } | 851 | } |
| 846 | out: | 852 | out: |
| 847 | nfs_unblock_sillyrename(dentry); | 853 | nfs_unblock_sillyrename(dentry); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 84d3c8b90206..e6ace0d93c71 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
| @@ -867,7 +867,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 867 | goto out; | 867 | goto out; |
| 868 | nfs_alloc_commit_data(dreq); | 868 | nfs_alloc_commit_data(dreq); |
| 869 | 869 | ||
| 870 | if (dreq->commit_data == NULL || count < wsize) | 870 | if (dreq->commit_data == NULL || count <= wsize) |
| 871 | sync = NFS_FILE_SYNC; | 871 | sync = NFS_FILE_SYNC; |
| 872 | 872 | ||
| 873 | dreq->inode = inode; | 873 | dreq->inode = inode; |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index db08ff3ff454..e6356b750b77 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -362,6 +362,15 @@ unsigned int nfs_page_length(struct page *page) | |||
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | /* | 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 | /* | ||
| 365 | * Determine the number of pages in an array of length 'len' and | 374 | * Determine the number of pages in an array of length 'len' and |
| 366 | * with a base offset of 'base' | 375 | * with a base offset of 'base' |
| 367 | */ | 376 | */ |
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 2563f765c9b4..5914a1911c95 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
| @@ -485,6 +485,8 @@ nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_se | |||
| 485 | entry->prev_cookie = entry->cookie; | 485 | entry->prev_cookie = entry->cookie; |
| 486 | entry->cookie = ntohl(*p++); | 486 | entry->cookie = ntohl(*p++); |
| 487 | 487 | ||
| 488 | entry->d_type = DT_UNKNOWN; | ||
| 489 | |||
| 488 | p = xdr_inline_peek(xdr, 8); | 490 | p = xdr_inline_peek(xdr, 8); |
| 489 | if (p != NULL) | 491 | if (p != NULL) |
| 490 | entry->eof = !p[0] && p[1]; | 492 | entry->eof = !p[0] && p[1]; |
| @@ -495,7 +497,7 @@ nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_se | |||
| 495 | 497 | ||
| 496 | out_overflow: | 498 | out_overflow: |
| 497 | print_overflow_msg(__func__, xdr); | 499 | print_overflow_msg(__func__, xdr); |
| 498 | return ERR_PTR(-EIO); | 500 | return ERR_PTR(-EAGAIN); |
| 499 | } | 501 | } |
| 500 | 502 | ||
| 501 | /* | 503 | /* |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 748dc91a4a14..f6cc60f06dac 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
| @@ -622,11 +622,13 @@ nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_s | |||
| 622 | entry->prev_cookie = entry->cookie; | 622 | entry->prev_cookie = entry->cookie; |
| 623 | p = xdr_decode_hyper(p, &entry->cookie); | 623 | p = xdr_decode_hyper(p, &entry->cookie); |
| 624 | 624 | ||
| 625 | entry->d_type = DT_UNKNOWN; | ||
| 625 | if (plus) { | 626 | if (plus) { |
| 626 | entry->fattr->valid = 0; | 627 | entry->fattr->valid = 0; |
| 627 | p = xdr_decode_post_op_attr_stream(xdr, entry->fattr); | 628 | p = xdr_decode_post_op_attr_stream(xdr, entry->fattr); |
| 628 | if (IS_ERR(p)) | 629 | if (IS_ERR(p)) |
| 629 | goto out_overflow_exit; | 630 | goto out_overflow_exit; |
| 631 | entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); | ||
| 630 | /* In fact, a post_op_fh3: */ | 632 | /* In fact, a post_op_fh3: */ |
| 631 | p = xdr_inline_decode(xdr, 4); | 633 | p = xdr_inline_decode(xdr, 4); |
| 632 | if (unlikely(!p)) | 634 | if (unlikely(!p)) |
| @@ -656,7 +658,7 @@ nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_s | |||
| 656 | out_overflow: | 658 | out_overflow: |
| 657 | print_overflow_msg(__func__, xdr); | 659 | print_overflow_msg(__func__, xdr); |
| 658 | out_overflow_exit: | 660 | out_overflow_exit: |
| 659 | return ERR_PTR(-EIO); | 661 | return ERR_PTR(-EAGAIN); |
| 660 | } | 662 | } |
| 661 | 663 | ||
| 662 | /* | 664 | /* |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index b7a204ff6fe1..9f1826b012e6 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -6208,6 +6208,10 @@ __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
| 6208 | if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) | 6208 | if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID) |
| 6209 | entry->ino = entry->fattr->fileid; | 6209 | entry->ino = entry->fattr->fileid; |
| 6210 | 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 | |||
| 6211 | if (verify_attr_len(xdr, p, len) < 0) | 6215 | if (verify_attr_len(xdr, p, len) < 0) |
| 6212 | goto out_overflow; | 6216 | goto out_overflow; |
| 6213 | 6217 | ||
| @@ -6221,7 +6225,7 @@ __be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, | |||
| 6221 | 6225 | ||
| 6222 | out_overflow: | 6226 | out_overflow: |
| 6223 | print_overflow_msg(__func__, xdr); | 6227 | print_overflow_msg(__func__, xdr); |
| 6224 | return ERR_PTR(-EIO); | 6228 | return ERR_PTR(-EAGAIN); |
| 6225 | } | 6229 | } |
| 6226 | 6230 | ||
| 6227 | /* | 6231 | /* |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index ba6cc8f223c9..80f07198a31a 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
| @@ -483,6 +483,7 @@ struct nfs_entry { | |||
| 483 | int eof; | 483 | int eof; |
| 484 | struct nfs_fh * fh; | 484 | struct nfs_fh * fh; |
| 485 | struct nfs_fattr * fattr; | 485 | struct nfs_fattr * fattr; |
| 486 | unsigned char d_type; | ||
| 486 | }; | 487 | }; |
| 487 | 488 | ||
| 488 | /* | 489 | /* |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 9dab9573be41..92ce94f5146b 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -989,20 +989,26 @@ call_refreshresult(struct rpc_task *task) | |||
| 989 | dprint_status(task); | 989 | dprint_status(task); |
| 990 | 990 | ||
| 991 | task->tk_status = 0; | 991 | task->tk_status = 0; |
| 992 | task->tk_action = call_allocate; | 992 | task->tk_action = call_refresh; |
| 993 | if (status >= 0 && rpcauth_uptodatecred(task)) | ||
| 994 | return; | ||
| 995 | switch (status) { | 993 | switch (status) { |
| 996 | case -EACCES: | 994 | case 0: |
| 997 | rpc_exit(task, -EACCES); | 995 | if (rpcauth_uptodatecred(task)) |
| 998 | return; | 996 | task->tk_action = call_allocate; |
| 999 | case -ENOMEM: | ||
| 1000 | rpc_exit(task, -ENOMEM); | ||
| 1001 | return; | 997 | return; |
| 1002 | case -ETIMEDOUT: | 998 | case -ETIMEDOUT: |
| 1003 | rpc_delay(task, 3*HZ); | 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; | ||
| 1004 | } | 1008 | } |
| 1005 | task->tk_action = call_refresh; | 1009 | dprintk("RPC: %5u %s: refresh creds failed with error %d\n", |
| 1010 | task->tk_pid, __func__, status); | ||
| 1011 | rpc_exit(task, status); | ||
| 1006 | } | 1012 | } |
| 1007 | 1013 | ||
| 1008 | /* | 1014 | /* |
