diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-04-02 18:48:28 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-05-01 01:17:04 -0400 |
commit | d8a5ad75cc4d577987964e37a4c43b1c648c201e (patch) | |
tree | 91604bf17f7a81cc60a214426c7ddca89bf4faee /fs/nfs/pagelist.c | |
parent | 91e59c368c6ba5eed0369a085c42c9f270b97aa8 (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.c | 117 |
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 | */ | ||
230 | void 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 | */ | ||
249 | static 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 | */ | ||
275 | static 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 | */ |
235 | int | 313 | void nfs_pageio_add_list(struct nfs_pageio_descriptor *desc, |
236 | nfs_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 |