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.c76
1 files changed, 64 insertions, 12 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 7913961aff22..b60970cc7f1f 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -114,7 +114,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req)
114 if (!nfs_lock_request_dontget(req)) 114 if (!nfs_lock_request_dontget(req))
115 return 0; 115 return 0;
116 if (test_bit(PG_MAPPED, &req->wb_flags)) 116 if (test_bit(PG_MAPPED, &req->wb_flags))
117 radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); 117 radix_tree_tag_set(&NFS_I(req->wb_context->dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
118 return 1; 118 return 1;
119} 119}
120 120
@@ -124,7 +124,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req)
124void nfs_clear_page_tag_locked(struct nfs_page *req) 124void nfs_clear_page_tag_locked(struct nfs_page *req)
125{ 125{
126 if (test_bit(PG_MAPPED, &req->wb_flags)) { 126 if (test_bit(PG_MAPPED, &req->wb_flags)) {
127 struct inode *inode = req->wb_context->path.dentry->d_inode; 127 struct inode *inode = req->wb_context->dentry->d_inode;
128 struct nfs_inode *nfsi = NFS_I(inode); 128 struct nfs_inode *nfsi = NFS_I(inode);
129 129
130 spin_lock(&inode->i_lock); 130 spin_lock(&inode->i_lock);
@@ -204,7 +204,7 @@ nfs_wait_on_request(struct nfs_page *req)
204 TASK_UNINTERRUPTIBLE); 204 TASK_UNINTERRUPTIBLE);
205} 205}
206 206
207static bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, struct nfs_page *prev, struct nfs_page *req) 207bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, struct nfs_page *prev, struct nfs_page *req)
208{ 208{
209 /* 209 /*
210 * FIXME: ideally we should be able to coalesce all requests 210 * FIXME: ideally we should be able to coalesce all requests
@@ -218,6 +218,7 @@ static bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, struct nfs_p
218 218
219 return desc->pg_count + req->wb_bytes <= desc->pg_bsize; 219 return desc->pg_count + req->wb_bytes <= desc->pg_bsize;
220} 220}
221EXPORT_SYMBOL_GPL(nfs_generic_pg_test);
221 222
222/** 223/**
223 * nfs_pageio_init - initialise a page io descriptor 224 * nfs_pageio_init - initialise a page io descriptor
@@ -229,7 +230,7 @@ static bool nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, struct nfs_p
229 */ 230 */
230void nfs_pageio_init(struct nfs_pageio_descriptor *desc, 231void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
231 struct inode *inode, 232 struct inode *inode,
232 int (*doio)(struct nfs_pageio_descriptor *), 233 const struct nfs_pageio_ops *pg_ops,
233 size_t bsize, 234 size_t bsize,
234 int io_flags) 235 int io_flags)
235{ 236{
@@ -239,13 +240,12 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
239 desc->pg_bsize = bsize; 240 desc->pg_bsize = bsize;
240 desc->pg_base = 0; 241 desc->pg_base = 0;
241 desc->pg_moreio = 0; 242 desc->pg_moreio = 0;
243 desc->pg_recoalesce = 0;
242 desc->pg_inode = inode; 244 desc->pg_inode = inode;
243 desc->pg_doio = doio; 245 desc->pg_ops = pg_ops;
244 desc->pg_ioflags = io_flags; 246 desc->pg_ioflags = io_flags;
245 desc->pg_error = 0; 247 desc->pg_error = 0;
246 desc->pg_lseg = NULL; 248 desc->pg_lseg = NULL;
247 desc->pg_test = nfs_generic_pg_test;
248 pnfs_pageio_init(desc, inode);
249} 249}
250 250
251/** 251/**
@@ -275,7 +275,7 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
275 return false; 275 return false;
276 if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE) 276 if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
277 return false; 277 return false;
278 return pgio->pg_test(pgio, prev, req); 278 return pgio->pg_ops->pg_test(pgio, prev, req);
279} 279}
280 280
281/** 281/**
@@ -296,6 +296,8 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
296 if (!nfs_can_coalesce_requests(prev, req, desc)) 296 if (!nfs_can_coalesce_requests(prev, req, desc))
297 return 0; 297 return 0;
298 } else { 298 } else {
299 if (desc->pg_ops->pg_init)
300 desc->pg_ops->pg_init(desc, req);
299 desc->pg_base = req->wb_pgbase; 301 desc->pg_base = req->wb_pgbase;
300 } 302 }
301 nfs_list_remove_request(req); 303 nfs_list_remove_request(req);
@@ -310,7 +312,7 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
310static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) 312static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
311{ 313{
312 if (!list_empty(&desc->pg_list)) { 314 if (!list_empty(&desc->pg_list)) {
313 int error = desc->pg_doio(desc); 315 int error = desc->pg_ops->pg_doio(desc);
314 if (error < 0) 316 if (error < 0)
315 desc->pg_error = error; 317 desc->pg_error = error;
316 else 318 else
@@ -330,7 +332,7 @@ static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
330 * Returns true if the request 'req' was successfully coalesced into the 332 * Returns true if the request 'req' was successfully coalesced into the
331 * existing list of pages 'desc'. 333 * existing list of pages 'desc'.
332 */ 334 */
333int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, 335static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
334 struct nfs_page *req) 336 struct nfs_page *req)
335{ 337{
336 while (!nfs_pageio_do_add_request(desc, req)) { 338 while (!nfs_pageio_do_add_request(desc, req)) {
@@ -339,17 +341,67 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
339 if (desc->pg_error < 0) 341 if (desc->pg_error < 0)
340 return 0; 342 return 0;
341 desc->pg_moreio = 0; 343 desc->pg_moreio = 0;
344 if (desc->pg_recoalesce)
345 return 0;
342 } 346 }
343 return 1; 347 return 1;
344} 348}
345 349
350static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
351{
352 LIST_HEAD(head);
353
354 do {
355 list_splice_init(&desc->pg_list, &head);
356 desc->pg_bytes_written -= desc->pg_count;
357 desc->pg_count = 0;
358 desc->pg_base = 0;
359 desc->pg_recoalesce = 0;
360
361 while (!list_empty(&head)) {
362 struct nfs_page *req;
363
364 req = list_first_entry(&head, struct nfs_page, wb_list);
365 nfs_list_remove_request(req);
366 if (__nfs_pageio_add_request(desc, req))
367 continue;
368 if (desc->pg_error < 0)
369 return 0;
370 break;
371 }
372 } while (desc->pg_recoalesce);
373 return 1;
374}
375
376int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
377 struct nfs_page *req)
378{
379 int ret;
380
381 do {
382 ret = __nfs_pageio_add_request(desc, req);
383 if (ret)
384 break;
385 if (desc->pg_error < 0)
386 break;
387 ret = nfs_do_recoalesce(desc);
388 } while (ret);
389 return ret;
390}
391
346/** 392/**
347 * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor 393 * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor
348 * @desc: pointer to io descriptor 394 * @desc: pointer to io descriptor
349 */ 395 */
350void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) 396void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
351{ 397{
352 nfs_pageio_doio(desc); 398 for (;;) {
399 nfs_pageio_doio(desc);
400 if (!desc->pg_recoalesce)
401 break;
402 if (!nfs_do_recoalesce(desc))
403 break;
404 }
353} 405}
354 406
355/** 407/**
@@ -368,7 +420,7 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
368 if (!list_empty(&desc->pg_list)) { 420 if (!list_empty(&desc->pg_list)) {
369 struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev); 421 struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev);
370 if (index != prev->wb_index + 1) 422 if (index != prev->wb_index + 1)
371 nfs_pageio_doio(desc); 423 nfs_pageio_complete(desc);
372 } 424 }
373} 425}
374 426