diff options
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r-- | fs/nfs/read.c | 49 |
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 | ||
46 | struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | 46 | struct 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 | ||
66 | void nfs_readdata_free(struct nfs_read_data *p) | 68 | static 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 | /* |