diff options
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r-- | fs/nfs/read.c | 127 |
1 files changed, 81 insertions, 46 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index aedcaa7f291f..7cded2b12a05 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -18,19 +18,20 @@ | |||
18 | #include <linux/sunrpc/clnt.h> | 18 | #include <linux/sunrpc/clnt.h> |
19 | #include <linux/nfs_fs.h> | 19 | #include <linux/nfs_fs.h> |
20 | #include <linux/nfs_page.h> | 20 | #include <linux/nfs_page.h> |
21 | #include <linux/module.h> | ||
21 | 22 | ||
22 | #include <asm/system.h> | 23 | #include <asm/system.h> |
24 | #include "pnfs.h" | ||
23 | 25 | ||
24 | #include "nfs4_fs.h" | 26 | #include "nfs4_fs.h" |
25 | #include "internal.h" | 27 | #include "internal.h" |
26 | #include "iostat.h" | 28 | #include "iostat.h" |
27 | #include "fscache.h" | 29 | #include "fscache.h" |
28 | #include "pnfs.h" | ||
29 | 30 | ||
30 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 31 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
31 | 32 | ||
32 | static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int); | 33 | static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc); |
33 | static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int); | 34 | static int nfs_pagein_one(struct nfs_pageio_descriptor *desc); |
34 | static const struct rpc_call_ops nfs_read_partial_ops; | 35 | static const struct rpc_call_ops nfs_read_partial_ops; |
35 | static const struct rpc_call_ops nfs_read_full_ops; | 36 | static const struct rpc_call_ops nfs_read_full_ops; |
36 | 37 | ||
@@ -69,6 +70,7 @@ void nfs_readdata_free(struct nfs_read_data *p) | |||
69 | 70 | ||
70 | static void nfs_readdata_release(struct nfs_read_data *rdata) | 71 | static void nfs_readdata_release(struct nfs_read_data *rdata) |
71 | { | 72 | { |
73 | put_lseg(rdata->lseg); | ||
72 | put_nfs_open_context(rdata->args.context); | 74 | put_nfs_open_context(rdata->args.context); |
73 | nfs_readdata_free(rdata); | 75 | nfs_readdata_free(rdata); |
74 | } | 76 | } |
@@ -114,14 +116,13 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data) | |||
114 | int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | 116 | int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, |
115 | struct page *page) | 117 | struct page *page) |
116 | { | 118 | { |
117 | LIST_HEAD(one_request); | ||
118 | struct nfs_page *new; | 119 | struct nfs_page *new; |
119 | unsigned int len; | 120 | unsigned int len; |
121 | struct nfs_pageio_descriptor pgio; | ||
120 | 122 | ||
121 | len = nfs_page_length(page); | 123 | len = nfs_page_length(page); |
122 | if (len == 0) | 124 | if (len == 0) |
123 | return nfs_return_empty_page(page); | 125 | return nfs_return_empty_page(page); |
124 | pnfs_update_layout(inode, ctx, IOMODE_READ); | ||
125 | new = nfs_create_request(ctx, inode, page, 0, len); | 126 | new = nfs_create_request(ctx, inode, page, 0, len); |
126 | if (IS_ERR(new)) { | 127 | if (IS_ERR(new)) { |
127 | unlock_page(page); | 128 | unlock_page(page); |
@@ -130,11 +131,14 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
130 | if (len < PAGE_CACHE_SIZE) | 131 | if (len < PAGE_CACHE_SIZE) |
131 | zero_user_segment(page, len, PAGE_CACHE_SIZE); | 132 | zero_user_segment(page, len, PAGE_CACHE_SIZE); |
132 | 133 | ||
133 | nfs_list_add_request(new, &one_request); | 134 | nfs_pageio_init(&pgio, inode, NULL, 0, 0); |
135 | nfs_list_add_request(new, &pgio.pg_list); | ||
136 | pgio.pg_count = len; | ||
137 | |||
134 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) | 138 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) |
135 | nfs_pagein_multi(inode, &one_request, 1, len, 0); | 139 | nfs_pagein_multi(&pgio); |
136 | else | 140 | else |
137 | nfs_pagein_one(inode, &one_request, 1, len, 0); | 141 | nfs_pagein_one(&pgio); |
138 | return 0; | 142 | return 0; |
139 | } | 143 | } |
140 | 144 | ||
@@ -155,24 +159,20 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
155 | nfs_release_request(req); | 159 | nfs_release_request(req); |
156 | } | 160 | } |
157 | 161 | ||
158 | /* | 162 | int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt, |
159 | * Set up the NFS read request struct | 163 | const struct rpc_call_ops *call_ops) |
160 | */ | ||
161 | static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | ||
162 | const struct rpc_call_ops *call_ops, | ||
163 | unsigned int count, unsigned int offset) | ||
164 | { | 164 | { |
165 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 165 | struct inode *inode = data->inode; |
166 | int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; | 166 | int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; |
167 | struct rpc_task *task; | 167 | struct rpc_task *task; |
168 | struct rpc_message msg = { | 168 | struct rpc_message msg = { |
169 | .rpc_argp = &data->args, | 169 | .rpc_argp = &data->args, |
170 | .rpc_resp = &data->res, | 170 | .rpc_resp = &data->res, |
171 | .rpc_cred = req->wb_context->cred, | 171 | .rpc_cred = data->cred, |
172 | }; | 172 | }; |
173 | struct rpc_task_setup task_setup_data = { | 173 | struct rpc_task_setup task_setup_data = { |
174 | .task = &data->task, | 174 | .task = &data->task, |
175 | .rpc_client = NFS_CLIENT(inode), | 175 | .rpc_client = clnt, |
176 | .rpc_message = &msg, | 176 | .rpc_message = &msg, |
177 | .callback_ops = call_ops, | 177 | .callback_ops = call_ops, |
178 | .callback_data = data, | 178 | .callback_data = data, |
@@ -180,9 +180,39 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
180 | .flags = RPC_TASK_ASYNC | swap_flags, | 180 | .flags = RPC_TASK_ASYNC | swap_flags, |
181 | }; | 181 | }; |
182 | 182 | ||
183 | /* Set up the initial task struct. */ | ||
184 | NFS_PROTO(inode)->read_setup(data, &msg); | ||
185 | |||
186 | dprintk("NFS: %5u initiated read call (req %s/%lld, %u bytes @ " | ||
187 | "offset %llu)\n", | ||
188 | data->task.tk_pid, | ||
189 | inode->i_sb->s_id, | ||
190 | (long long)NFS_FILEID(inode), | ||
191 | data->args.count, | ||
192 | (unsigned long long)data->args.offset); | ||
193 | |||
194 | task = rpc_run_task(&task_setup_data); | ||
195 | if (IS_ERR(task)) | ||
196 | return PTR_ERR(task); | ||
197 | rpc_put_task(task); | ||
198 | return 0; | ||
199 | } | ||
200 | EXPORT_SYMBOL_GPL(nfs_initiate_read); | ||
201 | |||
202 | /* | ||
203 | * Set up the NFS read request struct | ||
204 | */ | ||
205 | static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | ||
206 | const struct rpc_call_ops *call_ops, | ||
207 | unsigned int count, unsigned int offset, | ||
208 | struct pnfs_layout_segment *lseg) | ||
209 | { | ||
210 | struct inode *inode = req->wb_context->path.dentry->d_inode; | ||
211 | |||
183 | data->req = req; | 212 | data->req = req; |
184 | data->inode = inode; | 213 | data->inode = inode; |
185 | data->cred = msg.rpc_cred; | 214 | data->cred = req->wb_context->cred; |
215 | data->lseg = get_lseg(lseg); | ||
186 | 216 | ||
187 | data->args.fh = NFS_FH(inode); | 217 | data->args.fh = NFS_FH(inode); |
188 | data->args.offset = req_offset(req) + offset; | 218 | data->args.offset = req_offset(req) + offset; |
@@ -197,21 +227,11 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
197 | data->res.eof = 0; | 227 | data->res.eof = 0; |
198 | nfs_fattr_init(&data->fattr); | 228 | nfs_fattr_init(&data->fattr); |
199 | 229 | ||
200 | /* Set up the initial task struct. */ | 230 | if (data->lseg && |
201 | NFS_PROTO(inode)->read_setup(data, &msg); | 231 | (pnfs_try_to_read_data(data, call_ops) == PNFS_ATTEMPTED)) |
202 | 232 | return 0; | |
203 | dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n", | ||
204 | data->task.tk_pid, | ||
205 | inode->i_sb->s_id, | ||
206 | (long long)NFS_FILEID(inode), | ||
207 | count, | ||
208 | (unsigned long long)data->args.offset); | ||
209 | 233 | ||
210 | task = rpc_run_task(&task_setup_data); | 234 | return nfs_initiate_read(data, NFS_CLIENT(inode), call_ops); |
211 | if (IS_ERR(task)) | ||
212 | return PTR_ERR(task); | ||
213 | rpc_put_task(task); | ||
214 | return 0; | ||
215 | } | 235 | } |
216 | 236 | ||
217 | static void | 237 | static void |
@@ -240,20 +260,21 @@ nfs_async_read_error(struct list_head *head) | |||
240 | * won't see the new data until our attribute cache is updated. This is more | 260 | * won't see the new data until our attribute cache is updated. This is more |
241 | * or less conventional NFS client behavior. | 261 | * or less conventional NFS client behavior. |
242 | */ | 262 | */ |
243 | static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) | 263 | static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc) |
244 | { | 264 | { |
245 | struct nfs_page *req = nfs_list_entry(head->next); | 265 | struct nfs_page *req = nfs_list_entry(desc->pg_list.next); |
246 | struct page *page = req->wb_page; | 266 | struct page *page = req->wb_page; |
247 | struct nfs_read_data *data; | 267 | struct nfs_read_data *data; |
248 | size_t rsize = NFS_SERVER(inode)->rsize, nbytes; | 268 | size_t rsize = NFS_SERVER(desc->pg_inode)->rsize, nbytes; |
249 | unsigned int offset; | 269 | unsigned int offset; |
250 | int requests = 0; | 270 | int requests = 0; |
251 | int ret = 0; | 271 | int ret = 0; |
272 | struct pnfs_layout_segment *lseg; | ||
252 | LIST_HEAD(list); | 273 | LIST_HEAD(list); |
253 | 274 | ||
254 | nfs_list_remove_request(req); | 275 | nfs_list_remove_request(req); |
255 | 276 | ||
256 | nbytes = count; | 277 | nbytes = desc->pg_count; |
257 | do { | 278 | do { |
258 | size_t len = min(nbytes,rsize); | 279 | size_t len = min(nbytes,rsize); |
259 | 280 | ||
@@ -266,9 +287,11 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
266 | } while(nbytes != 0); | 287 | } while(nbytes != 0); |
267 | atomic_set(&req->wb_complete, requests); | 288 | atomic_set(&req->wb_complete, requests); |
268 | 289 | ||
290 | BUG_ON(desc->pg_lseg != NULL); | ||
291 | lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ); | ||
269 | ClearPageError(page); | 292 | ClearPageError(page); |
270 | offset = 0; | 293 | offset = 0; |
271 | nbytes = count; | 294 | nbytes = desc->pg_count; |
272 | do { | 295 | do { |
273 | int ret2; | 296 | int ret2; |
274 | 297 | ||
@@ -280,12 +303,14 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
280 | if (nbytes < rsize) | 303 | if (nbytes < rsize) |
281 | rsize = nbytes; | 304 | rsize = nbytes; |
282 | ret2 = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, | 305 | ret2 = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
283 | rsize, offset); | 306 | rsize, offset, lseg); |
284 | if (ret == 0) | 307 | if (ret == 0) |
285 | ret = ret2; | 308 | ret = ret2; |
286 | offset += rsize; | 309 | offset += rsize; |
287 | nbytes -= rsize; | 310 | nbytes -= rsize; |
288 | } while (nbytes != 0); | 311 | } while (nbytes != 0); |
312 | put_lseg(lseg); | ||
313 | desc->pg_lseg = NULL; | ||
289 | 314 | ||
290 | return ret; | 315 | return ret; |
291 | 316 | ||
@@ -300,16 +325,21 @@ out_bad: | |||
300 | return -ENOMEM; | 325 | return -ENOMEM; |
301 | } | 326 | } |
302 | 327 | ||
303 | static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) | 328 | static int nfs_pagein_one(struct nfs_pageio_descriptor *desc) |
304 | { | 329 | { |
305 | struct nfs_page *req; | 330 | struct nfs_page *req; |
306 | struct page **pages; | 331 | struct page **pages; |
307 | struct nfs_read_data *data; | 332 | struct nfs_read_data *data; |
333 | struct list_head *head = &desc->pg_list; | ||
334 | struct pnfs_layout_segment *lseg = desc->pg_lseg; | ||
308 | int ret = -ENOMEM; | 335 | int ret = -ENOMEM; |
309 | 336 | ||
310 | data = nfs_readdata_alloc(npages); | 337 | data = nfs_readdata_alloc(nfs_page_array_len(desc->pg_base, |
311 | if (!data) | 338 | desc->pg_count)); |
312 | goto out_bad; | 339 | if (!data) { |
340 | nfs_async_read_error(head); | ||
341 | goto out; | ||
342 | } | ||
313 | 343 | ||
314 | pages = data->pagevec; | 344 | pages = data->pagevec; |
315 | while (!list_empty(head)) { | 345 | while (!list_empty(head)) { |
@@ -320,10 +350,14 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned | |||
320 | *pages++ = req->wb_page; | 350 | *pages++ = req->wb_page; |
321 | } | 351 | } |
322 | req = nfs_list_entry(data->pages.next); | 352 | req = nfs_list_entry(data->pages.next); |
353 | if ((!lseg) && list_is_singular(&data->pages)) | ||
354 | lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_READ); | ||
323 | 355 | ||
324 | return nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); | 356 | ret = nfs_read_rpcsetup(req, data, &nfs_read_full_ops, desc->pg_count, |
325 | out_bad: | 357 | 0, lseg); |
326 | nfs_async_read_error(head); | 358 | out: |
359 | put_lseg(lseg); | ||
360 | desc->pg_lseg = NULL; | ||
327 | return ret; | 361 | return ret; |
328 | } | 362 | } |
329 | 363 | ||
@@ -366,6 +400,7 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data | |||
366 | return; | 400 | return; |
367 | 401 | ||
368 | /* Yes, so retry the read at the end of the data */ | 402 | /* Yes, so retry the read at the end of the data */ |
403 | data->mds_offset += resp->count; | ||
369 | argp->offset += resp->count; | 404 | argp->offset += resp->count; |
370 | argp->pgbase += resp->count; | 405 | argp->pgbase += resp->count; |
371 | argp->count -= resp->count; | 406 | argp->count -= resp->count; |
@@ -625,7 +660,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, | |||
625 | if (ret == 0) | 660 | if (ret == 0) |
626 | goto read_complete; /* all pages were read */ | 661 | goto read_complete; /* all pages were read */ |
627 | 662 | ||
628 | pnfs_update_layout(inode, desc.ctx, IOMODE_READ); | 663 | pnfs_pageio_init_read(&pgio, inode); |
629 | if (rsize < PAGE_CACHE_SIZE) | 664 | if (rsize < PAGE_CACHE_SIZE) |
630 | nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); | 665 | nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); |
631 | else | 666 | else |