|
@@ -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
|