diff options
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r-- | fs/nfs/read.c | 92 |
1 files changed, 34 insertions, 58 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 6ab4d5a9edf2..9a55807b2a70 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -27,7 +27,8 @@ | |||
27 | 27 | ||
28 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 28 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
29 | 29 | ||
30 | static int nfs_pagein_one(struct list_head *, struct inode *); | 30 | static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int); |
31 | static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int); | ||
31 | static const struct rpc_call_ops nfs_read_partial_ops; | 32 | static const struct rpc_call_ops nfs_read_partial_ops; |
32 | static const struct rpc_call_ops nfs_read_full_ops; | 33 | static const struct rpc_call_ops nfs_read_full_ops; |
33 | 34 | ||
@@ -36,9 +37,8 @@ static mempool_t *nfs_rdata_mempool; | |||
36 | 37 | ||
37 | #define MIN_POOL_READ (32) | 38 | #define MIN_POOL_READ (32) |
38 | 39 | ||
39 | struct nfs_read_data *nfs_readdata_alloc(size_t len) | 40 | struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) |
40 | { | 41 | { |
41 | unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
42 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS); | 42 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS); |
43 | 43 | ||
44 | if (p) { | 44 | if (p) { |
@@ -133,7 +133,10 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
133 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 133 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
134 | 134 | ||
135 | nfs_list_add_request(new, &one_request); | 135 | nfs_list_add_request(new, &one_request); |
136 | nfs_pagein_one(&one_request, inode); | 136 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) |
137 | nfs_pagein_multi(inode, &one_request, 1, len, 0); | ||
138 | else | ||
139 | nfs_pagein_one(inode, &one_request, 1, len, 0); | ||
137 | return 0; | 140 | return 0; |
138 | } | 141 | } |
139 | 142 | ||
@@ -230,7 +233,7 @@ static void nfs_execute_read(struct nfs_read_data *data) | |||
230 | * won't see the new data until our attribute cache is updated. This is more | 233 | * won't see the new data until our attribute cache is updated. This is more |
231 | * or less conventional NFS client behavior. | 234 | * or less conventional NFS client behavior. |
232 | */ | 235 | */ |
233 | static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | 236 | static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) |
234 | { | 237 | { |
235 | struct nfs_page *req = nfs_list_entry(head->next); | 238 | struct nfs_page *req = nfs_list_entry(head->next); |
236 | struct page *page = req->wb_page; | 239 | struct page *page = req->wb_page; |
@@ -242,11 +245,11 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | |||
242 | 245 | ||
243 | nfs_list_remove_request(req); | 246 | nfs_list_remove_request(req); |
244 | 247 | ||
245 | nbytes = req->wb_bytes; | 248 | nbytes = count; |
246 | do { | 249 | do { |
247 | size_t len = min(nbytes,rsize); | 250 | size_t len = min(nbytes,rsize); |
248 | 251 | ||
249 | data = nfs_readdata_alloc(len); | 252 | data = nfs_readdata_alloc(1); |
250 | if (!data) | 253 | if (!data) |
251 | goto out_bad; | 254 | goto out_bad; |
252 | INIT_LIST_HEAD(&data->pages); | 255 | INIT_LIST_HEAD(&data->pages); |
@@ -258,23 +261,19 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | |||
258 | 261 | ||
259 | ClearPageError(page); | 262 | ClearPageError(page); |
260 | offset = 0; | 263 | offset = 0; |
261 | nbytes = req->wb_bytes; | 264 | nbytes = count; |
262 | do { | 265 | do { |
263 | data = list_entry(list.next, struct nfs_read_data, pages); | 266 | data = list_entry(list.next, struct nfs_read_data, pages); |
264 | list_del_init(&data->pages); | 267 | list_del_init(&data->pages); |
265 | 268 | ||
266 | data->pagevec[0] = page; | 269 | data->pagevec[0] = page; |
267 | 270 | ||
268 | if (nbytes > rsize) { | 271 | if (nbytes < rsize) |
269 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, | 272 | rsize = nbytes; |
270 | rsize, offset); | 273 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
271 | offset += rsize; | 274 | rsize, offset); |
272 | nbytes -= rsize; | 275 | offset += rsize; |
273 | } else { | 276 | nbytes -= rsize; |
274 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, | ||
275 | nbytes, offset); | ||
276 | nbytes = 0; | ||
277 | } | ||
278 | nfs_execute_read(data); | 277 | nfs_execute_read(data); |
279 | } while (nbytes != 0); | 278 | } while (nbytes != 0); |
280 | 279 | ||
@@ -291,30 +290,24 @@ out_bad: | |||
291 | return -ENOMEM; | 290 | return -ENOMEM; |
292 | } | 291 | } |
293 | 292 | ||
294 | static int nfs_pagein_one(struct list_head *head, struct inode *inode) | 293 | static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) |
295 | { | 294 | { |
296 | struct nfs_page *req; | 295 | struct nfs_page *req; |
297 | struct page **pages; | 296 | struct page **pages; |
298 | struct nfs_read_data *data; | 297 | struct nfs_read_data *data; |
299 | unsigned int count; | ||
300 | 298 | ||
301 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) | 299 | data = nfs_readdata_alloc(npages); |
302 | return nfs_pagein_multi(head, inode); | ||
303 | |||
304 | data = nfs_readdata_alloc(NFS_SERVER(inode)->rsize); | ||
305 | if (!data) | 300 | if (!data) |
306 | goto out_bad; | 301 | goto out_bad; |
307 | 302 | ||
308 | INIT_LIST_HEAD(&data->pages); | 303 | INIT_LIST_HEAD(&data->pages); |
309 | pages = data->pagevec; | 304 | pages = data->pagevec; |
310 | count = 0; | ||
311 | while (!list_empty(head)) { | 305 | while (!list_empty(head)) { |
312 | req = nfs_list_entry(head->next); | 306 | req = nfs_list_entry(head->next); |
313 | nfs_list_remove_request(req); | 307 | nfs_list_remove_request(req); |
314 | nfs_list_add_request(req, &data->pages); | 308 | nfs_list_add_request(req, &data->pages); |
315 | ClearPageError(req->wb_page); | 309 | ClearPageError(req->wb_page); |
316 | *pages++ = req->wb_page; | 310 | *pages++ = req->wb_page; |
317 | count += req->wb_bytes; | ||
318 | } | 311 | } |
319 | req = nfs_list_entry(data->pages.next); | 312 | req = nfs_list_entry(data->pages.next); |
320 | 313 | ||
@@ -327,28 +320,6 @@ out_bad: | |||
327 | return -ENOMEM; | 320 | return -ENOMEM; |
328 | } | 321 | } |
329 | 322 | ||
330 | static int | ||
331 | nfs_pagein_list(struct list_head *head, int rpages) | ||
332 | { | ||
333 | LIST_HEAD(one_request); | ||
334 | struct nfs_page *req; | ||
335 | int error = 0; | ||
336 | unsigned int pages = 0; | ||
337 | |||
338 | while (!list_empty(head)) { | ||
339 | pages += nfs_coalesce_requests(head, &one_request, rpages); | ||
340 | req = nfs_list_entry(one_request.next); | ||
341 | error = nfs_pagein_one(&one_request, req->wb_context->dentry->d_inode); | ||
342 | if (error < 0) | ||
343 | break; | ||
344 | } | ||
345 | if (error >= 0) | ||
346 | return pages; | ||
347 | |||
348 | nfs_async_read_error(head); | ||
349 | return error; | ||
350 | } | ||
351 | |||
352 | /* | 323 | /* |
353 | * This is the callback from RPC telling us whether a reply was | 324 | * This is the callback from RPC telling us whether a reply was |
354 | * received or some error occurred (timeout or socket shutdown). | 325 | * received or some error occurred (timeout or socket shutdown). |
@@ -538,7 +509,7 @@ out_error: | |||
538 | } | 509 | } |
539 | 510 | ||
540 | struct nfs_readdesc { | 511 | struct nfs_readdesc { |
541 | struct list_head *head; | 512 | struct nfs_pageio_descriptor *pgio; |
542 | struct nfs_open_context *ctx; | 513 | struct nfs_open_context *ctx; |
543 | }; | 514 | }; |
544 | 515 | ||
@@ -562,19 +533,21 @@ readpage_async_filler(void *data, struct page *page) | |||
562 | } | 533 | } |
563 | if (len < PAGE_CACHE_SIZE) | 534 | if (len < PAGE_CACHE_SIZE) |
564 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 535 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
565 | nfs_list_add_request(new, desc->head); | 536 | nfs_pageio_add_request(desc->pgio, new); |
566 | return 0; | 537 | return 0; |
567 | } | 538 | } |
568 | 539 | ||
569 | int nfs_readpages(struct file *filp, struct address_space *mapping, | 540 | int nfs_readpages(struct file *filp, struct address_space *mapping, |
570 | struct list_head *pages, unsigned nr_pages) | 541 | struct list_head *pages, unsigned nr_pages) |
571 | { | 542 | { |
572 | LIST_HEAD(head); | 543 | struct nfs_pageio_descriptor pgio; |
573 | struct nfs_readdesc desc = { | 544 | struct nfs_readdesc desc = { |
574 | .head = &head, | 545 | .pgio = &pgio, |
575 | }; | 546 | }; |
576 | struct inode *inode = mapping->host; | 547 | struct inode *inode = mapping->host; |
577 | struct nfs_server *server = NFS_SERVER(inode); | 548 | struct nfs_server *server = NFS_SERVER(inode); |
549 | size_t rsize = server->rsize; | ||
550 | unsigned long npages; | ||
578 | int ret = -ESTALE; | 551 | int ret = -ESTALE; |
579 | 552 | ||
580 | dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", | 553 | dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", |
@@ -593,13 +566,16 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
593 | } else | 566 | } else |
594 | desc.ctx = get_nfs_open_context((struct nfs_open_context *) | 567 | desc.ctx = get_nfs_open_context((struct nfs_open_context *) |
595 | filp->private_data); | 568 | filp->private_data); |
569 | if (rsize < PAGE_CACHE_SIZE) | ||
570 | nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); | ||
571 | else | ||
572 | nfs_pageio_init(&pgio, inode, nfs_pagein_one, rsize, 0); | ||
573 | |||
596 | ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); | 574 | ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); |
597 | if (!list_empty(&head)) { | 575 | |
598 | int err = nfs_pagein_list(&head, server->rpages); | 576 | nfs_pageio_complete(&pgio); |
599 | if (!ret) | 577 | npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
600 | nfs_add_stats(inode, NFSIOS_READPAGES, err); | 578 | nfs_add_stats(inode, NFSIOS_READPAGES, npages); |
601 | ret = err; | ||
602 | } | ||
603 | put_nfs_open_context(desc.ctx); | 579 | put_nfs_open_context(desc.ctx); |
604 | out: | 580 | out: |
605 | return ret; | 581 | return ret; |