diff options
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r-- | fs/nfs/read.c | 179 |
1 files changed, 84 insertions, 95 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 244a8c45b68e..a9c26521a9e2 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | #include <asm/system.h> | 31 | #include <asm/system.h> |
32 | 32 | ||
33 | #include "internal.h" | ||
33 | #include "iostat.h" | 34 | #include "iostat.h" |
34 | 35 | ||
35 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 36 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
@@ -65,32 +66,22 @@ struct nfs_read_data *nfs_readdata_alloc(size_t len) | |||
65 | return p; | 66 | return p; |
66 | } | 67 | } |
67 | 68 | ||
68 | static void nfs_readdata_free(struct nfs_read_data *p) | 69 | static void nfs_readdata_rcu_free(struct rcu_head *head) |
69 | { | 70 | { |
71 | struct nfs_read_data *p = container_of(head, struct nfs_read_data, task.u.tk_rcu); | ||
70 | if (p && (p->pagevec != &p->page_array[0])) | 72 | if (p && (p->pagevec != &p->page_array[0])) |
71 | kfree(p->pagevec); | 73 | kfree(p->pagevec); |
72 | mempool_free(p, nfs_rdata_mempool); | 74 | mempool_free(p, nfs_rdata_mempool); |
73 | } | 75 | } |
74 | 76 | ||
75 | void nfs_readdata_release(void *data) | 77 | static void nfs_readdata_free(struct nfs_read_data *rdata) |
76 | { | 78 | { |
77 | nfs_readdata_free(data); | 79 | call_rcu_bh(&rdata->task.u.tk_rcu, nfs_readdata_rcu_free); |
78 | } | 80 | } |
79 | 81 | ||
80 | static | 82 | void nfs_readdata_release(void *data) |
81 | unsigned int nfs_page_length(struct inode *inode, struct page *page) | ||
82 | { | 83 | { |
83 | loff_t i_size = i_size_read(inode); | 84 | nfs_readdata_free(data); |
84 | unsigned long idx; | ||
85 | |||
86 | if (i_size <= 0) | ||
87 | return 0; | ||
88 | idx = (i_size - 1) >> PAGE_CACHE_SHIFT; | ||
89 | if (page->index > idx) | ||
90 | return 0; | ||
91 | if (page->index != idx) | ||
92 | return PAGE_CACHE_SIZE; | ||
93 | return 1 + ((i_size - 1) & (PAGE_CACHE_SIZE - 1)); | ||
94 | } | 85 | } |
95 | 86 | ||
96 | static | 87 | static |
@@ -139,12 +130,12 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
139 | { | 130 | { |
140 | unsigned int rsize = NFS_SERVER(inode)->rsize; | 131 | unsigned int rsize = NFS_SERVER(inode)->rsize; |
141 | unsigned int count = PAGE_CACHE_SIZE; | 132 | unsigned int count = PAGE_CACHE_SIZE; |
142 | int result; | 133 | int result = -ENOMEM; |
143 | struct nfs_read_data *rdata; | 134 | struct nfs_read_data *rdata; |
144 | 135 | ||
145 | rdata = nfs_readdata_alloc(count); | 136 | rdata = nfs_readdata_alloc(count); |
146 | if (!rdata) | 137 | if (!rdata) |
147 | return -ENOMEM; | 138 | goto out_unlock; |
148 | 139 | ||
149 | memset(rdata, 0, sizeof(*rdata)); | 140 | memset(rdata, 0, sizeof(*rdata)); |
150 | rdata->flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | 141 | rdata->flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); |
@@ -212,8 +203,9 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
212 | result = 0; | 203 | result = 0; |
213 | 204 | ||
214 | io_error: | 205 | io_error: |
215 | unlock_page(page); | ||
216 | nfs_readdata_free(rdata); | 206 | nfs_readdata_free(rdata); |
207 | out_unlock: | ||
208 | unlock_page(page); | ||
217 | return result; | 209 | return result; |
218 | } | 210 | } |
219 | 211 | ||
@@ -224,7 +216,7 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
224 | struct nfs_page *new; | 216 | struct nfs_page *new; |
225 | unsigned int len; | 217 | unsigned int len; |
226 | 218 | ||
227 | len = nfs_page_length(inode, page); | 219 | len = nfs_page_length(page); |
228 | if (len == 0) | 220 | if (len == 0) |
229 | return nfs_return_empty_page(page); | 221 | return nfs_return_empty_page(page); |
230 | new = nfs_create_request(ctx, inode, page, 0, len); | 222 | new = nfs_create_request(ctx, inode, page, 0, len); |
@@ -316,9 +308,7 @@ static void nfs_execute_read(struct nfs_read_data *data) | |||
316 | sigset_t oldset; | 308 | sigset_t oldset; |
317 | 309 | ||
318 | rpc_clnt_sigmask(clnt, &oldset); | 310 | rpc_clnt_sigmask(clnt, &oldset); |
319 | lock_kernel(); | ||
320 | rpc_execute(&data->task); | 311 | rpc_execute(&data->task); |
321 | unlock_kernel(); | ||
322 | rpc_clnt_sigunmask(clnt, &oldset); | 312 | rpc_clnt_sigunmask(clnt, &oldset); |
323 | } | 313 | } |
324 | 314 | ||
@@ -455,6 +445,55 @@ nfs_pagein_list(struct list_head *head, int rpages) | |||
455 | } | 445 | } |
456 | 446 | ||
457 | /* | 447 | /* |
448 | * This is the callback from RPC telling us whether a reply was | ||
449 | * received or some error occurred (timeout or socket shutdown). | ||
450 | */ | ||
451 | int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | ||
452 | { | ||
453 | int status; | ||
454 | |||
455 | dprintk("%s: %4d, (status %d)\n", __FUNCTION__, task->tk_pid, | ||
456 | task->tk_status); | ||
457 | |||
458 | status = NFS_PROTO(data->inode)->read_done(task, data); | ||
459 | if (status != 0) | ||
460 | return status; | ||
461 | |||
462 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, data->res.count); | ||
463 | |||
464 | if (task->tk_status == -ESTALE) { | ||
465 | set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); | ||
466 | nfs_mark_for_revalidate(data->inode); | ||
467 | } | ||
468 | spin_lock(&data->inode->i_lock); | ||
469 | NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; | ||
470 | spin_unlock(&data->inode->i_lock); | ||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static int nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) | ||
475 | { | ||
476 | struct nfs_readargs *argp = &data->args; | ||
477 | struct nfs_readres *resp = &data->res; | ||
478 | |||
479 | if (resp->eof || resp->count == argp->count) | ||
480 | return 0; | ||
481 | |||
482 | /* This is a short read! */ | ||
483 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | ||
484 | /* Has the server at least made some progress? */ | ||
485 | if (resp->count == 0) | ||
486 | return 0; | ||
487 | |||
488 | /* Yes, so retry the read at the end of the data */ | ||
489 | argp->offset += resp->count; | ||
490 | argp->pgbase += resp->count; | ||
491 | argp->count -= resp->count; | ||
492 | rpc_restart_call(task); | ||
493 | return -EAGAIN; | ||
494 | } | ||
495 | |||
496 | /* | ||
458 | * Handle a read reply that fills part of a page. | 497 | * Handle a read reply that fills part of a page. |
459 | */ | 498 | */ |
460 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) | 499 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) |
@@ -463,12 +502,16 @@ static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) | |||
463 | struct nfs_page *req = data->req; | 502 | struct nfs_page *req = data->req; |
464 | struct page *page = req->wb_page; | 503 | struct page *page = req->wb_page; |
465 | 504 | ||
466 | if (likely(task->tk_status >= 0)) | ||
467 | nfs_readpage_truncate_uninitialised_page(data); | ||
468 | else | ||
469 | SetPageError(page); | ||
470 | if (nfs_readpage_result(task, data) != 0) | 505 | if (nfs_readpage_result(task, data) != 0) |
471 | return; | 506 | return; |
507 | |||
508 | if (likely(task->tk_status >= 0)) { | ||
509 | nfs_readpage_truncate_uninitialised_page(data); | ||
510 | if (nfs_readpage_retry(task, data) != 0) | ||
511 | return; | ||
512 | } | ||
513 | if (unlikely(task->tk_status < 0)) | ||
514 | SetPageError(page); | ||
472 | if (atomic_dec_and_test(&req->wb_complete)) { | 515 | if (atomic_dec_and_test(&req->wb_complete)) { |
473 | if (!PageError(page)) | 516 | if (!PageError(page)) |
474 | SetPageUptodate(page); | 517 | SetPageUptodate(page); |
@@ -496,25 +539,13 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) | |||
496 | count += base; | 539 | count += base; |
497 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) | 540 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) |
498 | SetPageUptodate(*pages); | 541 | SetPageUptodate(*pages); |
499 | if (count != 0) | 542 | if (count == 0) |
543 | return; | ||
544 | /* Was this a short read? */ | ||
545 | if (data->res.eof || data->res.count == data->args.count) | ||
500 | SetPageUptodate(*pages); | 546 | SetPageUptodate(*pages); |
501 | } | 547 | } |
502 | 548 | ||
503 | static void nfs_readpage_set_pages_error(struct nfs_read_data *data) | ||
504 | { | ||
505 | unsigned int count = data->args.count; | ||
506 | unsigned int base = data->args.pgbase; | ||
507 | struct page **pages; | ||
508 | |||
509 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; | ||
510 | base &= ~PAGE_CACHE_MASK; | ||
511 | count += base; | ||
512 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) | ||
513 | SetPageError(*pages); | ||
514 | if (count != 0) | ||
515 | SetPageError(*pages); | ||
516 | } | ||
517 | |||
518 | /* | 549 | /* |
519 | * This is the callback from RPC telling us whether a reply was | 550 | * This is the callback from RPC telling us whether a reply was |
520 | * received or some error occurred (timeout or socket shutdown). | 551 | * received or some error occurred (timeout or socket shutdown). |
@@ -523,19 +554,20 @@ static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) | |||
523 | { | 554 | { |
524 | struct nfs_read_data *data = calldata; | 555 | struct nfs_read_data *data = calldata; |
525 | 556 | ||
557 | if (nfs_readpage_result(task, data) != 0) | ||
558 | return; | ||
526 | /* | 559 | /* |
527 | * Note: nfs_readpage_result may change the values of | 560 | * Note: nfs_readpage_retry may change the values of |
528 | * data->args. In the multi-page case, we therefore need | 561 | * data->args. In the multi-page case, we therefore need |
529 | * to ensure that we call the next nfs_readpage_set_page_uptodate() | 562 | * to ensure that we call nfs_readpage_set_pages_uptodate() |
530 | * first in the multi-page case. | 563 | * first. |
531 | */ | 564 | */ |
532 | if (likely(task->tk_status >= 0)) { | 565 | if (likely(task->tk_status >= 0)) { |
533 | nfs_readpage_truncate_uninitialised_page(data); | 566 | nfs_readpage_truncate_uninitialised_page(data); |
534 | nfs_readpage_set_pages_uptodate(data); | 567 | nfs_readpage_set_pages_uptodate(data); |
535 | } else | 568 | if (nfs_readpage_retry(task, data) != 0) |
536 | nfs_readpage_set_pages_error(data); | 569 | return; |
537 | if (nfs_readpage_result(task, data) != 0) | 570 | } |
538 | return; | ||
539 | while (!list_empty(&data->pages)) { | 571 | while (!list_empty(&data->pages)) { |
540 | struct nfs_page *req = nfs_list_entry(data->pages.next); | 572 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
541 | 573 | ||
@@ -550,50 +582,6 @@ static const struct rpc_call_ops nfs_read_full_ops = { | |||
550 | }; | 582 | }; |
551 | 583 | ||
552 | /* | 584 | /* |
553 | * This is the callback from RPC telling us whether a reply was | ||
554 | * received or some error occurred (timeout or socket shutdown). | ||
555 | */ | ||
556 | int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | ||
557 | { | ||
558 | struct nfs_readargs *argp = &data->args; | ||
559 | struct nfs_readres *resp = &data->res; | ||
560 | int status; | ||
561 | |||
562 | dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", | ||
563 | task->tk_pid, task->tk_status); | ||
564 | |||
565 | status = NFS_PROTO(data->inode)->read_done(task, data); | ||
566 | if (status != 0) | ||
567 | return status; | ||
568 | |||
569 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, resp->count); | ||
570 | |||
571 | if (task->tk_status < 0) { | ||
572 | if (task->tk_status == -ESTALE) { | ||
573 | set_bit(NFS_INO_STALE, &NFS_FLAGS(data->inode)); | ||
574 | nfs_mark_for_revalidate(data->inode); | ||
575 | } | ||
576 | } else if (resp->count < argp->count && !resp->eof) { | ||
577 | /* This is a short read! */ | ||
578 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | ||
579 | /* Has the server at least made some progress? */ | ||
580 | if (resp->count != 0) { | ||
581 | /* Yes, so retry the read at the end of the data */ | ||
582 | argp->offset += resp->count; | ||
583 | argp->pgbase += resp->count; | ||
584 | argp->count -= resp->count; | ||
585 | rpc_restart_call(task); | ||
586 | return -EAGAIN; | ||
587 | } | ||
588 | task->tk_status = -EIO; | ||
589 | } | ||
590 | spin_lock(&data->inode->i_lock); | ||
591 | NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; | ||
592 | spin_unlock(&data->inode->i_lock); | ||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | /* | ||
597 | * Read a page over NFS. | 585 | * Read a page over NFS. |
598 | * We read the page synchronously in the following case: | 586 | * We read the page synchronously in the following case: |
599 | * - The error flag is set for this page. This happens only when a | 587 | * - The error flag is set for this page. This happens only when a |
@@ -626,9 +614,10 @@ int nfs_readpage(struct file *file, struct page *page) | |||
626 | goto out_error; | 614 | goto out_error; |
627 | 615 | ||
628 | if (file == NULL) { | 616 | if (file == NULL) { |
617 | error = -EBADF; | ||
629 | ctx = nfs_find_open_context(inode, NULL, FMODE_READ); | 618 | ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
630 | if (ctx == NULL) | 619 | if (ctx == NULL) |
631 | return -EBADF; | 620 | goto out_error; |
632 | } else | 621 | } else |
633 | ctx = get_nfs_open_context((struct nfs_open_context *) | 622 | ctx = get_nfs_open_context((struct nfs_open_context *) |
634 | file->private_data); | 623 | file->private_data); |
@@ -663,7 +652,7 @@ readpage_async_filler(void *data, struct page *page) | |||
663 | unsigned int len; | 652 | unsigned int len; |
664 | 653 | ||
665 | nfs_wb_page(inode, page); | 654 | nfs_wb_page(inode, page); |
666 | len = nfs_page_length(inode, page); | 655 | len = nfs_page_length(page); |
667 | if (len == 0) | 656 | if (len == 0) |
668 | return nfs_return_empty_page(page); | 657 | return nfs_return_empty_page(page); |
669 | new = nfs_create_request(desc->ctx, inode, page, 0, len); | 658 | new = nfs_create_request(desc->ctx, inode, page, 0, len); |