Blame view
fs/nfs/read.c
17.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 |
#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> |
64419a9b2 NFSv4.1: generic ... |
20 |
#include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
21 22 |
#include <asm/system.h> |
bae724ef9 NFSv4.1: shift pn... |
23 |
#include "pnfs.h" |
1da177e4c Linux-2.6.12-rc2 |
24 |
|
f11c88af2 nfs41: read seque... |
25 |
#include "nfs4_fs.h" |
49a70f278 NFS: Cleanup: add... |
26 |
#include "internal.h" |
91d5b4702 NFS: add I/O perf... |
27 |
#include "iostat.h" |
9a9fc1c03 NFS: Read pages f... |
28 |
#include "fscache.h" |
91d5b4702 NFS: add I/O perf... |
29 |
|
1da177e4c Linux-2.6.12-rc2 |
30 |
#define NFSDBG_FACILITY NFSDBG_PAGECACHE |
1751c3638 NFS: Cleanup of t... |
31 |
static const struct nfs_pageio_ops nfs_pageio_read_ops; |
ec06c096e NFS: Cleanup of N... |
32 33 |
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 |
34 |
|
e18b890bb [PATCH] slab: rem... |
35 |
static struct kmem_cache *nfs_rdata_cachep; |
1da177e4c Linux-2.6.12-rc2 |
36 |
|
8d5658c94 NFS: Fix a buffer... |
37 |
struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) |
3feb2d493 NFS: Uninline nfs... |
38 |
{ |
b6ee8cd26 NFS: Get rid of t... |
39 |
struct nfs_read_data *p; |
3feb2d493 NFS: Uninline nfs... |
40 |
|
b6ee8cd26 NFS: Get rid of t... |
41 |
p = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL); |
3feb2d493 NFS: Uninline nfs... |
42 |
if (p) { |
3feb2d493 NFS: Uninline nfs... |
43 |
INIT_LIST_HEAD(&p->pages); |
e9f7bee1d [PATCH] NFS: larg... |
44 |
p->npages = pagecount; |
0d0b5cb36 NFS: Optimize all... |
45 46 |
if (pagecount <= ARRAY_SIZE(p->page_array)) p->pagevec = p->page_array; |
3feb2d493 NFS: Uninline nfs... |
47 |
else { |
93870d76f NFS: Read request... |
48 |
p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL); |
0d0b5cb36 NFS: Optimize all... |
49 |
if (!p->pagevec) { |
b6ee8cd26 NFS: Get rid of t... |
50 |
kmem_cache_free(nfs_rdata_cachep, p); |
3feb2d493 NFS: Uninline nfs... |
51 52 53 54 55 56 |
p = NULL; } } } return p; } |
1ae88b2e4 NFS: Fix an O_DIR... |
57 |
void nfs_readdata_free(struct nfs_read_data *p) |
3feb2d493 NFS: Uninline nfs... |
58 59 60 |
{ if (p && (p->pagevec != &p->page_array[0])) kfree(p->pagevec); |
b6ee8cd26 NFS: Get rid of t... |
61 |
kmem_cache_free(nfs_rdata_cachep, p); |
3feb2d493 NFS: Uninline nfs... |
62 |
} |
493292ddc NFS: Move the pnf... |
63 |
void nfs_readdata_release(struct nfs_read_data *rdata) |
1da177e4c Linux-2.6.12-rc2 |
64 |
{ |
bae724ef9 NFSv4.1: shift pn... |
65 |
put_lseg(rdata->lseg); |
383ba7193 NFS: Fix a deadlo... |
66 67 |
put_nfs_open_context(rdata->args.context); nfs_readdata_free(rdata); |
1da177e4c Linux-2.6.12-rc2 |
68 69 70 |
} static |
1da177e4c Linux-2.6.12-rc2 |
71 72 |
int nfs_return_empty_page(struct page *page) { |
eebd2aa35 Pagecache zeroing... |
73 |
zero_user(page, 0, PAGE_CACHE_SIZE); |
1da177e4c Linux-2.6.12-rc2 |
74 75 76 77 |
SetPageUptodate(page); unlock_page(page); return 0; } |
1de3fc12e NFS: Clean up and... |
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
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... |
94 95 |
for (;;) { if (remainder <= pglen) { |
eebd2aa35 Pagecache zeroing... |
96 |
zero_user(*pages, base, remainder); |
79558f361 NFS: Fix issue wi... |
97 98 |
break; } |
eebd2aa35 Pagecache zeroing... |
99 |
zero_user(*pages, base, pglen); |
79558f361 NFS: Fix issue wi... |
100 101 102 103 104 |
pages++; remainder -= pglen; pglen = PAGE_CACHE_SIZE; base = 0; } |
1de3fc12e NFS: Clean up and... |
105 |
} |
62e4a7698 NFS: Revert pnfs ... |
106 |
void nfs_pageio_init_read_mds(struct nfs_pageio_descriptor *pgio, |
1751c3638 NFS: Cleanup of t... |
107 108 109 110 111 |
struct inode *inode) { nfs_pageio_init(pgio, inode, &nfs_pageio_read_ops, NFS_SERVER(inode)->rsize, 0); } |
493292ddc NFS: Move the pnf... |
112 113 114 115 116 |
void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio) { pgio->pg_ops = &nfs_pageio_read_ops; pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize; } |
1f9453578 NFS: Clean up - s... |
117 |
EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds); |
493292ddc NFS: Move the pnf... |
118 |
|
1751c3638 NFS: Cleanup of t... |
119 120 121 122 123 124 |
static void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode) { if (!pnfs_pageio_init_read(pgio, inode)) nfs_pageio_init_read_mds(pgio, inode); } |
f42b293d6 NFS: nfs_readpage... |
125 126 |
int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, struct page *page) |
1da177e4c Linux-2.6.12-rc2 |
127 |
{ |
1da177e4c Linux-2.6.12-rc2 |
128 129 |
struct nfs_page *new; unsigned int len; |
c76069bda NFSv4.1: rearrang... |
130 |
struct nfs_pageio_descriptor pgio; |
1da177e4c Linux-2.6.12-rc2 |
131 |
|
49a70f278 NFS: Cleanup: add... |
132 |
len = nfs_page_length(page); |
1da177e4c Linux-2.6.12-rc2 |
133 134 135 136 137 138 139 140 |
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... |
141 |
zero_user_segment(page, len, PAGE_CACHE_SIZE); |
1da177e4c Linux-2.6.12-rc2 |
142 |
|
1751c3638 NFS: Cleanup of t... |
143 |
nfs_pageio_init_read(&pgio, inode); |
d8007d4dd NFSv4.1: Add an i... |
144 |
nfs_pageio_add_request(&pgio, new); |
1751c3638 NFS: Cleanup of t... |
145 |
nfs_pageio_complete(&pgio); |
1da177e4c Linux-2.6.12-rc2 |
146 147 148 149 150 |
return 0; } static void nfs_readpage_release(struct nfs_page *req) { |
3d4ff43d8 nfs_open_context ... |
151 |
struct inode *d_inode = req->wb_context->dentry->d_inode; |
7f8e05f60 NFS: Store pages ... |
152 153 154 |
if (PageUptodate(req->wb_page)) nfs_readpage_to_fscache(d_inode, req->wb_page, 0); |
1da177e4c Linux-2.6.12-rc2 |
155 |
unlock_page(req->wb_page); |
1da177e4c Linux-2.6.12-rc2 |
156 157 |
dprintk("NFS: read done (%s/%Ld %d@%Ld) ", |
3d4ff43d8 nfs_open_context ... |
158 159 |
req->wb_context->dentry->d_inode->i_sb->s_id, (long long)NFS_FILEID(req->wb_context->dentry->d_inode), |
1da177e4c Linux-2.6.12-rc2 |
160 161 |
req->wb_bytes, (long long)req_offset(req)); |
10d2c46f9 [PATCH] NFS: fix ... |
162 |
nfs_release_request(req); |
1da177e4c Linux-2.6.12-rc2 |
163 |
} |
dc70d7b31 NFSv4.1: filelayo... |
164 |
int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt, |
64419a9b2 NFSv4.1: generic ... |
165 |
const struct rpc_call_ops *call_ops) |
1da177e4c Linux-2.6.12-rc2 |
166 |
{ |
64419a9b2 NFSv4.1: generic ... |
167 |
struct inode *inode = data->inode; |
84115e1cd SUNRPC: Cleanup o... |
168 |
int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; |
077376919 NFS/SUNRPC: Conve... |
169 |
struct rpc_task *task; |
bdc7f021f NFS: Clean up the... |
170 171 172 |
struct rpc_message msg = { .rpc_argp = &data->args, .rpc_resp = &data->res, |
64419a9b2 NFSv4.1: generic ... |
173 |
.rpc_cred = data->cred, |
bdc7f021f NFS: Clean up the... |
174 |
}; |
84115e1cd SUNRPC: Cleanup o... |
175 |
struct rpc_task_setup task_setup_data = { |
077376919 NFS/SUNRPC: Conve... |
176 |
.task = &data->task, |
64419a9b2 NFSv4.1: generic ... |
177 |
.rpc_client = clnt, |
bdc7f021f NFS: Clean up the... |
178 |
.rpc_message = &msg, |
84115e1cd SUNRPC: Cleanup o... |
179 180 |
.callback_ops = call_ops, .callback_data = data, |
101070ca2 NFS: Ensure that ... |
181 |
.workqueue = nfsiod_workqueue, |
84115e1cd SUNRPC: Cleanup o... |
182 183 |
.flags = RPC_TASK_ASYNC | swap_flags, }; |
1da177e4c Linux-2.6.12-rc2 |
184 |
|
64419a9b2 NFSv4.1: generic ... |
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
/* Set up the initial task struct. */ NFS_PROTO(inode)->read_setup(data, &msg); dprintk("NFS: %5u initiated read call (req %s/%lld, %u bytes @ " "offset %llu) ", data->task.tk_pid, inode->i_sb->s_id, (long long)NFS_FILEID(inode), data->args.count, (unsigned long long)data->args.offset); task = rpc_run_task(&task_setup_data); if (IS_ERR(task)) return PTR_ERR(task); rpc_put_task(task); return 0; } |
dc70d7b31 NFSv4.1: filelayo... |
203 |
EXPORT_SYMBOL_GPL(nfs_initiate_read); |
64419a9b2 NFSv4.1: generic ... |
204 205 206 207 |
/* * Set up the NFS read request struct */ |
6e4efd568 NFS: Clean up nfs... |
208 209 |
static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, unsigned int count, unsigned int offset) |
64419a9b2 NFSv4.1: generic ... |
210 |
{ |
3d4ff43d8 nfs_open_context ... |
211 |
struct inode *inode = req->wb_context->dentry->d_inode; |
64419a9b2 NFSv4.1: generic ... |
212 |
|
1da177e4c Linux-2.6.12-rc2 |
213 |
data->req = req; |
84115e1cd SUNRPC: Cleanup o... |
214 |
data->inode = inode; |
64419a9b2 NFSv4.1: generic ... |
215 |
data->cred = req->wb_context->cred; |
1da177e4c Linux-2.6.12-rc2 |
216 217 218 219 220 221 |
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... |
222 |
data->args.context = get_nfs_open_context(req->wb_context); |
f11ac8db5 NFSv4: Ensure tha... |
223 |
data->args.lock_context = req->wb_lock_context; |
1da177e4c Linux-2.6.12-rc2 |
224 225 226 227 |
data->res.fattr = &data->fattr; data->res.count = count; data->res.eof = 0; |
0e574af1b NFS: Cleanup init... |
228 |
nfs_fattr_init(&data->fattr); |
6e4efd568 NFS: Clean up nfs... |
229 |
} |
1da177e4c Linux-2.6.12-rc2 |
230 |
|
6e4efd568 NFS: Clean up nfs... |
231 |
static int nfs_do_read(struct nfs_read_data *data, |
493292ddc NFS: Move the pnf... |
232 |
const struct rpc_call_ops *call_ops) |
6e4efd568 NFS: Clean up nfs... |
233 |
{ |
5f00bcb38 Merge branch 'mas... |
234 |
struct inode *inode = data->args.context->dentry->d_inode; |
6e4efd568 NFS: Clean up nfs... |
235 |
|
64419a9b2 NFSv4.1: generic ... |
236 |
return nfs_initiate_read(data, NFS_CLIENT(inode), call_ops); |
1da177e4c Linux-2.6.12-rc2 |
237 |
} |
275acaafd NFS: Clean up: sp... |
238 239 |
static int nfs_do_multiple_reads(struct list_head *head, |
493292ddc NFS: Move the pnf... |
240 |
const struct rpc_call_ops *call_ops) |
275acaafd NFS: Clean up: sp... |
241 242 243 244 245 246 247 248 249 |
{ struct nfs_read_data *data; int ret = 0; while (!list_empty(head)) { int ret2; data = list_entry(head->next, struct nfs_read_data, list); list_del_init(&data->list); |
493292ddc NFS: Move the pnf... |
250 |
ret2 = nfs_do_read(data, call_ops); |
275acaafd NFS: Clean up: sp... |
251 252 253 254 255 |
if (ret == 0) ret = ret2; } return ret; } |
1da177e4c Linux-2.6.12-rc2 |
256 257 258 259 260 261 262 263 |
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); |
1da177e4c Linux-2.6.12-rc2 |
264 265 266 267 268 |
nfs_readpage_release(req); } } /* |
1da177e4c Linux-2.6.12-rc2 |
269 270 271 272 273 274 275 276 277 278 279 280 |
* 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. */ |
275acaafd NFS: Clean up: sp... |
281 |
static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head *res) |
1da177e4c Linux-2.6.12-rc2 |
282 |
{ |
c76069bda NFSv4.1: rearrang... |
283 |
struct nfs_page *req = nfs_list_entry(desc->pg_list.next); |
1da177e4c Linux-2.6.12-rc2 |
284 285 |
struct page *page = req->wb_page; struct nfs_read_data *data; |
d097971d8 NFS: Use the nfs_... |
286 |
size_t rsize = desc->pg_bsize, nbytes; |
e9f7bee1d [PATCH] NFS: larg... |
287 |
unsigned int offset; |
1da177e4c Linux-2.6.12-rc2 |
288 |
int requests = 0; |
dbae4c73f NFS: Ensure that ... |
289 |
int ret = 0; |
1da177e4c Linux-2.6.12-rc2 |
290 291 |
nfs_list_remove_request(req); |
275acaafd NFS: Clean up: sp... |
292 |
offset = 0; |
c76069bda NFSv4.1: rearrang... |
293 |
nbytes = desc->pg_count; |
e9f7bee1d [PATCH] NFS: larg... |
294 295 |
do { size_t len = min(nbytes,rsize); |
8d5658c94 NFS: Fix a buffer... |
296 |
data = nfs_readdata_alloc(1); |
1da177e4c Linux-2.6.12-rc2 |
297 298 |
if (!data) goto out_bad; |
275acaafd NFS: Clean up: sp... |
299 300 301 |
data->pagevec[0] = page; nfs_read_rpcsetup(req, data, len, offset); list_add(&data->list, res); |
1da177e4c Linux-2.6.12-rc2 |
302 |
requests++; |
e9f7bee1d [PATCH] NFS: larg... |
303 |
nbytes -= len; |
275acaafd NFS: Clean up: sp... |
304 |
offset += len; |
e9f7bee1d [PATCH] NFS: larg... |
305 |
} while(nbytes != 0); |
1da177e4c Linux-2.6.12-rc2 |
306 |
atomic_set(&req->wb_complete, requests); |
50828d7e6 NFS: Cache rpc_op... |
307 |
desc->pg_rpc_callops = &nfs_read_partial_ops; |
dbae4c73f NFS: Ensure that ... |
308 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
309 |
out_bad: |
275acaafd NFS: Clean up: sp... |
310 311 |
while (!list_empty(res)) { data = list_entry(res->next, struct nfs_read_data, list); |
6e4efd568 NFS: Clean up nfs... |
312 |
list_del(&data->list); |
1da177e4c Linux-2.6.12-rc2 |
313 314 |
nfs_readdata_free(data); } |
1da177e4c Linux-2.6.12-rc2 |
315 316 317 |
nfs_readpage_release(req); return -ENOMEM; } |
275acaafd NFS: Clean up: sp... |
318 |
static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, struct list_head *res) |
1da177e4c Linux-2.6.12-rc2 |
319 320 321 322 |
{ struct nfs_page *req; struct page **pages; struct nfs_read_data *data; |
c76069bda NFSv4.1: rearrang... |
323 |
struct list_head *head = &desc->pg_list; |
3b6091846 NFS: fix return v... |
324 |
int ret = 0; |
1da177e4c Linux-2.6.12-rc2 |
325 |
|
c76069bda NFSv4.1: rearrang... |
326 327 |
data = nfs_readdata_alloc(nfs_page_array_len(desc->pg_base, desc->pg_count)); |
bae724ef9 NFSv4.1: shift pn... |
328 329 |
if (!data) { nfs_async_read_error(head); |
3b6091846 NFS: fix return v... |
330 |
ret = -ENOMEM; |
bae724ef9 NFSv4.1: shift pn... |
331 332 |
goto out; } |
1da177e4c Linux-2.6.12-rc2 |
333 |
|
1da177e4c Linux-2.6.12-rc2 |
334 |
pages = data->pagevec; |
1da177e4c Linux-2.6.12-rc2 |
335 336 337 338 |
while (!list_empty(head)) { req = nfs_list_entry(head->next); nfs_list_remove_request(req); nfs_list_add_request(req, &data->pages); |
1da177e4c Linux-2.6.12-rc2 |
339 |
*pages++ = req->wb_page; |
1da177e4c Linux-2.6.12-rc2 |
340 341 |
} req = nfs_list_entry(data->pages.next); |
6e4efd568 NFS: Clean up nfs... |
342 |
nfs_read_rpcsetup(req, data, desc->pg_count, 0); |
275acaafd NFS: Clean up: sp... |
343 |
list_add(&data->list, res); |
50828d7e6 NFS: Cache rpc_op... |
344 |
desc->pg_rpc_callops = &nfs_read_full_ops; |
bae724ef9 NFSv4.1: shift pn... |
345 |
out: |
dbae4c73f NFS: Ensure that ... |
346 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
347 |
} |
493292ddc NFS: Move the pnf... |
348 349 350 351 352 353 354 355 |
int nfs_generic_pagein(struct nfs_pageio_descriptor *desc, struct list_head *head) { if (desc->pg_bsize < PAGE_CACHE_SIZE) return nfs_pagein_multi(desc, head); return nfs_pagein_one(desc, head); } static int nfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) |
1751c3638 NFS: Cleanup of t... |
356 |
{ |
275acaafd NFS: Clean up: sp... |
357 358 |
LIST_HEAD(head); int ret; |
493292ddc NFS: Move the pnf... |
359 |
ret = nfs_generic_pagein(desc, &head); |
50828d7e6 NFS: Cache rpc_op... |
360 |
if (ret == 0) |
493292ddc NFS: Move the pnf... |
361 |
ret = nfs_do_multiple_reads(&head, desc->pg_rpc_callops); |
275acaafd NFS: Clean up: sp... |
362 |
return ret; |
1751c3638 NFS: Cleanup of t... |
363 |
} |
1751c3638 NFS: Cleanup of t... |
364 365 366 367 368 |
static const struct nfs_pageio_ops nfs_pageio_read_ops = { .pg_test = nfs_generic_pg_test, .pg_doio = nfs_generic_pg_readpages, }; |
1da177e4c Linux-2.6.12-rc2 |
369 |
/* |
0b6713014 NFS: Fix asynchro... |
370 371 372 373 374 375 |
* 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... |
376 377 |
dprintk("NFS: %s: %5u, (status %d) ", __func__, task->tk_pid, |
0b6713014 NFS: Fix asynchro... |
378 379 380 381 382 383 384 385 386 |
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... |
387 |
set_bit(NFS_INO_STALE, &NFS_I(data->inode)->flags); |
0b6713014 NFS: Fix asynchro... |
388 389 |
nfs_mark_for_revalidate(data->inode); } |
0b6713014 NFS: Fix asynchro... |
390 391 |
return 0; } |
fdd1e74c8 NFS: Ensure that ... |
392 |
static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) |
0b6713014 NFS: Fix asynchro... |
393 394 395 396 397 |
{ struct nfs_readargs *argp = &data->args; struct nfs_readres *resp = &data->res; if (resp->eof || resp->count == argp->count) |
d61e612a7 NFSv41: Clean up ... |
398 |
return; |
0b6713014 NFS: Fix asynchro... |
399 400 401 402 403 |
/* This is a short read! */ nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); /* Has the server at least made some progress? */ if (resp->count == 0) |
d61e612a7 NFSv41: Clean up ... |
404 |
return; |
0b6713014 NFS: Fix asynchro... |
405 406 |
/* Yes, so retry the read at the end of the data */ |
cbdabc7f8 NFSv4.1: filelayo... |
407 |
data->mds_offset += resp->count; |
0b6713014 NFS: Fix asynchro... |
408 409 410 |
argp->offset += resp->count; argp->pgbase += resp->count; argp->count -= resp->count; |
d00c5d438 NFS: Get rid of n... |
411 |
rpc_restart_call_prepare(task); |
0b6713014 NFS: Fix asynchro... |
412 413 414 |
} /* |
1da177e4c Linux-2.6.12-rc2 |
415 416 |
* Handle a read reply that fills part of a page. */ |
ec06c096e NFS: Cleanup of N... |
417 |
static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) |
1da177e4c Linux-2.6.12-rc2 |
418 |
{ |
ec06c096e NFS: Cleanup of N... |
419 |
struct nfs_read_data *data = calldata; |
1da177e4c Linux-2.6.12-rc2 |
420 |
|
ec06c096e NFS: Cleanup of N... |
421 422 |
if (nfs_readpage_result(task, data) != 0) return; |
fdd1e74c8 NFS: Ensure that ... |
423 424 |
if (task->tk_status < 0) return; |
0b6713014 NFS: Fix asynchro... |
425 |
|
fdd1e74c8 NFS: Ensure that ... |
426 427 428 429 430 431 432 433 434 435 436 437 |
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) |
fba730050 NFS: Don't rely o... |
438 |
set_bit(PG_PARTIAL_READ_FAILED, &req->wb_flags); |
fdd1e74c8 NFS: Ensure that ... |
439 |
|
1da177e4c Linux-2.6.12-rc2 |
440 |
if (atomic_dec_and_test(&req->wb_complete)) { |
fba730050 NFS: Don't rely o... |
441 |
if (!test_bit(PG_PARTIAL_READ_FAILED, &req->wb_flags)) |
1da177e4c Linux-2.6.12-rc2 |
442 443 444 |
SetPageUptodate(page); nfs_readpage_release(req); } |
fdd1e74c8 NFS: Ensure that ... |
445 |
nfs_readdata_release(calldata); |
1da177e4c Linux-2.6.12-rc2 |
446 |
} |
f11c88af2 nfs41: read seque... |
447 448 449 450 |
#if defined(CONFIG_NFS_V4_1) void nfs_read_prepare(struct rpc_task *task, void *calldata) { struct nfs_read_data *data = calldata; |
035168ab3 NFSv4.1: Make nfs... |
451 |
if (nfs4_setup_sequence(NFS_SERVER(data->inode), |
f11c88af2 nfs41: read seque... |
452 453 454 455 456 457 |
&data->args.seq_args, &data->res.seq_res, 0, task)) return; rpc_call_start(task); } #endif /* CONFIG_NFS_V4_1 */ |
ec06c096e NFS: Cleanup of N... |
458 |
static const struct rpc_call_ops nfs_read_partial_ops = { |
f11c88af2 nfs41: read seque... |
459 460 461 |
#if defined(CONFIG_NFS_V4_1) .rpc_call_prepare = nfs_read_prepare, #endif /* CONFIG_NFS_V4_1 */ |
ec06c096e NFS: Cleanup of N... |
462 |
.rpc_call_done = nfs_readpage_result_partial, |
fdd1e74c8 NFS: Ensure that ... |
463 |
.rpc_release = nfs_readpage_release_partial, |
ec06c096e NFS: Cleanup of N... |
464 |
}; |
1de3fc12e NFS: Clean up and... |
465 466 467 468 469 |
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... |
470 471 |
if (data->res.eof) count = data->args.count; |
1de3fc12e NFS: Clean up and... |
472 473 474 475 476 477 478 |
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... |
479 480 481 482 |
if (count == 0) return; /* Was this a short read? */ if (data->res.eof || data->res.count == data->args.count) |
1de3fc12e NFS: Clean up and... |
483 484 |
SetPageUptodate(*pages); } |
1da177e4c Linux-2.6.12-rc2 |
485 486 487 488 |
/* * 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... |
489 |
static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) |
1da177e4c Linux-2.6.12-rc2 |
490 |
{ |
ec06c096e NFS: Cleanup of N... |
491 |
struct nfs_read_data *data = calldata; |
1da177e4c Linux-2.6.12-rc2 |
492 |
|
0b6713014 NFS: Fix asynchro... |
493 494 |
if (nfs_readpage_result(task, data) != 0) return; |
fdd1e74c8 NFS: Ensure that ... |
495 496 |
if (task->tk_status < 0) return; |
1de3fc12e NFS: Clean up and... |
497 |
/* |
0b6713014 NFS: Fix asynchro... |
498 |
* Note: nfs_readpage_retry may change the values of |
1de3fc12e NFS: Clean up and... |
499 |
* data->args. In the multi-page case, we therefore need |
0b6713014 NFS: Fix asynchro... |
500 501 |
* to ensure that we call nfs_readpage_set_pages_uptodate() * first. |
1de3fc12e NFS: Clean up and... |
502 |
*/ |
fdd1e74c8 NFS: Ensure that ... |
503 504 505 506 507 508 509 510 |
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 |
511 512 |
while (!list_empty(&data->pages)) { struct nfs_page *req = nfs_list_entry(data->pages.next); |
1da177e4c Linux-2.6.12-rc2 |
513 |
|
1de3fc12e NFS: Clean up and... |
514 |
nfs_list_remove_request(req); |
62e4a7698 NFS: Revert pnfs ... |
515 |
nfs_readpage_release(req); |
1da177e4c Linux-2.6.12-rc2 |
516 |
} |
fdd1e74c8 NFS: Ensure that ... |
517 |
nfs_readdata_release(calldata); |
1da177e4c Linux-2.6.12-rc2 |
518 |
} |
ec06c096e NFS: Cleanup of N... |
519 |
static const struct rpc_call_ops nfs_read_full_ops = { |
f11c88af2 nfs41: read seque... |
520 521 522 |
#if defined(CONFIG_NFS_V4_1) .rpc_call_prepare = nfs_read_prepare, #endif /* CONFIG_NFS_V4_1 */ |
ec06c096e NFS: Cleanup of N... |
523 |
.rpc_call_done = nfs_readpage_result_full, |
fdd1e74c8 NFS: Ensure that ... |
524 |
.rpc_release = nfs_readpage_release_full, |
ec06c096e NFS: Cleanup of N... |
525 |
}; |
1da177e4c Linux-2.6.12-rc2 |
526 |
/* |
1da177e4c Linux-2.6.12-rc2 |
527 528 529 530 531 532 533 534 535 536 537 538 539 540 |
* 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... |
541 542 |
nfs_inc_stats(inode, NFSIOS_VFSREADPAGE); nfs_add_stats(inode, NFSIOS_READPAGES, 1); |
1da177e4c Linux-2.6.12-rc2 |
543 544 545 546 547 548 549 550 551 |
/* * 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... |
552 553 554 |
goto out_unlock; if (PageUptodate(page)) goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
555 |
|
5f004cf2a NFS: Make read() ... |
556 557 |
error = -ESTALE; if (NFS_STALE(inode)) |
de05a0cc2 NFS: Minor read o... |
558 |
goto out_unlock; |
5f004cf2a NFS: Make read() ... |
559 |
|
1da177e4c Linux-2.6.12-rc2 |
560 |
if (file == NULL) { |
cf1308ff7 NFS: Fix missing ... |
561 |
error = -EBADF; |
d530838bf NFSv4: Fix proble... |
562 |
ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
1da177e4c Linux-2.6.12-rc2 |
563 |
if (ctx == NULL) |
de05a0cc2 NFS: Minor read o... |
564 |
goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
565 |
} else |
cd3758e37 NFS: Replace file... |
566 |
ctx = get_nfs_open_context(nfs_file_open_context(file)); |
1da177e4c Linux-2.6.12-rc2 |
567 |
|
9a9fc1c03 NFS: Read pages f... |
568 569 570 571 572 |
if (!IS_SYNC(inode)) { error = nfs_readpage_from_fscache(ctx, inode, page); if (error == 0) goto out; } |
8e0969f04 NFS: Remove nfs_r... |
573 |
error = nfs_readpage_async(ctx, inode, page); |
9a9fc1c03 NFS: Read pages f... |
574 |
out: |
1da177e4c Linux-2.6.12-rc2 |
575 576 |
put_nfs_open_context(ctx); return error; |
de05a0cc2 NFS: Minor read o... |
577 |
out_unlock: |
1da177e4c Linux-2.6.12-rc2 |
578 579 580 581 582 |
unlock_page(page); return error; } struct nfs_readdesc { |
8b09bee30 NFS: Cleanup for ... |
583 |
struct nfs_pageio_descriptor *pgio; |
1da177e4c Linux-2.6.12-rc2 |
584 585 586 587 588 589 590 591 592 593 |
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... |
594 |
int error; |
49a70f278 NFS: Cleanup: add... |
595 |
len = nfs_page_length(page); |
1da177e4c Linux-2.6.12-rc2 |
596 597 |
if (len == 0) return nfs_return_empty_page(page); |
de05a0cc2 NFS: Minor read o... |
598 |
|
1da177e4c Linux-2.6.12-rc2 |
599 |
new = nfs_create_request(desc->ctx, inode, page, 0, len); |
de05a0cc2 NFS: Minor read o... |
600 601 |
if (IS_ERR(new)) goto out_error; |
1da177e4c Linux-2.6.12-rc2 |
602 |
if (len < PAGE_CACHE_SIZE) |
eebd2aa35 Pagecache zeroing... |
603 |
zero_user_segment(page, len, PAGE_CACHE_SIZE); |
f8512ad0d nfs: don't ignore... |
604 605 606 607 |
if (!nfs_pageio_add_request(desc->pgio, new)) { error = desc->pgio->pg_error; goto out_unlock; } |
1da177e4c Linux-2.6.12-rc2 |
608 |
return 0; |
de05a0cc2 NFS: Minor read o... |
609 610 |
out_error: error = PTR_ERR(new); |
de05a0cc2 NFS: Minor read o... |
611 612 613 |
out_unlock: unlock_page(page); return error; |
1da177e4c Linux-2.6.12-rc2 |
614 615 616 617 618 |
} int nfs_readpages(struct file *filp, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { |
8b09bee30 NFS: Cleanup for ... |
619 |
struct nfs_pageio_descriptor pgio; |
1da177e4c Linux-2.6.12-rc2 |
620 |
struct nfs_readdesc desc = { |
8b09bee30 NFS: Cleanup for ... |
621 |
.pgio = &pgio, |
1da177e4c Linux-2.6.12-rc2 |
622 623 |
}; struct inode *inode = mapping->host; |
8b09bee30 NFS: Cleanup for ... |
624 |
unsigned long npages; |
5f004cf2a NFS: Make read() ... |
625 |
int ret = -ESTALE; |
1da177e4c Linux-2.6.12-rc2 |
626 627 628 629 630 631 |
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... |
632 |
nfs_inc_stats(inode, NFSIOS_VFSREADPAGES); |
1da177e4c Linux-2.6.12-rc2 |
633 |
|
5f004cf2a NFS: Make read() ... |
634 635 |
if (NFS_STALE(inode)) goto out; |
1da177e4c Linux-2.6.12-rc2 |
636 |
if (filp == NULL) { |
d530838bf NFSv4: Fix proble... |
637 |
desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); |
1da177e4c Linux-2.6.12-rc2 |
638 639 640 |
if (desc.ctx == NULL) return -EBADF; } else |
cd3758e37 NFS: Replace file... |
641 |
desc.ctx = get_nfs_open_context(nfs_file_open_context(filp)); |
9a9fc1c03 NFS: Read pages f... |
642 643 644 645 646 647 648 649 |
/* attempt to read as many of the pages as possible from the cache * - this returns -ENOBUFS immediately if the cookie is negative */ ret = nfs_readpages_from_fscache(desc.ctx, inode, mapping, pages, &nr_pages); if (ret == 0) goto read_complete; /* all pages were read */ |
1751c3638 NFS: Cleanup of t... |
650 |
nfs_pageio_init_read(&pgio, inode); |
8b09bee30 NFS: Cleanup for ... |
651 |
|
1da177e4c Linux-2.6.12-rc2 |
652 |
ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); |
8b09bee30 NFS: Cleanup for ... |
653 654 655 656 |
nfs_pageio_complete(&pgio); npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; nfs_add_stats(inode, NFSIOS_READPAGES, npages); |
9a9fc1c03 NFS: Read pages f... |
657 |
read_complete: |
1da177e4c Linux-2.6.12-rc2 |
658 |
put_nfs_open_context(desc.ctx); |
5f004cf2a NFS: Make read() ... |
659 |
out: |
1da177e4c Linux-2.6.12-rc2 |
660 661 |
return ret; } |
f7b422b17 NFS: Split fs/nfs... |
662 |
int __init nfs_init_readpagecache(void) |
1da177e4c Linux-2.6.12-rc2 |
663 664 665 666 |
{ nfs_rdata_cachep = kmem_cache_create("nfs_read_data", sizeof(struct nfs_read_data), 0, SLAB_HWCACHE_ALIGN, |
20c2df83d mm: Remove slab d... |
667 |
NULL); |
1da177e4c Linux-2.6.12-rc2 |
668 669 |
if (nfs_rdata_cachep == NULL) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
670 671 |
return 0; } |
266bee886 [PATCH] fix stati... |
672 |
void nfs_destroy_readpagecache(void) |
1da177e4c Linux-2.6.12-rc2 |
673 |
{ |
1a1d92c10 [PATCH] Really ig... |
674 |
kmem_cache_destroy(nfs_rdata_cachep); |
1da177e4c Linux-2.6.12-rc2 |
675 |
} |