Blame view
fs/nfs/read.c
15.4 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 |
/* * linux/fs/nfs/read.c * * Block I/O for NFS * * Partial copy of Linus' read cache modifications to fs/nfs/file.c * modified for async RPC by okir@monad.swb.de |
1da177e4c Linux-2.6.12-rc2 |
8 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <linux/time.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/fcntl.h> #include <linux/stat.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/pagemap.h> #include <linux/sunrpc/clnt.h> #include <linux/nfs_fs.h> #include <linux/nfs_page.h> #include <linux/smp_lock.h> #include <asm/system.h> |
49a70f278 NFS: Cleanup: add... |
23 |
#include "internal.h" |
91d5b4702 NFS: add I/O perf... |
24 |
#include "iostat.h" |
1da177e4c Linux-2.6.12-rc2 |
25 |
#define NFSDBG_FACILITY NFSDBG_PAGECACHE |
8d5658c94 NFS: Fix a buffer... |
26 27 |
static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int); static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int); |
ec06c096e NFS: Cleanup of N... |
28 29 |
static const struct rpc_call_ops nfs_read_partial_ops; static const struct rpc_call_ops nfs_read_full_ops; |
1da177e4c Linux-2.6.12-rc2 |
30 |
|
e18b890bb [PATCH] slab: rem... |
31 |
static struct kmem_cache *nfs_rdata_cachep; |
3feb2d493 NFS: Uninline nfs... |
32 |
static mempool_t *nfs_rdata_mempool; |
1da177e4c Linux-2.6.12-rc2 |
33 34 |
#define MIN_POOL_READ (32) |
8d5658c94 NFS: Fix a buffer... |
35 |
struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) |
3feb2d493 NFS: Uninline nfs... |
36 |
{ |
e6b4f8da3 [PATCH] slab: rem... |
37 |
struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS); |
3feb2d493 NFS: Uninline nfs... |
38 39 40 41 |
if (p) { memset(p, 0, sizeof(*p)); INIT_LIST_HEAD(&p->pages); |
e9f7bee1d [PATCH] NFS: larg... |
42 |
p->npages = pagecount; |
0d0b5cb36 NFS: Optimize all... |
43 44 |
if (pagecount <= ARRAY_SIZE(p->page_array)) p->pagevec = p->page_array; |
3feb2d493 NFS: Uninline nfs... |
45 |
else { |
0d0b5cb36 NFS: Optimize all... |
46 47 |
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS); if (!p->pagevec) { |
3feb2d493 NFS: Uninline nfs... |
48 49 50 51 52 53 54 |
mempool_free(p, nfs_rdata_mempool); p = NULL; } } } return p; } |
5e4424af9 SUNRPC: Remove no... |
55 |
static void nfs_readdata_free(struct nfs_read_data *p) |
3feb2d493 NFS: Uninline nfs... |
56 57 58 59 60 |
{ if (p && (p->pagevec != &p->page_array[0])) kfree(p->pagevec); mempool_free(p, nfs_rdata_mempool); } |
963d8fe53 RPC: Clean up RPC... |
61 |
void nfs_readdata_release(void *data) |
1da177e4c Linux-2.6.12-rc2 |
62 |
{ |
383ba7193 NFS: Fix a deadlo... |
63 64 65 66 |
struct nfs_read_data *rdata = data; put_nfs_open_context(rdata->args.context); nfs_readdata_free(rdata); |
1da177e4c Linux-2.6.12-rc2 |
67 68 69 |
} static |
1da177e4c Linux-2.6.12-rc2 |
70 71 |
int nfs_return_empty_page(struct page *page) { |
eebd2aa35 Pagecache zeroing... |
72 |
zero_user(page, 0, PAGE_CACHE_SIZE); |
1da177e4c Linux-2.6.12-rc2 |
73 74 75 76 |
SetPageUptodate(page); unlock_page(page); return 0; } |
1de3fc12e NFS: Clean up and... |
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data) { unsigned int remainder = data->args.count - data->res.count; unsigned int base = data->args.pgbase + data->res.count; unsigned int pglen; struct page **pages; if (data->res.eof == 0 || remainder == 0) return; /* * Note: "remainder" can never be negative, since we check for * this in the XDR code. */ pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; base &= ~PAGE_CACHE_MASK; pglen = PAGE_CACHE_SIZE - base; |
79558f361 NFS: Fix issue wi... |
93 94 |
for (;;) { if (remainder <= pglen) { |
eebd2aa35 Pagecache zeroing... |
95 |
zero_user(*pages, base, remainder); |
79558f361 NFS: Fix issue wi... |
96 97 |
break; } |
eebd2aa35 Pagecache zeroing... |
98 |
zero_user(*pages, base, pglen); |
79558f361 NFS: Fix issue wi... |
99 100 101 102 103 |
pages++; remainder -= pglen; pglen = PAGE_CACHE_SIZE; base = 0; } |
1de3fc12e NFS: Clean up and... |
104 |
} |
1da177e4c Linux-2.6.12-rc2 |
105 106 107 108 109 110 |
static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, struct page *page) { LIST_HEAD(one_request); struct nfs_page *new; unsigned int len; |
49a70f278 NFS: Cleanup: add... |
111 |
len = nfs_page_length(page); |
1da177e4c Linux-2.6.12-rc2 |
112 113 114 115 116 117 118 119 |
if (len == 0) return nfs_return_empty_page(page); new = nfs_create_request(ctx, inode, page, 0, len); if (IS_ERR(new)) { unlock_page(page); return PTR_ERR(new); } if (len < PAGE_CACHE_SIZE) |
eebd2aa35 Pagecache zeroing... |
120 |
zero_user_segment(page, len, PAGE_CACHE_SIZE); |
1da177e4c Linux-2.6.12-rc2 |
121 |
|
1da177e4c Linux-2.6.12-rc2 |
122 |
nfs_list_add_request(new, &one_request); |
bcb71bba7 NFS: Another clea... |
123 |
if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) |
8d5658c94 NFS: Fix a buffer... |
124 |
nfs_pagein_multi(inode, &one_request, 1, len, 0); |
bcb71bba7 NFS: Another clea... |
125 |
else |
8d5658c94 NFS: Fix a buffer... |
126 |
nfs_pagein_one(inode, &one_request, 1, len, 0); |
1da177e4c Linux-2.6.12-rc2 |
127 128 129 130 131 132 |
return 0; } static void nfs_readpage_release(struct nfs_page *req) { unlock_page(req->wb_page); |
1da177e4c Linux-2.6.12-rc2 |
133 134 |
dprintk("NFS: read done (%s/%Ld %d@%Ld) ", |
88be9f990 NFS: Replace vfsm... |
135 136 |
req->wb_context->path.dentry->d_inode->i_sb->s_id, (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), |
1da177e4c Linux-2.6.12-rc2 |
137 138 |
req->wb_bytes, (long long)req_offset(req)); |
10d2c46f9 [PATCH] NFS: fix ... |
139 140 |
nfs_clear_request(req); nfs_release_request(req); |
1da177e4c Linux-2.6.12-rc2 |
141 142 143 144 145 |
} /* * Set up the NFS read request struct */ |
dbae4c73f NFS: Ensure that ... |
146 |
static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, |
ec06c096e NFS: Cleanup of N... |
147 |
const struct rpc_call_ops *call_ops, |
1da177e4c Linux-2.6.12-rc2 |
148 149 |
unsigned int count, unsigned int offset) { |
84115e1cd SUNRPC: Cleanup o... |
150 151 |
struct inode *inode = req->wb_context->path.dentry->d_inode; int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; |
077376919 NFS/SUNRPC: Conve... |
152 |
struct rpc_task *task; |
bdc7f021f NFS: Clean up the... |
153 154 155 156 157 |
struct rpc_message msg = { .rpc_argp = &data->args, .rpc_resp = &data->res, .rpc_cred = req->wb_context->cred, }; |
84115e1cd SUNRPC: Cleanup o... |
158 |
struct rpc_task_setup task_setup_data = { |
077376919 NFS/SUNRPC: Conve... |
159 |
.task = &data->task, |
84115e1cd SUNRPC: Cleanup o... |
160 |
.rpc_client = NFS_CLIENT(inode), |
bdc7f021f NFS: Clean up the... |
161 |
.rpc_message = &msg, |
84115e1cd SUNRPC: Cleanup o... |
162 163 |
.callback_ops = call_ops, .callback_data = data, |
101070ca2 NFS: Ensure that ... |
164 |
.workqueue = nfsiod_workqueue, |
84115e1cd SUNRPC: Cleanup o... |
165 166 |
.flags = RPC_TASK_ASYNC | swap_flags, }; |
1da177e4c Linux-2.6.12-rc2 |
167 168 |
data->req = req; |
84115e1cd SUNRPC: Cleanup o... |
169 |
data->inode = inode; |
bdc7f021f NFS: Clean up the... |
170 |
data->cred = msg.rpc_cred; |
1da177e4c Linux-2.6.12-rc2 |
171 172 173 174 175 176 |
data->args.fh = NFS_FH(inode); data->args.offset = req_offset(req) + offset; data->args.pgbase = req->wb_pgbase + offset; data->args.pages = data->pagevec; data->args.count = count; |
383ba7193 NFS: Fix a deadlo... |
177 |
data->args.context = get_nfs_open_context(req->wb_context); |
1da177e4c Linux-2.6.12-rc2 |
178 179 180 181 |
data->res.fattr = &data->fattr; data->res.count = count; data->res.eof = 0; |
0e574af1b NFS: Cleanup init... |
182 |
nfs_fattr_init(&data->fattr); |
1da177e4c Linux-2.6.12-rc2 |
183 |
|
ec06c096e NFS: Cleanup of N... |
184 |
/* Set up the initial task struct. */ |
bdc7f021f NFS: Clean up the... |
185 |
NFS_PROTO(inode)->read_setup(data, &msg); |
1da177e4c Linux-2.6.12-rc2 |
186 |
|
a3f565b1e NFS: fix print fo... |
187 188 |
dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu) ", |
1da177e4c Linux-2.6.12-rc2 |
189 190 191 192 193 |
data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), count, (unsigned long long)data->args.offset); |
bdc7f021f NFS: Clean up the... |
194 |
|
077376919 NFS/SUNRPC: Conve... |
195 |
task = rpc_run_task(&task_setup_data); |
dbae4c73f NFS: Ensure that ... |
196 197 198 199 |
if (IS_ERR(task)) return PTR_ERR(task); rpc_put_task(task); return 0; |
1da177e4c Linux-2.6.12-rc2 |
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
} static void nfs_async_read_error(struct list_head *head) { struct nfs_page *req; while (!list_empty(head)) { req = nfs_list_entry(head->next); nfs_list_remove_request(req); SetPageError(req->wb_page); nfs_readpage_release(req); } } /* |
1da177e4c Linux-2.6.12-rc2 |
216 217 218 219 220 221 222 223 224 225 226 227 |
* Generate multiple requests to fill a single page. * * We optimize to reduce the number of read operations on the wire. If we * detect that we're reading a page, or an area of a page, that is past the * end of file, we do not generate NFS read operations but just clear the * parts of the page that would have come back zero from the server anyway. * * We rely on the cached value of i_size to make this determination; another * client can fill pages on the server past our cached end-of-file, but we * won't see the new data until our attribute cache is updated. This is more * or less conventional NFS client behavior. */ |
8d5658c94 NFS: Fix a buffer... |
228 |
static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) |
1da177e4c Linux-2.6.12-rc2 |
229 230 231 232 |
{ struct nfs_page *req = nfs_list_entry(head->next); struct page *page = req->wb_page; struct nfs_read_data *data; |
e9f7bee1d [PATCH] NFS: larg... |
233 234 |
size_t rsize = NFS_SERVER(inode)->rsize, nbytes; unsigned int offset; |
1da177e4c Linux-2.6.12-rc2 |
235 |
int requests = 0; |
dbae4c73f NFS: Ensure that ... |
236 |
int ret = 0; |
1da177e4c Linux-2.6.12-rc2 |
237 238 239 |
LIST_HEAD(list); nfs_list_remove_request(req); |
bcb71bba7 NFS: Another clea... |
240 |
nbytes = count; |
e9f7bee1d [PATCH] NFS: larg... |
241 242 |
do { size_t len = min(nbytes,rsize); |
8d5658c94 NFS: Fix a buffer... |
243 |
data = nfs_readdata_alloc(1); |
1da177e4c Linux-2.6.12-rc2 |
244 245 |
if (!data) goto out_bad; |
1da177e4c Linux-2.6.12-rc2 |
246 247 |
list_add(&data->pages, &list); requests++; |
e9f7bee1d [PATCH] NFS: larg... |
248 249 |
nbytes -= len; } while(nbytes != 0); |
1da177e4c Linux-2.6.12-rc2 |
250 251 252 253 |
atomic_set(&req->wb_complete, requests); ClearPageError(page); offset = 0; |
bcb71bba7 NFS: Another clea... |
254 |
nbytes = count; |
1da177e4c Linux-2.6.12-rc2 |
255 |
do { |
dbae4c73f NFS: Ensure that ... |
256 |
int ret2; |
1da177e4c Linux-2.6.12-rc2 |
257 258 259 260 |
data = list_entry(list.next, struct nfs_read_data, pages); list_del_init(&data->pages); data->pagevec[0] = page; |
1da177e4c Linux-2.6.12-rc2 |
261 |
|
bcb71bba7 NFS: Another clea... |
262 263 |
if (nbytes < rsize) rsize = nbytes; |
dbae4c73f NFS: Ensure that ... |
264 |
ret2 = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
bcb71bba7 NFS: Another clea... |
265 |
rsize, offset); |
dbae4c73f NFS: Ensure that ... |
266 267 |
if (ret == 0) ret = ret2; |
bcb71bba7 NFS: Another clea... |
268 269 |
offset += rsize; nbytes -= rsize; |
1da177e4c Linux-2.6.12-rc2 |
270 |
} while (nbytes != 0); |
dbae4c73f NFS: Ensure that ... |
271 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
272 273 274 275 276 277 278 279 280 281 282 |
out_bad: while (!list_empty(&list)) { data = list_entry(list.next, struct nfs_read_data, pages); list_del(&data->pages); nfs_readdata_free(data); } SetPageError(page); nfs_readpage_release(req); return -ENOMEM; } |
8d5658c94 NFS: Fix a buffer... |
283 |
static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) |
1da177e4c Linux-2.6.12-rc2 |
284 285 286 287 |
{ struct nfs_page *req; struct page **pages; struct nfs_read_data *data; |
dbae4c73f NFS: Ensure that ... |
288 |
int ret = -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
289 |
|
8d5658c94 NFS: Fix a buffer... |
290 |
data = nfs_readdata_alloc(npages); |
1da177e4c Linux-2.6.12-rc2 |
291 292 |
if (!data) goto out_bad; |
1da177e4c Linux-2.6.12-rc2 |
293 |
pages = data->pagevec; |
1da177e4c Linux-2.6.12-rc2 |
294 295 296 297 298 299 |
while (!list_empty(head)) { req = nfs_list_entry(head->next); nfs_list_remove_request(req); nfs_list_add_request(req, &data->pages); ClearPageError(req->wb_page); *pages++ = req->wb_page; |
1da177e4c Linux-2.6.12-rc2 |
300 301 |
} req = nfs_list_entry(data->pages.next); |
dbae4c73f NFS: Ensure that ... |
302 |
return nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); |
1da177e4c Linux-2.6.12-rc2 |
303 304 |
out_bad: nfs_async_read_error(head); |
dbae4c73f NFS: Ensure that ... |
305 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
306 |
} |
1da177e4c Linux-2.6.12-rc2 |
307 |
/* |
0b6713014 NFS: Fix asynchro... |
308 309 310 311 312 313 |
* This is the callback from RPC telling us whether a reply was * received or some error occurred (timeout or socket shutdown). */ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) { int status; |
3110ff804 nfs: replace rema... |
314 315 |
dprintk("NFS: %s: %5u, (status %d) ", __func__, task->tk_pid, |
0b6713014 NFS: Fix asynchro... |
316 317 318 319 320 321 322 323 324 |
task->tk_status); status = NFS_PROTO(data->inode)->read_done(task, data); if (status != 0) return status; nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, data->res.count); if (task->tk_status == -ESTALE) { |
3a10c30ac nfs: obliterate N... |
325 |
set_bit(NFS_INO_STALE, &NFS_I(data->inode)->flags); |
0b6713014 NFS: Fix asynchro... |
326 327 |
nfs_mark_for_revalidate(data->inode); } |
0b6713014 NFS: Fix asynchro... |
328 329 |
return 0; } |
fdd1e74c8 NFS: Ensure that ... |
330 |
static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) |
0b6713014 NFS: Fix asynchro... |
331 332 333 334 335 |
{ struct nfs_readargs *argp = &data->args; struct nfs_readres *resp = &data->res; if (resp->eof || resp->count == argp->count) |
fdd1e74c8 NFS: Ensure that ... |
336 |
return; |
0b6713014 NFS: Fix asynchro... |
337 338 339 340 341 |
/* This is a short read! */ nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); /* Has the server at least made some progress? */ if (resp->count == 0) |
fdd1e74c8 NFS: Ensure that ... |
342 |
return; |
0b6713014 NFS: Fix asynchro... |
343 344 345 346 347 348 |
/* Yes, so retry the read at the end of the data */ argp->offset += resp->count; argp->pgbase += resp->count; argp->count -= resp->count; rpc_restart_call(task); |
0b6713014 NFS: Fix asynchro... |
349 350 351 |
} /* |
1da177e4c Linux-2.6.12-rc2 |
352 353 |
* Handle a read reply that fills part of a page. */ |
ec06c096e NFS: Cleanup of N... |
354 |
static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) |
1da177e4c Linux-2.6.12-rc2 |
355 |
{ |
ec06c096e NFS: Cleanup of N... |
356 |
struct nfs_read_data *data = calldata; |
1da177e4c Linux-2.6.12-rc2 |
357 |
|
ec06c096e NFS: Cleanup of N... |
358 359 |
if (nfs_readpage_result(task, data) != 0) return; |
fdd1e74c8 NFS: Ensure that ... |
360 361 |
if (task->tk_status < 0) return; |
0b6713014 NFS: Fix asynchro... |
362 |
|
fdd1e74c8 NFS: Ensure that ... |
363 364 365 366 367 368 369 370 371 372 373 374 |
nfs_readpage_truncate_uninitialised_page(data); nfs_readpage_retry(task, data); } static void nfs_readpage_release_partial(void *calldata) { struct nfs_read_data *data = calldata; struct nfs_page *req = data->req; struct page *page = req->wb_page; int status = data->task.tk_status; if (status < 0) |
0b6713014 NFS: Fix asynchro... |
375 |
SetPageError(page); |
fdd1e74c8 NFS: Ensure that ... |
376 |
|
1da177e4c Linux-2.6.12-rc2 |
377 378 379 380 381 |
if (atomic_dec_and_test(&req->wb_complete)) { if (!PageError(page)) SetPageUptodate(page); nfs_readpage_release(req); } |
fdd1e74c8 NFS: Ensure that ... |
382 |
nfs_readdata_release(calldata); |
1da177e4c Linux-2.6.12-rc2 |
383 |
} |
ec06c096e NFS: Cleanup of N... |
384 385 |
static const struct rpc_call_ops nfs_read_partial_ops = { .rpc_call_done = nfs_readpage_result_partial, |
fdd1e74c8 NFS: Ensure that ... |
386 |
.rpc_release = nfs_readpage_release_partial, |
ec06c096e NFS: Cleanup of N... |
387 |
}; |
1de3fc12e NFS: Clean up and... |
388 389 390 391 392 |
static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) { unsigned int count = data->res.count; unsigned int base = data->args.pgbase; struct page **pages; |
79558f361 NFS: Fix issue wi... |
393 394 |
if (data->res.eof) count = data->args.count; |
1de3fc12e NFS: Clean up and... |
395 396 397 398 399 400 401 |
if (unlikely(count == 0)) return; pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; base &= ~PAGE_CACHE_MASK; count += base; for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) SetPageUptodate(*pages); |
0b6713014 NFS: Fix asynchro... |
402 403 404 405 |
if (count == 0) return; /* Was this a short read? */ if (data->res.eof || data->res.count == data->args.count) |
1de3fc12e NFS: Clean up and... |
406 407 |
SetPageUptodate(*pages); } |
1da177e4c Linux-2.6.12-rc2 |
408 409 410 411 |
/* * This is the callback from RPC telling us whether a reply was * received or some error occurred (timeout or socket shutdown). */ |
ec06c096e NFS: Cleanup of N... |
412 |
static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) |
1da177e4c Linux-2.6.12-rc2 |
413 |
{ |
ec06c096e NFS: Cleanup of N... |
414 |
struct nfs_read_data *data = calldata; |
1da177e4c Linux-2.6.12-rc2 |
415 |
|
0b6713014 NFS: Fix asynchro... |
416 417 |
if (nfs_readpage_result(task, data) != 0) return; |
fdd1e74c8 NFS: Ensure that ... |
418 419 |
if (task->tk_status < 0) return; |
1de3fc12e NFS: Clean up and... |
420 |
/* |
0b6713014 NFS: Fix asynchro... |
421 |
* Note: nfs_readpage_retry may change the values of |
1de3fc12e NFS: Clean up and... |
422 |
* data->args. In the multi-page case, we therefore need |
0b6713014 NFS: Fix asynchro... |
423 424 |
* to ensure that we call nfs_readpage_set_pages_uptodate() * first. |
1de3fc12e NFS: Clean up and... |
425 |
*/ |
fdd1e74c8 NFS: Ensure that ... |
426 427 428 429 430 431 432 433 |
nfs_readpage_truncate_uninitialised_page(data); nfs_readpage_set_pages_uptodate(data); nfs_readpage_retry(task, data); } static void nfs_readpage_release_full(void *calldata) { struct nfs_read_data *data = calldata; |
1da177e4c Linux-2.6.12-rc2 |
434 435 |
while (!list_empty(&data->pages)) { struct nfs_page *req = nfs_list_entry(data->pages.next); |
1da177e4c Linux-2.6.12-rc2 |
436 |
|
1de3fc12e NFS: Clean up and... |
437 |
nfs_list_remove_request(req); |
1da177e4c Linux-2.6.12-rc2 |
438 439 |
nfs_readpage_release(req); } |
fdd1e74c8 NFS: Ensure that ... |
440 |
nfs_readdata_release(calldata); |
1da177e4c Linux-2.6.12-rc2 |
441 |
} |
ec06c096e NFS: Cleanup of N... |
442 443 |
static const struct rpc_call_ops nfs_read_full_ops = { .rpc_call_done = nfs_readpage_result_full, |
fdd1e74c8 NFS: Ensure that ... |
444 |
.rpc_release = nfs_readpage_release_full, |
ec06c096e NFS: Cleanup of N... |
445 |
}; |
1da177e4c Linux-2.6.12-rc2 |
446 |
/* |
1da177e4c Linux-2.6.12-rc2 |
447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
* Read a page over NFS. * We read the page synchronously in the following case: * - The error flag is set for this page. This happens only when a * previous async read operation failed. */ int nfs_readpage(struct file *file, struct page *page) { struct nfs_open_context *ctx; struct inode *inode = page->mapping->host; int error; dprintk("NFS: nfs_readpage (%p %ld@%lu) ", page, PAGE_CACHE_SIZE, page->index); |
91d5b4702 NFS: add I/O perf... |
461 462 |
nfs_inc_stats(inode, NFSIOS_VFSREADPAGE); nfs_add_stats(inode, NFSIOS_READPAGES, 1); |
1da177e4c Linux-2.6.12-rc2 |
463 464 465 466 467 468 469 470 471 |
/* * Try to flush any pending writes to the file.. * * NOTE! Because we own the page lock, there cannot * be any new pending writes generated at this point * for this page (other pages can be written to). */ error = nfs_wb_page(inode, page); if (error) |
de05a0cc2 NFS: Minor read o... |
472 473 474 |
goto out_unlock; if (PageUptodate(page)) goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
475 |
|
5f004cf2a NFS: Make read() ... |
476 477 |
error = -ESTALE; if (NFS_STALE(inode)) |
de05a0cc2 NFS: Minor read o... |
478 |
goto out_unlock; |
5f004cf2a NFS: Make read() ... |
479 |
|
1da177e4c Linux-2.6.12-rc2 |
480 |
if (file == NULL) { |
cf1308ff7 NFS: Fix missing ... |
481 |
error = -EBADF; |
d530838bf NFSv4: Fix proble... |
482 |
ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
1da177e4c Linux-2.6.12-rc2 |
483 |
if (ctx == NULL) |
de05a0cc2 NFS: Minor read o... |
484 |
goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
485 |
} else |
cd3758e37 NFS: Replace file... |
486 |
ctx = get_nfs_open_context(nfs_file_open_context(file)); |
1da177e4c Linux-2.6.12-rc2 |
487 |
|
8e0969f04 NFS: Remove nfs_r... |
488 |
error = nfs_readpage_async(ctx, inode, page); |
1da177e4c Linux-2.6.12-rc2 |
489 490 |
put_nfs_open_context(ctx); return error; |
de05a0cc2 NFS: Minor read o... |
491 |
out_unlock: |
1da177e4c Linux-2.6.12-rc2 |
492 493 494 495 496 |
unlock_page(page); return error; } struct nfs_readdesc { |
8b09bee30 NFS: Cleanup for ... |
497 |
struct nfs_pageio_descriptor *pgio; |
1da177e4c Linux-2.6.12-rc2 |
498 499 500 501 502 503 504 505 506 507 |
struct nfs_open_context *ctx; }; static int readpage_async_filler(void *data, struct page *page) { struct nfs_readdesc *desc = (struct nfs_readdesc *)data; struct inode *inode = page->mapping->host; struct nfs_page *new; unsigned int len; |
de05a0cc2 NFS: Minor read o... |
508 509 510 511 512 513 514 |
int error; error = nfs_wb_page(inode, page); if (error) goto out_unlock; if (PageUptodate(page)) goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
515 |
|
49a70f278 NFS: Cleanup: add... |
516 |
len = nfs_page_length(page); |
1da177e4c Linux-2.6.12-rc2 |
517 518 |
if (len == 0) return nfs_return_empty_page(page); |
de05a0cc2 NFS: Minor read o... |
519 |
|
1da177e4c Linux-2.6.12-rc2 |
520 |
new = nfs_create_request(desc->ctx, inode, page, 0, len); |
de05a0cc2 NFS: Minor read o... |
521 522 |
if (IS_ERR(new)) goto out_error; |
1da177e4c Linux-2.6.12-rc2 |
523 |
if (len < PAGE_CACHE_SIZE) |
eebd2aa35 Pagecache zeroing... |
524 |
zero_user_segment(page, len, PAGE_CACHE_SIZE); |
f8512ad0d nfs: don't ignore... |
525 526 527 528 |
if (!nfs_pageio_add_request(desc->pgio, new)) { error = desc->pgio->pg_error; goto out_unlock; } |
1da177e4c Linux-2.6.12-rc2 |
529 |
return 0; |
de05a0cc2 NFS: Minor read o... |
530 531 532 533 534 535 |
out_error: error = PTR_ERR(new); SetPageError(page); out_unlock: unlock_page(page); return error; |
1da177e4c Linux-2.6.12-rc2 |
536 537 538 539 540 |
} int nfs_readpages(struct file *filp, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { |
8b09bee30 NFS: Cleanup for ... |
541 |
struct nfs_pageio_descriptor pgio; |
1da177e4c Linux-2.6.12-rc2 |
542 |
struct nfs_readdesc desc = { |
8b09bee30 NFS: Cleanup for ... |
543 |
.pgio = &pgio, |
1da177e4c Linux-2.6.12-rc2 |
544 545 546 |
}; struct inode *inode = mapping->host; struct nfs_server *server = NFS_SERVER(inode); |
8b09bee30 NFS: Cleanup for ... |
547 548 |
size_t rsize = server->rsize; unsigned long npages; |
5f004cf2a NFS: Make read() ... |
549 |
int ret = -ESTALE; |
1da177e4c Linux-2.6.12-rc2 |
550 551 552 553 554 555 |
dprintk("NFS: nfs_readpages (%s/%Ld %d) ", inode->i_sb->s_id, (long long)NFS_FILEID(inode), nr_pages); |
91d5b4702 NFS: add I/O perf... |
556 |
nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); |
1da177e4c Linux-2.6.12-rc2 |
557 |
|
5f004cf2a NFS: Make read() ... |
558 559 |
if (NFS_STALE(inode)) goto out; |
1da177e4c Linux-2.6.12-rc2 |
560 |
if (filp == NULL) { |
d530838bf NFSv4: Fix proble... |
561 |
desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
1da177e4c Linux-2.6.12-rc2 |
562 563 564 |
if (desc.ctx == NULL) return -EBADF; } else |
cd3758e37 NFS: Replace file... |
565 |
desc.ctx = get_nfs_open_context(nfs_file_open_context(filp)); |
8b09bee30 NFS: Cleanup for ... |
566 567 568 569 |
if (rsize < PAGE_CACHE_SIZE) nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); else nfs_pageio_init(&pgio, inode, nfs_pagein_one, rsize, 0); |
1da177e4c Linux-2.6.12-rc2 |
570 |
ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); |
8b09bee30 NFS: Cleanup for ... |
571 572 573 574 |
nfs_pageio_complete(&pgio); npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; nfs_add_stats(inode, NFSIOS_READPAGES, npages); |
1da177e4c Linux-2.6.12-rc2 |
575 |
put_nfs_open_context(desc.ctx); |
5f004cf2a NFS: Make read() ... |
576 |
out: |
1da177e4c Linux-2.6.12-rc2 |
577 578 |
return ret; } |
f7b422b17 NFS: Split fs/nfs... |
579 |
int __init nfs_init_readpagecache(void) |
1da177e4c Linux-2.6.12-rc2 |
580 581 582 583 |
{ nfs_rdata_cachep = kmem_cache_create("nfs_read_data", sizeof(struct nfs_read_data), 0, SLAB_HWCACHE_ALIGN, |
20c2df83d mm: Remove slab d... |
584 |
NULL); |
1da177e4c Linux-2.6.12-rc2 |
585 586 |
if (nfs_rdata_cachep == NULL) return -ENOMEM; |
93d2341c7 [PATCH] mempool: ... |
587 588 |
nfs_rdata_mempool = mempool_create_slab_pool(MIN_POOL_READ, nfs_rdata_cachep); |
1da177e4c Linux-2.6.12-rc2 |
589 590 591 592 593 |
if (nfs_rdata_mempool == NULL) return -ENOMEM; return 0; } |
266bee886 [PATCH] fix stati... |
594 |
void nfs_destroy_readpagecache(void) |
1da177e4c Linux-2.6.12-rc2 |
595 596 |
{ mempool_destroy(nfs_rdata_mempool); |
1a1d92c10 [PATCH] Really ig... |
597 |
kmem_cache_destroy(nfs_rdata_cachep); |
1da177e4c Linux-2.6.12-rc2 |
598 |
} |