diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/nfs/read.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r-- | fs/nfs/read.c | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c new file mode 100644 index 000000000000..a0042fb58634 --- /dev/null +++ b/fs/nfs/read.c | |||
@@ -0,0 +1,618 @@ | |||
1 | /* | ||
2 | * linux/fs/nfs/read.c | ||
3 | * | ||
4 | * Block I/O for NFS | ||
5 | * | ||
6 | * Partial copy of Linus' read cache modifications to fs/nfs/file.c | ||
7 | * modified for async RPC by okir@monad.swb.de | ||
8 | * | ||
9 | * We do an ugly hack here in order to return proper error codes to the | ||
10 | * user program when a read request failed: since generic_file_read | ||
11 | * only checks the return value of inode->i_op->readpage() which is always 0 | ||
12 | * for async RPC, we set the error bit of the page to 1 when an error occurs, | ||
13 | * and make nfs_readpage transmit requests synchronously when encountering this. | ||
14 | * This is only a small problem, though, since we now retry all operations | ||
15 | * within the RPC code when root squashing is suspected. | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/time.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/fcntl.h> | ||
23 | #include <linux/stat.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/pagemap.h> | ||
27 | #include <linux/sunrpc/clnt.h> | ||
28 | #include <linux/nfs_fs.h> | ||
29 | #include <linux/nfs_page.h> | ||
30 | #include <linux/smp_lock.h> | ||
31 | |||
32 | #include <asm/system.h> | ||
33 | |||
34 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | ||
35 | |||
36 | static int nfs_pagein_one(struct list_head *, struct inode *); | ||
37 | static void nfs_readpage_result_partial(struct nfs_read_data *, int); | ||
38 | static void nfs_readpage_result_full(struct nfs_read_data *, int); | ||
39 | |||
40 | static kmem_cache_t *nfs_rdata_cachep; | ||
41 | mempool_t *nfs_rdata_mempool; | ||
42 | |||
43 | #define MIN_POOL_READ (32) | ||
44 | |||
45 | void nfs_readdata_release(struct rpc_task *task) | ||
46 | { | ||
47 | struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; | ||
48 | nfs_readdata_free(data); | ||
49 | } | ||
50 | |||
51 | static | ||
52 | unsigned int nfs_page_length(struct inode *inode, struct page *page) | ||
53 | { | ||
54 | loff_t i_size = i_size_read(inode); | ||
55 | unsigned long idx; | ||
56 | |||
57 | if (i_size <= 0) | ||
58 | return 0; | ||
59 | idx = (i_size - 1) >> PAGE_CACHE_SHIFT; | ||
60 | if (page->index > idx) | ||
61 | return 0; | ||
62 | if (page->index != idx) | ||
63 | return PAGE_CACHE_SIZE; | ||
64 | return 1 + ((i_size - 1) & (PAGE_CACHE_SIZE - 1)); | ||
65 | } | ||
66 | |||
67 | static | ||
68 | int nfs_return_empty_page(struct page *page) | ||
69 | { | ||
70 | memclear_highpage_flush(page, 0, PAGE_CACHE_SIZE); | ||
71 | SetPageUptodate(page); | ||
72 | unlock_page(page); | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Read a page synchronously. | ||
78 | */ | ||
79 | static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode, | ||
80 | struct page *page) | ||
81 | { | ||
82 | unsigned int rsize = NFS_SERVER(inode)->rsize; | ||
83 | unsigned int count = PAGE_CACHE_SIZE; | ||
84 | int result; | ||
85 | struct nfs_read_data *rdata; | ||
86 | |||
87 | rdata = nfs_readdata_alloc(); | ||
88 | if (!rdata) | ||
89 | return -ENOMEM; | ||
90 | |||
91 | memset(rdata, 0, sizeof(*rdata)); | ||
92 | rdata->flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0); | ||
93 | rdata->cred = ctx->cred; | ||
94 | rdata->inode = inode; | ||
95 | INIT_LIST_HEAD(&rdata->pages); | ||
96 | rdata->args.fh = NFS_FH(inode); | ||
97 | rdata->args.context = ctx; | ||
98 | rdata->args.pages = &page; | ||
99 | rdata->args.pgbase = 0UL; | ||
100 | rdata->args.count = rsize; | ||
101 | rdata->res.fattr = &rdata->fattr; | ||
102 | |||
103 | dprintk("NFS: nfs_readpage_sync(%p)\n", page); | ||
104 | |||
105 | /* | ||
106 | * This works now because the socket layer never tries to DMA | ||
107 | * into this buffer directly. | ||
108 | */ | ||
109 | do { | ||
110 | if (count < rsize) | ||
111 | rdata->args.count = count; | ||
112 | rdata->res.count = rdata->args.count; | ||
113 | rdata->args.offset = page_offset(page) + rdata->args.pgbase; | ||
114 | |||
115 | dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n", | ||
116 | NFS_SERVER(inode)->hostname, | ||
117 | inode->i_sb->s_id, | ||
118 | (long long)NFS_FILEID(inode), | ||
119 | (unsigned long long)rdata->args.pgbase, | ||
120 | rdata->args.count); | ||
121 | |||
122 | lock_kernel(); | ||
123 | result = NFS_PROTO(inode)->read(rdata); | ||
124 | unlock_kernel(); | ||
125 | |||
126 | /* | ||
127 | * Even if we had a partial success we can't mark the page | ||
128 | * cache valid. | ||
129 | */ | ||
130 | if (result < 0) { | ||
131 | if (result == -EISDIR) | ||
132 | result = -EINVAL; | ||
133 | goto io_error; | ||
134 | } | ||
135 | count -= result; | ||
136 | rdata->args.pgbase += result; | ||
137 | /* Note: result == 0 should only happen if we're caching | ||
138 | * a write that extends the file and punches a hole. | ||
139 | */ | ||
140 | if (rdata->res.eof != 0 || result == 0) | ||
141 | break; | ||
142 | } while (count); | ||
143 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; | ||
144 | |||
145 | if (count) | ||
146 | memclear_highpage_flush(page, rdata->args.pgbase, count); | ||
147 | SetPageUptodate(page); | ||
148 | if (PageError(page)) | ||
149 | ClearPageError(page); | ||
150 | result = 0; | ||
151 | |||
152 | io_error: | ||
153 | unlock_page(page); | ||
154 | nfs_readdata_free(rdata); | ||
155 | return result; | ||
156 | } | ||
157 | |||
158 | static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | ||
159 | struct page *page) | ||
160 | { | ||
161 | LIST_HEAD(one_request); | ||
162 | struct nfs_page *new; | ||
163 | unsigned int len; | ||
164 | |||
165 | len = nfs_page_length(inode, page); | ||
166 | if (len == 0) | ||
167 | return nfs_return_empty_page(page); | ||
168 | new = nfs_create_request(ctx, inode, page, 0, len); | ||
169 | if (IS_ERR(new)) { | ||
170 | unlock_page(page); | ||
171 | return PTR_ERR(new); | ||
172 | } | ||
173 | if (len < PAGE_CACHE_SIZE) | ||
174 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | ||
175 | |||
176 | nfs_lock_request(new); | ||
177 | nfs_list_add_request(new, &one_request); | ||
178 | nfs_pagein_one(&one_request, inode); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static void nfs_readpage_release(struct nfs_page *req) | ||
183 | { | ||
184 | unlock_page(req->wb_page); | ||
185 | |||
186 | nfs_clear_request(req); | ||
187 | nfs_release_request(req); | ||
188 | nfs_unlock_request(req); | ||
189 | |||
190 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", | ||
191 | req->wb_context->dentry->d_inode->i_sb->s_id, | ||
192 | (long long)NFS_FILEID(req->wb_context->dentry->d_inode), | ||
193 | req->wb_bytes, | ||
194 | (long long)req_offset(req)); | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Set up the NFS read request struct | ||
199 | */ | ||
200 | static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | ||
201 | unsigned int count, unsigned int offset) | ||
202 | { | ||
203 | struct inode *inode; | ||
204 | |||
205 | data->req = req; | ||
206 | data->inode = inode = req->wb_context->dentry->d_inode; | ||
207 | data->cred = req->wb_context->cred; | ||
208 | |||
209 | data->args.fh = NFS_FH(inode); | ||
210 | data->args.offset = req_offset(req) + offset; | ||
211 | data->args.pgbase = req->wb_pgbase + offset; | ||
212 | data->args.pages = data->pagevec; | ||
213 | data->args.count = count; | ||
214 | data->args.context = req->wb_context; | ||
215 | |||
216 | data->res.fattr = &data->fattr; | ||
217 | data->res.count = count; | ||
218 | data->res.eof = 0; | ||
219 | |||
220 | NFS_PROTO(inode)->read_setup(data); | ||
221 | |||
222 | data->task.tk_cookie = (unsigned long)inode; | ||
223 | data->task.tk_calldata = data; | ||
224 | /* Release requests */ | ||
225 | data->task.tk_release = nfs_readdata_release; | ||
226 | |||
227 | dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", | ||
228 | data->task.tk_pid, | ||
229 | inode->i_sb->s_id, | ||
230 | (long long)NFS_FILEID(inode), | ||
231 | count, | ||
232 | (unsigned long long)data->args.offset); | ||
233 | } | ||
234 | |||
235 | static void | ||
236 | nfs_async_read_error(struct list_head *head) | ||
237 | { | ||
238 | struct nfs_page *req; | ||
239 | |||
240 | while (!list_empty(head)) { | ||
241 | req = nfs_list_entry(head->next); | ||
242 | nfs_list_remove_request(req); | ||
243 | SetPageError(req->wb_page); | ||
244 | nfs_readpage_release(req); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | /* | ||
249 | * Start an async read operation | ||
250 | */ | ||
251 | static void nfs_execute_read(struct nfs_read_data *data) | ||
252 | { | ||
253 | struct rpc_clnt *clnt = NFS_CLIENT(data->inode); | ||
254 | sigset_t oldset; | ||
255 | |||
256 | rpc_clnt_sigmask(clnt, &oldset); | ||
257 | lock_kernel(); | ||
258 | rpc_execute(&data->task); | ||
259 | unlock_kernel(); | ||
260 | rpc_clnt_sigunmask(clnt, &oldset); | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Generate multiple requests to fill a single page. | ||
265 | * | ||
266 | * We optimize to reduce the number of read operations on the wire. If we | ||
267 | * detect that we're reading a page, or an area of a page, that is past the | ||
268 | * end of file, we do not generate NFS read operations but just clear the | ||
269 | * parts of the page that would have come back zero from the server anyway. | ||
270 | * | ||
271 | * We rely on the cached value of i_size to make this determination; another | ||
272 | * client can fill pages on the server past our cached end-of-file, but we | ||
273 | * won't see the new data until our attribute cache is updated. This is more | ||
274 | * or less conventional NFS client behavior. | ||
275 | */ | ||
276 | static int nfs_pagein_multi(struct list_head *head, struct inode *inode) | ||
277 | { | ||
278 | struct nfs_page *req = nfs_list_entry(head->next); | ||
279 | struct page *page = req->wb_page; | ||
280 | struct nfs_read_data *data; | ||
281 | unsigned int rsize = NFS_SERVER(inode)->rsize; | ||
282 | unsigned int nbytes, offset; | ||
283 | int requests = 0; | ||
284 | LIST_HEAD(list); | ||
285 | |||
286 | nfs_list_remove_request(req); | ||
287 | |||
288 | nbytes = req->wb_bytes; | ||
289 | for(;;) { | ||
290 | data = nfs_readdata_alloc(); | ||
291 | if (!data) | ||
292 | goto out_bad; | ||
293 | INIT_LIST_HEAD(&data->pages); | ||
294 | list_add(&data->pages, &list); | ||
295 | requests++; | ||
296 | if (nbytes <= rsize) | ||
297 | break; | ||
298 | nbytes -= rsize; | ||
299 | } | ||
300 | atomic_set(&req->wb_complete, requests); | ||
301 | |||
302 | ClearPageError(page); | ||
303 | offset = 0; | ||
304 | nbytes = req->wb_bytes; | ||
305 | do { | ||
306 | data = list_entry(list.next, struct nfs_read_data, pages); | ||
307 | list_del_init(&data->pages); | ||
308 | |||
309 | data->pagevec[0] = page; | ||
310 | data->complete = nfs_readpage_result_partial; | ||
311 | |||
312 | if (nbytes > rsize) { | ||
313 | nfs_read_rpcsetup(req, data, rsize, offset); | ||
314 | offset += rsize; | ||
315 | nbytes -= rsize; | ||
316 | } else { | ||
317 | nfs_read_rpcsetup(req, data, nbytes, offset); | ||
318 | nbytes = 0; | ||
319 | } | ||
320 | nfs_execute_read(data); | ||
321 | } while (nbytes != 0); | ||
322 | |||
323 | return 0; | ||
324 | |||
325 | out_bad: | ||
326 | while (!list_empty(&list)) { | ||
327 | data = list_entry(list.next, struct nfs_read_data, pages); | ||
328 | list_del(&data->pages); | ||
329 | nfs_readdata_free(data); | ||
330 | } | ||
331 | SetPageError(page); | ||
332 | nfs_readpage_release(req); | ||
333 | return -ENOMEM; | ||
334 | } | ||
335 | |||
336 | static int nfs_pagein_one(struct list_head *head, struct inode *inode) | ||
337 | { | ||
338 | struct nfs_page *req; | ||
339 | struct page **pages; | ||
340 | struct nfs_read_data *data; | ||
341 | unsigned int count; | ||
342 | |||
343 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) | ||
344 | return nfs_pagein_multi(head, inode); | ||
345 | |||
346 | data = nfs_readdata_alloc(); | ||
347 | if (!data) | ||
348 | goto out_bad; | ||
349 | |||
350 | INIT_LIST_HEAD(&data->pages); | ||
351 | pages = data->pagevec; | ||
352 | count = 0; | ||
353 | while (!list_empty(head)) { | ||
354 | req = nfs_list_entry(head->next); | ||
355 | nfs_list_remove_request(req); | ||
356 | nfs_list_add_request(req, &data->pages); | ||
357 | ClearPageError(req->wb_page); | ||
358 | *pages++ = req->wb_page; | ||
359 | count += req->wb_bytes; | ||
360 | } | ||
361 | req = nfs_list_entry(data->pages.next); | ||
362 | |||
363 | data->complete = nfs_readpage_result_full; | ||
364 | nfs_read_rpcsetup(req, data, count, 0); | ||
365 | |||
366 | nfs_execute_read(data); | ||
367 | return 0; | ||
368 | out_bad: | ||
369 | nfs_async_read_error(head); | ||
370 | return -ENOMEM; | ||
371 | } | ||
372 | |||
373 | static int | ||
374 | nfs_pagein_list(struct list_head *head, int rpages) | ||
375 | { | ||
376 | LIST_HEAD(one_request); | ||
377 | struct nfs_page *req; | ||
378 | int error = 0; | ||
379 | unsigned int pages = 0; | ||
380 | |||
381 | while (!list_empty(head)) { | ||
382 | pages += nfs_coalesce_requests(head, &one_request, rpages); | ||
383 | req = nfs_list_entry(one_request.next); | ||
384 | error = nfs_pagein_one(&one_request, req->wb_context->dentry->d_inode); | ||
385 | if (error < 0) | ||
386 | break; | ||
387 | } | ||
388 | if (error >= 0) | ||
389 | return pages; | ||
390 | |||
391 | nfs_async_read_error(head); | ||
392 | return error; | ||
393 | } | ||
394 | |||
395 | /* | ||
396 | * Handle a read reply that fills part of a page. | ||
397 | */ | ||
398 | static void nfs_readpage_result_partial(struct nfs_read_data *data, int status) | ||
399 | { | ||
400 | struct nfs_page *req = data->req; | ||
401 | struct page *page = req->wb_page; | ||
402 | |||
403 | if (status >= 0) { | ||
404 | unsigned int request = data->args.count; | ||
405 | unsigned int result = data->res.count; | ||
406 | |||
407 | if (result < request) { | ||
408 | memclear_highpage_flush(page, | ||
409 | data->args.pgbase + result, | ||
410 | request - result); | ||
411 | } | ||
412 | } else | ||
413 | SetPageError(page); | ||
414 | |||
415 | if (atomic_dec_and_test(&req->wb_complete)) { | ||
416 | if (!PageError(page)) | ||
417 | SetPageUptodate(page); | ||
418 | nfs_readpage_release(req); | ||
419 | } | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * This is the callback from RPC telling us whether a reply was | ||
424 | * received or some error occurred (timeout or socket shutdown). | ||
425 | */ | ||
426 | static void nfs_readpage_result_full(struct nfs_read_data *data, int status) | ||
427 | { | ||
428 | unsigned int count = data->res.count; | ||
429 | |||
430 | while (!list_empty(&data->pages)) { | ||
431 | struct nfs_page *req = nfs_list_entry(data->pages.next); | ||
432 | struct page *page = req->wb_page; | ||
433 | nfs_list_remove_request(req); | ||
434 | |||
435 | if (status >= 0) { | ||
436 | if (count < PAGE_CACHE_SIZE) { | ||
437 | if (count < req->wb_bytes) | ||
438 | memclear_highpage_flush(page, | ||
439 | req->wb_pgbase + count, | ||
440 | req->wb_bytes - count); | ||
441 | count = 0; | ||
442 | } else | ||
443 | count -= PAGE_CACHE_SIZE; | ||
444 | SetPageUptodate(page); | ||
445 | } else | ||
446 | SetPageError(page); | ||
447 | nfs_readpage_release(req); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | /* | ||
452 | * This is the callback from RPC telling us whether a reply was | ||
453 | * received or some error occurred (timeout or socket shutdown). | ||
454 | */ | ||
455 | void nfs_readpage_result(struct rpc_task *task) | ||
456 | { | ||
457 | struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; | ||
458 | struct nfs_readargs *argp = &data->args; | ||
459 | struct nfs_readres *resp = &data->res; | ||
460 | int status = task->tk_status; | ||
461 | |||
462 | dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", | ||
463 | task->tk_pid, status); | ||
464 | |||
465 | /* Is this a short read? */ | ||
466 | if (task->tk_status >= 0 && resp->count < argp->count && !resp->eof) { | ||
467 | /* Has the server at least made some progress? */ | ||
468 | if (resp->count != 0) { | ||
469 | /* Yes, so retry the read at the end of the data */ | ||
470 | argp->offset += resp->count; | ||
471 | argp->pgbase += resp->count; | ||
472 | argp->count -= resp->count; | ||
473 | rpc_restart_call(task); | ||
474 | return; | ||
475 | } | ||
476 | task->tk_status = -EIO; | ||
477 | } | ||
478 | NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME; | ||
479 | data->complete(data, status); | ||
480 | } | ||
481 | |||
482 | /* | ||
483 | * Read a page over NFS. | ||
484 | * We read the page synchronously in the following case: | ||
485 | * - The error flag is set for this page. This happens only when a | ||
486 | * previous async read operation failed. | ||
487 | */ | ||
488 | int nfs_readpage(struct file *file, struct page *page) | ||
489 | { | ||
490 | struct nfs_open_context *ctx; | ||
491 | struct inode *inode = page->mapping->host; | ||
492 | int error; | ||
493 | |||
494 | dprintk("NFS: nfs_readpage (%p %ld@%lu)\n", | ||
495 | page, PAGE_CACHE_SIZE, page->index); | ||
496 | /* | ||
497 | * Try to flush any pending writes to the file.. | ||
498 | * | ||
499 | * NOTE! Because we own the page lock, there cannot | ||
500 | * be any new pending writes generated at this point | ||
501 | * for this page (other pages can be written to). | ||
502 | */ | ||
503 | error = nfs_wb_page(inode, page); | ||
504 | if (error) | ||
505 | goto out_error; | ||
506 | |||
507 | if (file == NULL) { | ||
508 | ctx = nfs_find_open_context(inode, FMODE_READ); | ||
509 | if (ctx == NULL) | ||
510 | return -EBADF; | ||
511 | } else | ||
512 | ctx = get_nfs_open_context((struct nfs_open_context *) | ||
513 | file->private_data); | ||
514 | if (!IS_SYNC(inode)) { | ||
515 | error = nfs_readpage_async(ctx, inode, page); | ||
516 | goto out; | ||
517 | } | ||
518 | |||
519 | error = nfs_readpage_sync(ctx, inode, page); | ||
520 | if (error < 0 && IS_SWAPFILE(inode)) | ||
521 | printk("Aiee.. nfs swap-in of page failed!\n"); | ||
522 | out: | ||
523 | put_nfs_open_context(ctx); | ||
524 | return error; | ||
525 | |||
526 | out_error: | ||
527 | unlock_page(page); | ||
528 | return error; | ||
529 | } | ||
530 | |||
531 | struct nfs_readdesc { | ||
532 | struct list_head *head; | ||
533 | struct nfs_open_context *ctx; | ||
534 | }; | ||
535 | |||
536 | static int | ||
537 | readpage_async_filler(void *data, struct page *page) | ||
538 | { | ||
539 | struct nfs_readdesc *desc = (struct nfs_readdesc *)data; | ||
540 | struct inode *inode = page->mapping->host; | ||
541 | struct nfs_page *new; | ||
542 | unsigned int len; | ||
543 | |||
544 | nfs_wb_page(inode, page); | ||
545 | len = nfs_page_length(inode, page); | ||
546 | if (len == 0) | ||
547 | return nfs_return_empty_page(page); | ||
548 | new = nfs_create_request(desc->ctx, inode, page, 0, len); | ||
549 | if (IS_ERR(new)) { | ||
550 | SetPageError(page); | ||
551 | unlock_page(page); | ||
552 | return PTR_ERR(new); | ||
553 | } | ||
554 | if (len < PAGE_CACHE_SIZE) | ||
555 | memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); | ||
556 | nfs_lock_request(new); | ||
557 | nfs_list_add_request(new, desc->head); | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | int nfs_readpages(struct file *filp, struct address_space *mapping, | ||
562 | struct list_head *pages, unsigned nr_pages) | ||
563 | { | ||
564 | LIST_HEAD(head); | ||
565 | struct nfs_readdesc desc = { | ||
566 | .head = &head, | ||
567 | }; | ||
568 | struct inode *inode = mapping->host; | ||
569 | struct nfs_server *server = NFS_SERVER(inode); | ||
570 | int ret; | ||
571 | |||
572 | dprintk("NFS: nfs_readpages (%s/%Ld %d)\n", | ||
573 | inode->i_sb->s_id, | ||
574 | (long long)NFS_FILEID(inode), | ||
575 | nr_pages); | ||
576 | |||
577 | if (filp == NULL) { | ||
578 | desc.ctx = nfs_find_open_context(inode, FMODE_READ); | ||
579 | if (desc.ctx == NULL) | ||
580 | return -EBADF; | ||
581 | } else | ||
582 | desc.ctx = get_nfs_open_context((struct nfs_open_context *) | ||
583 | filp->private_data); | ||
584 | ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); | ||
585 | if (!list_empty(&head)) { | ||
586 | int err = nfs_pagein_list(&head, server->rpages); | ||
587 | if (!ret) | ||
588 | ret = err; | ||
589 | } | ||
590 | put_nfs_open_context(desc.ctx); | ||
591 | return ret; | ||
592 | } | ||
593 | |||
594 | int nfs_init_readpagecache(void) | ||
595 | { | ||
596 | nfs_rdata_cachep = kmem_cache_create("nfs_read_data", | ||
597 | sizeof(struct nfs_read_data), | ||
598 | 0, SLAB_HWCACHE_ALIGN, | ||
599 | NULL, NULL); | ||
600 | if (nfs_rdata_cachep == NULL) | ||
601 | return -ENOMEM; | ||
602 | |||
603 | nfs_rdata_mempool = mempool_create(MIN_POOL_READ, | ||
604 | mempool_alloc_slab, | ||
605 | mempool_free_slab, | ||
606 | nfs_rdata_cachep); | ||
607 | if (nfs_rdata_mempool == NULL) | ||
608 | return -ENOMEM; | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | void nfs_destroy_readpagecache(void) | ||
614 | { | ||
615 | mempool_destroy(nfs_rdata_mempool); | ||
616 | if (kmem_cache_destroy(nfs_rdata_cachep)) | ||
617 | printk(KERN_INFO "nfs_read_data: not all structures were freed\n"); | ||
618 | } | ||