aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/pagelist.c
diff options
context:
space:
mode:
authorAnna Schumaker <Anna.Schumaker@netapp.com>2014-05-06 09:12:36 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-05-28 18:41:12 -0400
commitef2c488c073f4f0b3a200745dd8d608c01d69c39 (patch)
tree7bb53a2479bb8df2bb66b0943f4814e0abb20f8b /fs/nfs/pagelist.c
parent844c9e691d8723853ca8f2de0207683538645824 (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.c106
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
29static struct kmem_cache *nfs_page_cachep; 29static struct kmem_cache *nfs_page_cachep;
30static const struct rpc_call_ops nfs_pgio_common_ops;
30 31
31static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount) 32static 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 */
341struct nfs_pgio_data *nfs_pgio_data_alloc(struct nfs_pgio_header *hdr, 342static 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 */
399void nfs_pgio_rpcsetup(struct nfs_pgio_data *data, 400static 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 */
454int nfs_pgio_error(struct nfs_pageio_descriptor *desc, 455static 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 */
542static 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 */
590static 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
624int 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}
631EXPORT_SYMBOL_GPL(nfs_generic_pgio);
632
537static bool nfs_match_open_context(const struct nfs_open_context *ctx1, 633static 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
744const struct rpc_call_ops nfs_pgio_common_ops = { 840static 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,