aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/read.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r--fs/nfs/read.c49
1 files changed, 29 insertions, 20 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 52bf634260a1..7a9ee00e0c61 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -43,13 +43,15 @@ static mempool_t *nfs_rdata_mempool;
43 43
44#define MIN_POOL_READ (32) 44#define MIN_POOL_READ (32)
45 45
46struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) 46struct nfs_read_data *nfs_readdata_alloc(size_t len)
47{ 47{
48 unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
48 struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, SLAB_NOFS); 49 struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, SLAB_NOFS);
49 50
50 if (p) { 51 if (p) {
51 memset(p, 0, sizeof(*p)); 52 memset(p, 0, sizeof(*p));
52 INIT_LIST_HEAD(&p->pages); 53 INIT_LIST_HEAD(&p->pages);
54 p->npages = pagecount;
53 if (pagecount <= ARRAY_SIZE(p->page_array)) 55 if (pagecount <= ARRAY_SIZE(p->page_array))
54 p->pagevec = p->page_array; 56 p->pagevec = p->page_array;
55 else { 57 else {
@@ -63,7 +65,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
63 return p; 65 return p;
64} 66}
65 67
66void nfs_readdata_free(struct nfs_read_data *p) 68static void nfs_readdata_free(struct nfs_read_data *p)
67{ 69{
68 if (p && (p->pagevec != &p->page_array[0])) 70 if (p && (p->pagevec != &p->page_array[0]))
69 kfree(p->pagevec); 71 kfree(p->pagevec);
@@ -116,10 +118,17 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
116 pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; 118 pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
117 base &= ~PAGE_CACHE_MASK; 119 base &= ~PAGE_CACHE_MASK;
118 pglen = PAGE_CACHE_SIZE - base; 120 pglen = PAGE_CACHE_SIZE - base;
119 if (pglen < remainder) 121 for (;;) {
122 if (remainder <= pglen) {
123 memclear_highpage_flush(*pages, base, remainder);
124 break;
125 }
120 memclear_highpage_flush(*pages, base, pglen); 126 memclear_highpage_flush(*pages, base, pglen);
121 else 127 pages++;
122 memclear_highpage_flush(*pages, base, remainder); 128 remainder -= pglen;
129 pglen = PAGE_CACHE_SIZE;
130 base = 0;
131 }
123} 132}
124 133
125/* 134/*
@@ -133,7 +142,7 @@ static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode,
133 int result; 142 int result;
134 struct nfs_read_data *rdata; 143 struct nfs_read_data *rdata;
135 144
136 rdata = nfs_readdata_alloc(1); 145 rdata = nfs_readdata_alloc(count);
137 if (!rdata) 146 if (!rdata)
138 return -ENOMEM; 147 return -ENOMEM;
139 148
@@ -329,25 +338,25 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
329 struct nfs_page *req = nfs_list_entry(head->next); 338 struct nfs_page *req = nfs_list_entry(head->next);
330 struct page *page = req->wb_page; 339 struct page *page = req->wb_page;
331 struct nfs_read_data *data; 340 struct nfs_read_data *data;
332 unsigned int rsize = NFS_SERVER(inode)->rsize; 341 size_t rsize = NFS_SERVER(inode)->rsize, nbytes;
333 unsigned int nbytes, offset; 342 unsigned int offset;
334 int requests = 0; 343 int requests = 0;
335 LIST_HEAD(list); 344 LIST_HEAD(list);
336 345
337 nfs_list_remove_request(req); 346 nfs_list_remove_request(req);
338 347
339 nbytes = req->wb_bytes; 348 nbytes = req->wb_bytes;
340 for(;;) { 349 do {
341 data = nfs_readdata_alloc(1); 350 size_t len = min(nbytes,rsize);
351
352 data = nfs_readdata_alloc(len);
342 if (!data) 353 if (!data)
343 goto out_bad; 354 goto out_bad;
344 INIT_LIST_HEAD(&data->pages); 355 INIT_LIST_HEAD(&data->pages);
345 list_add(&data->pages, &list); 356 list_add(&data->pages, &list);
346 requests++; 357 requests++;
347 if (nbytes <= rsize) 358 nbytes -= len;
348 break; 359 } while(nbytes != 0);
349 nbytes -= rsize;
350 }
351 atomic_set(&req->wb_complete, requests); 360 atomic_set(&req->wb_complete, requests);
352 361
353 ClearPageError(page); 362 ClearPageError(page);
@@ -395,7 +404,7 @@ static int nfs_pagein_one(struct list_head *head, struct inode *inode)
395 if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) 404 if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
396 return nfs_pagein_multi(head, inode); 405 return nfs_pagein_multi(head, inode);
397 406
398 data = nfs_readdata_alloc(NFS_SERVER(inode)->rpages); 407 data = nfs_readdata_alloc(NFS_SERVER(inode)->rsize);
399 if (!data) 408 if (!data)
400 goto out_bad; 409 goto out_bad;
401 410
@@ -476,6 +485,8 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
476 unsigned int base = data->args.pgbase; 485 unsigned int base = data->args.pgbase;
477 struct page **pages; 486 struct page **pages;
478 487
488 if (data->res.eof)
489 count = data->args.count;
479 if (unlikely(count == 0)) 490 if (unlikely(count == 0))
480 return; 491 return;
481 pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; 492 pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
@@ -483,11 +494,7 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
483 count += base; 494 count += base;
484 for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) 495 for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
485 SetPageUptodate(*pages); 496 SetPageUptodate(*pages);
486 /* 497 if (count != 0)
487 * Was this an eof or a short read? If the latter, don't mark the page
488 * as uptodate yet.
489 */
490 if (count > 0 && (data->res.eof || data->args.count == data->res.count))
491 SetPageUptodate(*pages); 498 SetPageUptodate(*pages);
492} 499}
493 500
@@ -502,6 +509,8 @@ static void nfs_readpage_set_pages_error(struct nfs_read_data *data)
502 count += base; 509 count += base;
503 for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) 510 for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
504 SetPageError(*pages); 511 SetPageError(*pages);
512 if (count != 0)
513 SetPageError(*pages);
505} 514}
506 515
507/* 516/*