diff options
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r-- | fs/nfs/read.c | 62 |
1 files changed, 27 insertions, 35 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 97f0f42e136d..0effa74992df 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 *, size_t, int); |
31 | static int nfs_pagein_one(struct inode *, struct list_head *, 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 | ||
@@ -133,7 +134,10 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
133 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | 134 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); |
134 | 135 | ||
135 | nfs_list_add_request(new, &one_request); | 136 | nfs_list_add_request(new, &one_request); |
136 | nfs_pagein_one(&one_request, inode); | 137 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) |
138 | nfs_pagein_multi(inode, &one_request, len, 0); | ||
139 | else | ||
140 | nfs_pagein_one(inode, &one_request, len, 0); | ||
137 | return 0; | 141 | return 0; |
138 | } | 142 | } |
139 | 143 | ||
@@ -230,7 +234,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 | 234 | * won't see the new data until our attribute cache is updated. This is more |
231 | * or less conventional NFS client behavior. | 235 | * or less conventional NFS client behavior. |
232 | */ | 236 | */ |
233 | static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | 237 | static int nfs_pagein_multi(struct inode *inode, struct list_head *head, size_t count, int flags) |
234 | { | 238 | { |
235 | struct nfs_page *req = nfs_list_entry(head->next); | 239 | struct nfs_page *req = nfs_list_entry(head->next); |
236 | struct page *page = req->wb_page; | 240 | struct page *page = req->wb_page; |
@@ -242,7 +246,7 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | |||
242 | 246 | ||
243 | nfs_list_remove_request(req); | 247 | nfs_list_remove_request(req); |
244 | 248 | ||
245 | nbytes = req->wb_bytes; | 249 | nbytes = count; |
246 | do { | 250 | do { |
247 | size_t len = min(nbytes,rsize); | 251 | size_t len = min(nbytes,rsize); |
248 | 252 | ||
@@ -258,23 +262,19 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | |||
258 | 262 | ||
259 | ClearPageError(page); | 263 | ClearPageError(page); |
260 | offset = 0; | 264 | offset = 0; |
261 | nbytes = req->wb_bytes; | 265 | nbytes = count; |
262 | do { | 266 | do { |
263 | data = list_entry(list.next, struct nfs_read_data, pages); | 267 | data = list_entry(list.next, struct nfs_read_data, pages); |
264 | list_del_init(&data->pages); | 268 | list_del_init(&data->pages); |
265 | 269 | ||
266 | data->pagevec[0] = page; | 270 | data->pagevec[0] = page; |
267 | 271 | ||
268 | if (nbytes > rsize) { | 272 | if (nbytes < rsize) |
269 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, | 273 | rsize = nbytes; |
270 | rsize, offset); | 274 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
271 | offset += rsize; | 275 | rsize, offset); |
272 | nbytes -= rsize; | 276 | offset += rsize; |
273 | } else { | 277 | nbytes -= rsize; |
274 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, | ||
275 | nbytes, offset); | ||
276 | nbytes = 0; | ||
277 | } | ||
278 | nfs_execute_read(data); | 278 | nfs_execute_read(data); |
279 | } while (nbytes != 0); | 279 | } while (nbytes != 0); |
280 | 280 | ||
@@ -291,30 +291,24 @@ out_bad: | |||
291 | return -ENOMEM; | 291 | return -ENOMEM; |
292 | } | 292 | } |
293 | 293 | ||
294 | static int nfs_pagein_one(struct list_head *head, struct inode *inode) | 294 | static int nfs_pagein_one(struct inode *inode, struct list_head *head, size_t count, int flags) |
295 | { | 295 | { |
296 | struct nfs_page *req; | 296 | struct nfs_page *req; |
297 | struct page **pages; | 297 | struct page **pages; |
298 | struct nfs_read_data *data; | 298 | struct nfs_read_data *data; |
299 | unsigned int count; | ||
300 | |||
301 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) | ||
302 | return nfs_pagein_multi(head, inode); | ||
303 | 299 | ||
304 | data = nfs_readdata_alloc(NFS_SERVER(inode)->rsize); | 300 | data = nfs_readdata_alloc(count); |
305 | if (!data) | 301 | if (!data) |
306 | goto out_bad; | 302 | goto out_bad; |
307 | 303 | ||
308 | INIT_LIST_HEAD(&data->pages); | 304 | INIT_LIST_HEAD(&data->pages); |
309 | pages = data->pagevec; | 305 | pages = data->pagevec; |
310 | count = 0; | ||
311 | while (!list_empty(head)) { | 306 | while (!list_empty(head)) { |
312 | req = nfs_list_entry(head->next); | 307 | req = nfs_list_entry(head->next); |
313 | nfs_list_remove_request(req); | 308 | nfs_list_remove_request(req); |
314 | nfs_list_add_request(req, &data->pages); | 309 | nfs_list_add_request(req, &data->pages); |
315 | ClearPageError(req->wb_page); | 310 | ClearPageError(req->wb_page); |
316 | *pages++ = req->wb_page; | 311 | *pages++ = req->wb_page; |
317 | count += req->wb_bytes; | ||
318 | } | 312 | } |
319 | req = nfs_list_entry(data->pages.next); | 313 | req = nfs_list_entry(data->pages.next); |
320 | 314 | ||
@@ -328,22 +322,20 @@ out_bad: | |||
328 | } | 322 | } |
329 | 323 | ||
330 | static int | 324 | static int |
331 | nfs_pagein_list(struct list_head *head, unsigned int rsize) | 325 | nfs_pagein_list(struct inode *inode, struct list_head *head, unsigned int rsize) |
332 | { | 326 | { |
333 | struct nfs_pageio_descriptor desc; | 327 | struct nfs_pageio_descriptor desc; |
334 | struct nfs_page *req; | ||
335 | unsigned int pages = 0; | 328 | unsigned int pages = 0; |
336 | int error = 0; | 329 | int error = 0; |
337 | 330 | ||
338 | while (!list_empty(head)) { | 331 | if (rsize < PAGE_CACHE_SIZE) |
339 | nfs_pageio_init(&desc, rsize); | 332 | nfs_pageio_init(&desc, inode, nfs_pagein_multi, rsize, 0); |
340 | nfs_pageio_add_list(&desc, head); | 333 | else |
341 | req = nfs_list_entry(desc.pg_list.next); | 334 | nfs_pageio_init(&desc, inode, nfs_pagein_one, rsize, 0); |
342 | error = nfs_pagein_one(&desc.pg_list, req->wb_context->dentry->d_inode); | 335 | |
343 | if (error < 0) | 336 | nfs_pageio_add_list(&desc, head); |
344 | break; | 337 | nfs_pageio_complete(&desc); |
345 | pages += (desc.pg_count + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 338 | pages += (desc.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
346 | } | ||
347 | 339 | ||
348 | nfs_async_read_error(head); | 340 | nfs_async_read_error(head); |
349 | if (error >= 0) | 341 | if (error >= 0) |
@@ -597,7 +589,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
597 | filp->private_data); | 589 | filp->private_data); |
598 | ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); | 590 | ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); |
599 | if (!list_empty(&head)) { | 591 | if (!list_empty(&head)) { |
600 | int err = nfs_pagein_list(&head, server->rsize); | 592 | int err = nfs_pagein_list(inode, &head, server->rsize); |
601 | if (!ret) | 593 | if (!ret) |
602 | nfs_add_stats(inode, NFSIOS_READPAGES, err); | 594 | nfs_add_stats(inode, NFSIOS_READPAGES, err); |
603 | ret = err; | 595 | ret = err; |