diff options
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r-- | fs/nfs/read.c | 102 |
1 files changed, 84 insertions, 18 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 05eb43fadf8e..3961524fd4ab 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -31,17 +31,49 @@ | |||
31 | 31 | ||
32 | #include <asm/system.h> | 32 | #include <asm/system.h> |
33 | 33 | ||
34 | #include "iostat.h" | ||
35 | |||
34 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 36 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
35 | 37 | ||
36 | static int nfs_pagein_one(struct list_head *, struct inode *); | 38 | static int nfs_pagein_one(struct list_head *, struct inode *); |
37 | static void nfs_readpage_result_partial(struct nfs_read_data *, int); | 39 | static const struct rpc_call_ops nfs_read_partial_ops; |
38 | static void nfs_readpage_result_full(struct nfs_read_data *, int); | 40 | static const struct rpc_call_ops nfs_read_full_ops; |
39 | 41 | ||
40 | static kmem_cache_t *nfs_rdata_cachep; | 42 | static kmem_cache_t *nfs_rdata_cachep; |
41 | mempool_t *nfs_rdata_mempool; | 43 | static mempool_t *nfs_rdata_mempool; |
42 | 44 | ||
43 | #define MIN_POOL_READ (32) | 45 | #define MIN_POOL_READ (32) |
44 | 46 | ||
47 | struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | ||
48 | { | ||
49 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, SLAB_NOFS); | ||
50 | |||
51 | if (p) { | ||
52 | memset(p, 0, sizeof(*p)); | ||
53 | INIT_LIST_HEAD(&p->pages); | ||
54 | if (pagecount < NFS_PAGEVEC_SIZE) | ||
55 | p->pagevec = &p->page_array[0]; | ||
56 | else { | ||
57 | size_t size = ++pagecount * sizeof(struct page *); | ||
58 | p->pagevec = kmalloc(size, GFP_NOFS); | ||
59 | if (p->pagevec) { | ||
60 | memset(p->pagevec, 0, size); | ||
61 | } else { | ||
62 | mempool_free(p, nfs_rdata_mempool); | ||
63 | p = NULL; | ||
64 | } | ||
65 | } | ||
66 | } | ||
67 | return p; | ||
68 | } | ||
69 | |||
70 | void nfs_readdata_free(struct nfs_read_data *p) | ||
71 | { | ||
72 | if (p && (p->pagevec != &p->page_array[0])) | ||
73 | kfree(p->pagevec); | ||
74 | mempool_free(p, nfs_rdata_mempool); | ||
75 | } | ||
76 | |||
45 | void nfs_readdata_release(void *data) | 77 | void nfs_readdata_release(void *data) |
46 | { | 78 | { |
47 | nfs_readdata_free(data); | 79 | nfs_readdata_free(data); |
@@ -133,6 +165,8 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
133 | } | 165 | } |
134 | count -= result; | 166 | count -= result; |
135 | rdata->args.pgbase += result; | 167 | rdata->args.pgbase += result; |
168 | nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, result); | ||
169 | |||
136 | /* Note: result == 0 should only happen if we're caching | 170 | /* Note: result == 0 should only happen if we're caching |
137 | * a write that extends the file and punches a hole. | 171 | * a write that extends the file and punches a hole. |
138 | */ | 172 | */ |
@@ -196,9 +230,11 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
196 | * Set up the NFS read request struct | 230 | * Set up the NFS read request struct |
197 | */ | 231 | */ |
198 | static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | 232 | static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, |
233 | const struct rpc_call_ops *call_ops, | ||
199 | unsigned int count, unsigned int offset) | 234 | unsigned int count, unsigned int offset) |
200 | { | 235 | { |
201 | struct inode *inode; | 236 | struct inode *inode; |
237 | int flags; | ||
202 | 238 | ||
203 | data->req = req; | 239 | data->req = req; |
204 | data->inode = inode = req->wb_context->dentry->d_inode; | 240 | data->inode = inode = req->wb_context->dentry->d_inode; |
@@ -216,6 +252,9 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
216 | data->res.eof = 0; | 252 | data->res.eof = 0; |
217 | nfs_fattr_init(&data->fattr); | 253 | nfs_fattr_init(&data->fattr); |
218 | 254 | ||
255 | /* Set up the initial task struct. */ | ||
256 | flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | ||
257 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | ||
219 | NFS_PROTO(inode)->read_setup(data); | 258 | NFS_PROTO(inode)->read_setup(data); |
220 | 259 | ||
221 | data->task.tk_cookie = (unsigned long)inode; | 260 | data->task.tk_cookie = (unsigned long)inode; |
@@ -303,14 +342,15 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | |||
303 | list_del_init(&data->pages); | 342 | list_del_init(&data->pages); |
304 | 343 | ||
305 | data->pagevec[0] = page; | 344 | data->pagevec[0] = page; |
306 | data->complete = nfs_readpage_result_partial; | ||
307 | 345 | ||
308 | if (nbytes > rsize) { | 346 | if (nbytes > rsize) { |
309 | nfs_read_rpcsetup(req, data, rsize, offset); | 347 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
348 | rsize, offset); | ||
310 | offset += rsize; | 349 | offset += rsize; |
311 | nbytes -= rsize; | 350 | nbytes -= rsize; |
312 | } else { | 351 | } else { |
313 | nfs_read_rpcsetup(req, data, nbytes, offset); | 352 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
353 | nbytes, offset); | ||
314 | nbytes = 0; | 354 | nbytes = 0; |
315 | } | 355 | } |
316 | nfs_execute_read(data); | 356 | nfs_execute_read(data); |
@@ -356,8 +396,7 @@ static int nfs_pagein_one(struct list_head *head, struct inode *inode) | |||
356 | } | 396 | } |
357 | req = nfs_list_entry(data->pages.next); | 397 | req = nfs_list_entry(data->pages.next); |
358 | 398 | ||
359 | data->complete = nfs_readpage_result_full; | 399 | nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); |
360 | nfs_read_rpcsetup(req, data, count, 0); | ||
361 | 400 | ||
362 | nfs_execute_read(data); | 401 | nfs_execute_read(data); |
363 | return 0; | 402 | return 0; |
@@ -391,12 +430,15 @@ nfs_pagein_list(struct list_head *head, int rpages) | |||
391 | /* | 430 | /* |
392 | * Handle a read reply that fills part of a page. | 431 | * Handle a read reply that fills part of a page. |
393 | */ | 432 | */ |
394 | static void nfs_readpage_result_partial(struct nfs_read_data *data, int status) | 433 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) |
395 | { | 434 | { |
435 | struct nfs_read_data *data = calldata; | ||
396 | struct nfs_page *req = data->req; | 436 | struct nfs_page *req = data->req; |
397 | struct page *page = req->wb_page; | 437 | struct page *page = req->wb_page; |
398 | 438 | ||
399 | if (status >= 0) { | 439 | if (nfs_readpage_result(task, data) != 0) |
440 | return; | ||
441 | if (task->tk_status >= 0) { | ||
400 | unsigned int request = data->args.count; | 442 | unsigned int request = data->args.count; |
401 | unsigned int result = data->res.count; | 443 | unsigned int result = data->res.count; |
402 | 444 | ||
@@ -415,20 +457,28 @@ static void nfs_readpage_result_partial(struct nfs_read_data *data, int status) | |||
415 | } | 457 | } |
416 | } | 458 | } |
417 | 459 | ||
460 | static const struct rpc_call_ops nfs_read_partial_ops = { | ||
461 | .rpc_call_done = nfs_readpage_result_partial, | ||
462 | .rpc_release = nfs_readdata_release, | ||
463 | }; | ||
464 | |||
418 | /* | 465 | /* |
419 | * This is the callback from RPC telling us whether a reply was | 466 | * This is the callback from RPC telling us whether a reply was |
420 | * received or some error occurred (timeout or socket shutdown). | 467 | * received or some error occurred (timeout or socket shutdown). |
421 | */ | 468 | */ |
422 | static void nfs_readpage_result_full(struct nfs_read_data *data, int status) | 469 | static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) |
423 | { | 470 | { |
471 | struct nfs_read_data *data = calldata; | ||
424 | unsigned int count = data->res.count; | 472 | unsigned int count = data->res.count; |
425 | 473 | ||
474 | if (nfs_readpage_result(task, data) != 0) | ||
475 | return; | ||
426 | while (!list_empty(&data->pages)) { | 476 | while (!list_empty(&data->pages)) { |
427 | struct nfs_page *req = nfs_list_entry(data->pages.next); | 477 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
428 | struct page *page = req->wb_page; | 478 | struct page *page = req->wb_page; |
429 | nfs_list_remove_request(req); | 479 | nfs_list_remove_request(req); |
430 | 480 | ||
431 | if (status >= 0) { | 481 | if (task->tk_status >= 0) { |
432 | if (count < PAGE_CACHE_SIZE) { | 482 | if (count < PAGE_CACHE_SIZE) { |
433 | if (count < req->wb_bytes) | 483 | if (count < req->wb_bytes) |
434 | memclear_highpage_flush(page, | 484 | memclear_highpage_flush(page, |
@@ -444,22 +494,33 @@ static void nfs_readpage_result_full(struct nfs_read_data *data, int status) | |||
444 | } | 494 | } |
445 | } | 495 | } |
446 | 496 | ||
497 | static const struct rpc_call_ops nfs_read_full_ops = { | ||
498 | .rpc_call_done = nfs_readpage_result_full, | ||
499 | .rpc_release = nfs_readdata_release, | ||
500 | }; | ||
501 | |||
447 | /* | 502 | /* |
448 | * This is the callback from RPC telling us whether a reply was | 503 | * This is the callback from RPC telling us whether a reply was |
449 | * received or some error occurred (timeout or socket shutdown). | 504 | * received or some error occurred (timeout or socket shutdown). |
450 | */ | 505 | */ |
451 | void nfs_readpage_result(struct rpc_task *task, void *calldata) | 506 | int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) |
452 | { | 507 | { |
453 | struct nfs_read_data *data = calldata; | ||
454 | struct nfs_readargs *argp = &data->args; | 508 | struct nfs_readargs *argp = &data->args; |
455 | struct nfs_readres *resp = &data->res; | 509 | struct nfs_readres *resp = &data->res; |
456 | int status = task->tk_status; | 510 | int status; |
457 | 511 | ||
458 | dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", | 512 | dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", |
459 | task->tk_pid, status); | 513 | task->tk_pid, task->tk_status); |
514 | |||
515 | status = NFS_PROTO(data->inode)->read_done(task, data); | ||
516 | if (status != 0) | ||
517 | return status; | ||
518 | |||
519 | nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, resp->count); | ||
460 | 520 | ||
461 | /* Is this a short read? */ | 521 | /* Is this a short read? */ |
462 | if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) { | 522 | if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) { |
523 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | ||
463 | /* Has the server at least made some progress? */ | 524 | /* Has the server at least made some progress? */ |
464 | if (resp->count != 0) { | 525 | if (resp->count != 0) { |
465 | /* Yes, so retry the read at the end of the data */ | 526 | /* Yes, so retry the read at the end of the data */ |
@@ -467,14 +528,14 @@ void nfs_readpage_result(struct rpc_task *task, void *calldata) | |||
467 | argp->pgbase += resp->count; | 528 | argp->pgbase += resp->count; |
468 | argp->count -= resp->count; | 529 | argp->count -= resp->count; |
469 | rpc_restart_call(task); | 530 | rpc_restart_call(task); |
470 | return; | 531 | return -EAGAIN; |
471 | } | 532 | } |
472 | task->tk_status = -EIO; | 533 | task->tk_status = -EIO; |
473 | } | 534 | } |
474 | spin_lock(&data->inode->i_lock); | 535 | spin_lock(&data->inode->i_lock); |
475 | NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; | 536 | NFS_I(data->inode)->cache_validity |= NFS_INO_INVALID_ATIME; |
476 | spin_unlock(&data->inode->i_lock); | 537 | spin_unlock(&data->inode->i_lock); |
477 | data->complete(data, status); | 538 | return 0; |
478 | } | 539 | } |
479 | 540 | ||
480 | /* | 541 | /* |
@@ -491,6 +552,9 @@ int nfs_readpage(struct file *file, struct page *page) | |||
491 | 552 | ||
492 | dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", | 553 | dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", |
493 | page, PAGE_CACHE_SIZE, page->index); | 554 | page, PAGE_CACHE_SIZE, page->index); |
555 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGE); | ||
556 | nfs_add_stats(inode, NFSIOS_READPAGES, 1); | ||
557 | |||
494 | /* | 558 | /* |
495 | * Try to flush any pending writes to the file.. | 559 | * Try to flush any pending writes to the file.. |
496 | * | 560 | * |
@@ -570,6 +634,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
570 | inode->i_sb->s_id, | 634 | inode->i_sb->s_id, |
571 | (long long)NFS_FILEID(inode), | 635 | (long long)NFS_FILEID(inode), |
572 | nr_pages); | 636 | nr_pages); |
637 | nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); | ||
573 | 638 | ||
574 | if (filp == NULL) { | 639 | if (filp == NULL) { |
575 | desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); | 640 | desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
@@ -582,6 +647,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
582 | if (!list_empty(&head)) { | 647 | if (!list_empty(&head)) { |
583 | int err = nfs_pagein_list(&head, server->rpages); | 648 | int err = nfs_pagein_list(&head, server->rpages); |
584 | if (!ret) | 649 | if (!ret) |
650 | nfs_add_stats(inode, NFSIOS_READPAGES, err); | ||
585 | ret = err; | 651 | ret = err; |
586 | } | 652 | } |
587 | put_nfs_open_context(desc.ctx); | 653 | put_nfs_open_context(desc.ctx); |