diff options
author | Anna Schumaker <Anna.Schumaker@netapp.com> | 2014-05-06 09:12:36 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-05-28 18:41:12 -0400 |
commit | ef2c488c073f4f0b3a200745dd8d608c01d69c39 (patch) | |
tree | 7bb53a2479bb8df2bb66b0943f4814e0abb20f8b /fs/nfs/pagelist.c | |
parent | 844c9e691d8723853ca8f2de0207683538645824 (diff) |
NFS: Create a generic_pgio function
These functions are almost identical on both the read and write side.
FLUSH_COND_STABLE will never be set for the read path, so leaving it in
the generic code won't hurt anything.
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs/pagelist.c')
-rw-r--r-- | fs/nfs/pagelist.c | 106 |
1 files changed, 101 insertions, 5 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index b0a98daae14c..d8d25a4deb88 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 27 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
28 | 28 | ||
29 | static struct kmem_cache *nfs_page_cachep; | 29 | static struct kmem_cache *nfs_page_cachep; |
30 | static const struct rpc_call_ops nfs_pgio_common_ops; | ||
30 | 31 | ||
31 | static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount) | 32 | static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount) |
32 | { | 33 | { |
@@ -338,8 +339,8 @@ EXPORT_SYMBOL_GPL(nfs_rw_header_free); | |||
338 | * @hdr: The header making a request | 339 | * @hdr: The header making a request |
339 | * @pagecount: Number of pages to create | 340 | * @pagecount: Number of pages to create |
340 | */ | 341 | */ |
341 | struct nfs_pgio_data *nfs_pgio_data_alloc(struct nfs_pgio_header *hdr, | 342 | static struct nfs_pgio_data *nfs_pgio_data_alloc(struct nfs_pgio_header *hdr, |
342 | unsigned int pagecount) | 343 | unsigned int pagecount) |
343 | { | 344 | { |
344 | struct nfs_pgio_data *data, *prealloc; | 345 | struct nfs_pgio_data *data, *prealloc; |
345 | 346 | ||
@@ -396,7 +397,7 @@ EXPORT_SYMBOL_GPL(nfs_pgio_data_release); | |||
396 | * @how: How to commit data (writes only) | 397 | * @how: How to commit data (writes only) |
397 | * @cinfo: Commit information for the call (writes only) | 398 | * @cinfo: Commit information for the call (writes only) |
398 | */ | 399 | */ |
399 | void nfs_pgio_rpcsetup(struct nfs_pgio_data *data, | 400 | static void nfs_pgio_rpcsetup(struct nfs_pgio_data *data, |
400 | unsigned int count, unsigned int offset, | 401 | unsigned int count, unsigned int offset, |
401 | int how, struct nfs_commit_info *cinfo) | 402 | int how, struct nfs_commit_info *cinfo) |
402 | { | 403 | { |
@@ -451,7 +452,7 @@ static void nfs_pgio_prepare(struct rpc_task *task, void *calldata) | |||
451 | * @desc: IO descriptor | 452 | * @desc: IO descriptor |
452 | * @hdr: pageio header | 453 | * @hdr: pageio header |
453 | */ | 454 | */ |
454 | int nfs_pgio_error(struct nfs_pageio_descriptor *desc, | 455 | static int nfs_pgio_error(struct nfs_pageio_descriptor *desc, |
455 | struct nfs_pgio_header *hdr) | 456 | struct nfs_pgio_header *hdr) |
456 | { | 457 | { |
457 | struct nfs_pgio_data *data; | 458 | struct nfs_pgio_data *data; |
@@ -534,6 +535,101 @@ static void nfs_pgio_result(struct rpc_task *task, void *calldata) | |||
534 | data->header->rw_ops->rw_result(task, data); | 535 | data->header->rw_ops->rw_result(task, data); |
535 | } | 536 | } |
536 | 537 | ||
538 | /* | ||
539 | * Generate multiple small requests to read or write a single | ||
540 | * contiguous dirty on one page. | ||
541 | */ | ||
542 | static int nfs_pgio_multi(struct nfs_pageio_descriptor *desc, | ||
543 | struct nfs_pgio_header *hdr) | ||
544 | { | ||
545 | struct nfs_page *req = hdr->req; | ||
546 | struct page *page = req->wb_page; | ||
547 | struct nfs_pgio_data *data; | ||
548 | size_t wsize = desc->pg_bsize, nbytes; | ||
549 | unsigned int offset; | ||
550 | int requests = 0; | ||
551 | struct nfs_commit_info cinfo; | ||
552 | |||
553 | nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); | ||
554 | |||
555 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && | ||
556 | (desc->pg_moreio || nfs_reqs_to_commit(&cinfo) || | ||
557 | desc->pg_count > wsize)) | ||
558 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | ||
559 | |||
560 | offset = 0; | ||
561 | nbytes = desc->pg_count; | ||
562 | do { | ||
563 | size_t len = min(nbytes, wsize); | ||
564 | |||
565 | data = nfs_pgio_data_alloc(hdr, 1); | ||
566 | if (!data) | ||
567 | return nfs_pgio_error(desc, hdr); | ||
568 | data->pages.pagevec[0] = page; | ||
569 | nfs_pgio_rpcsetup(data, len, offset, desc->pg_ioflags, &cinfo); | ||
570 | list_add(&data->list, &hdr->rpc_list); | ||
571 | requests++; | ||
572 | nbytes -= len; | ||
573 | offset += len; | ||
574 | } while (nbytes != 0); | ||
575 | |||
576 | nfs_list_remove_request(req); | ||
577 | nfs_list_add_request(req, &hdr->pages); | ||
578 | desc->pg_rpc_callops = &nfs_pgio_common_ops; | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | /* | ||
583 | * Create an RPC task for the given read or write request and kick it. | ||
584 | * The page must have been locked by the caller. | ||
585 | * | ||
586 | * It may happen that the page we're passed is not marked dirty. | ||
587 | * This is the case if nfs_updatepage detects a conflicting request | ||
588 | * that has been written but not committed. | ||
589 | */ | ||
590 | static int nfs_pgio_one(struct nfs_pageio_descriptor *desc, | ||
591 | struct nfs_pgio_header *hdr) | ||
592 | { | ||
593 | struct nfs_page *req; | ||
594 | struct page **pages; | ||
595 | struct nfs_pgio_data *data; | ||
596 | struct list_head *head = &desc->pg_list; | ||
597 | struct nfs_commit_info cinfo; | ||
598 | |||
599 | data = nfs_pgio_data_alloc(hdr, nfs_page_array_len(desc->pg_base, | ||
600 | desc->pg_count)); | ||
601 | if (!data) | ||
602 | return nfs_pgio_error(desc, hdr); | ||
603 | |||
604 | nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); | ||
605 | pages = data->pages.pagevec; | ||
606 | while (!list_empty(head)) { | ||
607 | req = nfs_list_entry(head->next); | ||
608 | nfs_list_remove_request(req); | ||
609 | nfs_list_add_request(req, &hdr->pages); | ||
610 | *pages++ = req->wb_page; | ||
611 | } | ||
612 | |||
613 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && | ||
614 | (desc->pg_moreio || nfs_reqs_to_commit(&cinfo))) | ||
615 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | ||
616 | |||
617 | /* Set up the argument struct */ | ||
618 | nfs_pgio_rpcsetup(data, desc->pg_count, 0, desc->pg_ioflags, &cinfo); | ||
619 | list_add(&data->list, &hdr->rpc_list); | ||
620 | desc->pg_rpc_callops = &nfs_pgio_common_ops; | ||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, | ||
625 | struct nfs_pgio_header *hdr) | ||
626 | { | ||
627 | if (desc->pg_bsize < PAGE_CACHE_SIZE) | ||
628 | return nfs_pgio_multi(desc, hdr); | ||
629 | return nfs_pgio_one(desc, hdr); | ||
630 | } | ||
631 | EXPORT_SYMBOL_GPL(nfs_generic_pgio); | ||
632 | |||
537 | static bool nfs_match_open_context(const struct nfs_open_context *ctx1, | 633 | static bool nfs_match_open_context(const struct nfs_open_context *ctx1, |
538 | const struct nfs_open_context *ctx2) | 634 | const struct nfs_open_context *ctx2) |
539 | { | 635 | { |
@@ -741,7 +837,7 @@ void nfs_destroy_nfspagecache(void) | |||
741 | kmem_cache_destroy(nfs_page_cachep); | 837 | kmem_cache_destroy(nfs_page_cachep); |
742 | } | 838 | } |
743 | 839 | ||
744 | const struct rpc_call_ops nfs_pgio_common_ops = { | 840 | static const struct rpc_call_ops nfs_pgio_common_ops = { |
745 | .rpc_call_prepare = nfs_pgio_prepare, | 841 | .rpc_call_prepare = nfs_pgio_prepare, |
746 | .rpc_call_done = nfs_pgio_result, | 842 | .rpc_call_done = nfs_pgio_result, |
747 | .rpc_release = nfs_pgio_release, | 843 | .rpc_release = nfs_pgio_release, |