aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/pagelist.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-04-02 18:48:28 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-05-01 01:17:04 -0400
commitd8a5ad75cc4d577987964e37a4c43b1c648c201e (patch)
tree91604bf17f7a81cc60a214426c7ddca89bf4faee /fs/nfs/pagelist.c
parent91e59c368c6ba5eed0369a085c42c9f270b97aa8 (diff)
NFS: Cleanup the coalescing code
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
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 ca4b1d4ff42b..7017eb0e0bc8 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -223,48 +223,101 @@ out:
223} 223}
224 224
225/** 225/**
226 * nfs_coalesce_requests - Split coalesced requests out from a list. 226 * nfs_pageio_init - initialise a page io descriptor
227 * @desc: pointer to descriptor
228 * @iosize: io block size
229 */
230void nfs_pageio_init(struct nfs_pageio_descriptor *desc, unsigned int bsize)
231{
232 INIT_LIST_HEAD(&desc->pg_list);
233 desc->pg_count = 0;
234 desc->pg_bsize = bsize;
235 desc->pg_base = 0;
236}
237
238/**
239 * nfs_can_coalesce_requests - test two requests for compatibility
240 * @prev: pointer to nfs_page
241 * @req: pointer to nfs_page
242 *
243 * The nfs_page structures 'prev' and 'req' are compared to ensure that the
244 * page data area they describe is contiguous, and that their RPC
245 * credentials, NFSv4 open state, and lockowners are the same.
246 *
247 * Return 'true' if this is the case, else return 'false'.
248 */
249static int nfs_can_coalesce_requests(struct nfs_page *prev,
250 struct nfs_page *req)
251{
252 if (req->wb_context->cred != prev->wb_context->cred)
253 return 0;
254 if (req->wb_context->lockowner != prev->wb_context->lockowner)
255 return 0;
256 if (req->wb_context->state != prev->wb_context->state)
257 return 0;
258 if (req->wb_index != (prev->wb_index + 1))
259 return 0;
260 if (req->wb_pgbase != 0)
261 return 0;
262 if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
263 return 0;
264 return 1;
265}
266
267/**
268 * nfs_pageio_add_request - Attempt to coalesce a request into a page list.
269 * @desc: destination io descriptor
270 * @req: request
271 *
272 * Returns true if the request 'req' was successfully coalesced into the
273 * existing list of pages 'desc'.
274 */
275static int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
276 struct nfs_page *req)
277{
278 size_t newlen = req->wb_bytes;
279
280 if (desc->pg_count != 0) {
281 struct nfs_page *prev;
282
283 /*
284 * FIXME: ideally we should be able to coalesce all requests
285 * that are not block boundary aligned, but currently this
286 * is problematic for the case of bsize < PAGE_CACHE_SIZE,
287 * since nfs_flush_multi and nfs_pagein_multi assume you
288 * can have only one struct nfs_page.
289 */
290 newlen += desc->pg_count;
291 if (desc->pg_base + newlen > desc->pg_bsize)
292 return 0;
293 prev = nfs_list_entry(desc->pg_list.prev);
294 if (!nfs_can_coalesce_requests(prev, req))
295 return 0;
296 } else
297 desc->pg_base = req->wb_pgbase;
298 nfs_list_remove_request(req);
299 nfs_list_add_request(req, &desc->pg_list);
300 desc->pg_count = newlen;
301 return 1;
302}
303
304/**
305 * nfs_pageio_add_list - Split coalesced requests out from a list.
306 * @desc: destination io descriptor
227 * @head: source list 307 * @head: source list
228 * @dst: destination list
229 * @nmax: maximum number of requests to coalesce
230 * 308 *
231 * Moves a maximum of 'nmax' elements from one list to another. 309 * Moves a maximum of 'nmax' elements from one list to another.
232 * The elements are checked to ensure that they form a contiguous set 310 * The elements are checked to ensure that they form a contiguous set
233 * of pages, and that the RPC credentials are the same. 311 * of pages, and that the RPC credentials are the same.
234 */ 312 */
235int 313void nfs_pageio_add_list(struct nfs_pageio_descriptor *desc,
236nfs_coalesce_requests(struct list_head *head, struct list_head *dst, 314 struct list_head *head)
237 unsigned int nmax)
238{ 315{
239 struct nfs_page *req = NULL;
240 unsigned int npages = 0;
241
242 while (!list_empty(head)) { 316 while (!list_empty(head)) {
243 struct nfs_page *prev = req; 317 struct nfs_page *req = nfs_list_entry(head->next);
244 318 if (!nfs_pageio_add_request(desc, req))
245 req = nfs_list_entry(head->next);
246 if (prev) {
247 if (req->wb_context->cred != prev->wb_context->cred)
248 break;
249 if (req->wb_context->lockowner != prev->wb_context->lockowner)
250 break;
251 if (req->wb_context->state != prev->wb_context->state)
252 break;
253 if (req->wb_index != (prev->wb_index + 1))
254 break;
255
256 if (req->wb_pgbase != 0)
257 break;
258 }
259 nfs_list_remove_request(req);
260 nfs_list_add_request(req, dst);
261 npages++;
262 if (req->wb_pgbase + req->wb_bytes != PAGE_CACHE_SIZE)
263 break;
264 if (npages >= nmax)
265 break; 319 break;
266 } 320 }
267 return npages;
268} 321}
269 322
270#define NFS_SCAN_MAXENTRIES 16 323#define NFS_SCAN_MAXENTRIES 16