aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/pagelist.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/pagelist.c')
-rw-r--r--fs/nfs/pagelist.c117
1 files changed, 85 insertions, 32 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index ca4b1d4..7017eb0 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -223,48 +223,101 @@ out:
}
/**
- * nfs_coalesce_requests - Split coalesced requests out from a list.
+ * nfs_pageio_init - initialise a page io descriptor
+ * @desc: pointer to descriptor
+ * @iosize: io block size
+ */
+void nfs_pageio_init(struct nfs_pageio_descriptor *desc, unsigned int bsize)
+{
+ INIT_LIST_HEAD(&desc->pg_list);
+ desc->pg_count = 0;
+ desc->pg_bsize = bsize;
+ desc->pg_base = 0;
+}
+
+/**
+ * nfs_can_coalesce_requests - test two requests for compatibility
+ * @prev: pointer to nfs_page
+ * @req: pointer to nfs_page
+ *
+ * The nfs_page structures 'prev' and 'req' are compared to ensure that the
+ * page data area they describe is contiguous, and that their RPC
+ * credentials, NFSv4 open state, and lockowners are the same.
+ *
+ * Return 'true' if this is the case, else return 'false'.
+ */
+static int nfs_can_coalesce_requests(struct nfs_page *prev,
+ struct nfs_page *req)
+{
+ if (req->wb_context->cred != prev->wb_context->cred)
+ return 0;
+ if (req->wb_context->lockowner != prev->wb_context->lockowner)
+ return 0;
+ if (req->wb_context->state != prev->wb_context->state)
+ return 0;
+ if (req->wb_index != (prev->wb_index + 1))
+ return 0;
+ if (req->wb_pgbase != 0)
+ return 0;
+ if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
+ return 0;
+ return 1;
+}
+
+/**
+ * nfs_pageio_add_request - Attempt to coalesce a request into a page list.
+ * @desc: destination io descriptor
+ * @req: request
+ *
+ * Returns true if the request 'req' was successfully coalesced into the
+ * existing list of pages 'desc'.
+ */
+static int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
+ struct nfs_page *req)
+{
+ size_t newlen = req->wb_bytes;
+
+ if (desc->pg_count != 0) {
+ struct nfs_page *prev;
+
+ /*
+ * FIXME: ideally we should be able to coalesce all requests
+ * that are not block boundary aligned, but currently this
+ * is problematic for the case of bsize < PAGE_CACHE_SIZE,
+ * since nfs_flush_multi and nfs_pagein_multi assume you
+ * can have only one struct nfs_page.
+ */
+ newlen += desc->pg_count;
+ if (desc->pg_base + newlen > desc->pg_bsize)
+ return 0;
+ prev = nfs_list_entry(desc->pg_list.prev);
+ if (!nfs_can_coalesce_requests(prev, req))
+ return 0;
+ } else
+ desc->pg_base = req->wb_pgbase;
+ nfs_list_remove_request(req);
+ nfs_list_add_request(req, &desc->pg_list);
+ desc->pg_count = newlen;
+ return 1;
+}
+
+/**
+ * nfs_pageio_add_list - Split coalesced requests out from a list.
+ * @desc: destination io descriptor
* @head: source list
- * @dst: destination list
- * @nmax: maximum number of requests to coalesce
*
* Moves a maximum of 'nmax' elements from one list to another.
* The elements are checked to ensure that they form a contiguous set
* of pages, and that the RPC credentials are the same.
*/
-int
-nfs_coalesce_requests(struct list_head *head, struct list_head *dst,
- unsigned int nmax)
+void nfs_pageio_add_list(struct nfs_pageio_descriptor *desc,
+ struct list_head *head)
{
- struct nfs_page *req = NULL;
- unsigned int npages = 0;
-
while (!list_empty(head)) {
- struct nfs_page *prev = req;
-
- req = nfs_list_entry(head->next);
- if (prev) {
- if (req->wb_context->cred != prev->wb_context->cred)
- break;
- if (req->wb_context->lockowner != prev->wb_context->lockowner)
- break;
- if (req->wb_context->state != prev->wb_context->state)
- break;
- if (req->wb_index != (prev->wb_index + 1))
- break;
-
- if (req->wb_pgbase != 0)
- break;
- }
- nfs_list_remove_request(req);
- nfs_list_add_request(req, dst);
- npages++;
- if (req->wb_pgbase + req->wb_bytes != PAGE_CACHE_SIZE)
- break;
- if (npages >= nmax)
+ struct nfs_page *req = nfs_list_entry(head->next);
+ if (!nfs_pageio_add_request(desc, req))
break;
}
- return npages;
}
#define NFS_SCAN_MAXENTRIES 16