aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/read.c
diff options
context:
space:
mode:
authorFred Isaman <iisaman@netapp.com>2012-04-20 14:47:44 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-04-27 14:10:37 -0400
commitcd841605f7a721878d8a2d1362484723d8abf569 (patch)
treeb5c37db575cd545a183577249909e042fe38d646 /fs/nfs/read.c
parentb5542849764aa56fd3f05c0041195b637b9d2ac2 (diff)
NFS: create common nfs_pgio_header for both read and write
In order to avoid duplicating all the data in nfs_read_data whenever we split it up into multiple RPC calls (either due to a short read result or due to rsize < PAGE_SIZE), we split out the bits that are the same per RPC call into a separate "header" structure. The goal this patch moves towards is to have a single header refcounted by several rpc_data structures. Thus, want to always refer from rpc_data to the header, and not the other way. This patch comes close to that ideal, but the directio code currently needs some special casing, isolated in the nfs_direct_[read_write]hdr_release() functions. This will be dealt with in a future patch. Signed-off-by: Fred Isaman <iisaman@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r--fs/nfs/read.c89
1 files changed, 51 insertions, 38 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 4ddba670634..d6d46823d9e 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -35,19 +35,24 @@ static const struct rpc_call_ops nfs_read_full_ops;
35 35
36static struct kmem_cache *nfs_rdata_cachep; 36static struct kmem_cache *nfs_rdata_cachep;
37 37
38struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) 38struct nfs_read_header *nfs_readhdr_alloc(unsigned int pagecount)
39{ 39{
40 struct nfs_read_data *p; 40 struct nfs_read_header *p;
41 41
42 p = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL); 42 p = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL);
43 if (p) { 43 if (p) {
44 INIT_LIST_HEAD(&p->pages); 44 struct nfs_pgio_header *hdr = &p->header;
45 p->npages = pagecount; 45 struct nfs_read_data *data = &p->rpc_data;
46 if (pagecount <= ARRAY_SIZE(p->page_array)) 46
47 p->pagevec = p->page_array; 47 INIT_LIST_HEAD(&hdr->pages);
48 INIT_LIST_HEAD(&data->list);
49 data->npages = pagecount;
50 data->header = hdr;
51 if (pagecount <= ARRAY_SIZE(data->page_array))
52 data->pagevec = data->page_array;
48 else { 53 else {
49 p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL); 54 data->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL);
50 if (!p->pagevec) { 55 if (!data->pagevec) {
51 kmem_cache_free(nfs_rdata_cachep, p); 56 kmem_cache_free(nfs_rdata_cachep, p);
52 p = NULL; 57 p = NULL;
53 } 58 }
@@ -56,17 +61,19 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
56 return p; 61 return p;
57} 62}
58 63
59void nfs_readdata_free(struct nfs_read_data *p) 64void nfs_readhdr_free(struct nfs_pgio_header *hdr)
60{ 65{
61 if (p && (p->pagevec != &p->page_array[0])) 66 struct nfs_read_header *rhdr = container_of(hdr, struct nfs_read_header, header);
62 kfree(p->pagevec); 67
63 kmem_cache_free(nfs_rdata_cachep, p); 68 kmem_cache_free(nfs_rdata_cachep, rhdr);
64} 69}
65 70
66void nfs_readdata_release(struct nfs_read_data *rdata) 71void nfs_readdata_release(struct nfs_read_data *rdata)
67{ 72{
68 put_nfs_open_context(rdata->args.context); 73 put_nfs_open_context(rdata->args.context);
69 nfs_readdata_free(rdata); 74 if (rdata->pagevec != rdata->page_array)
75 kfree(rdata->pagevec);
76 nfs_readhdr_free(rdata->header);
70} 77}
71 78
72static 79static
@@ -173,13 +180,13 @@ int nfs_initiate_read(struct rpc_clnt *clnt,
173 struct nfs_read_data *data, 180 struct nfs_read_data *data,
174 const struct rpc_call_ops *call_ops) 181 const struct rpc_call_ops *call_ops)
175{ 182{
176 struct inode *inode = data->inode; 183 struct inode *inode = data->header->inode;
177 int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; 184 int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0;
178 struct rpc_task *task; 185 struct rpc_task *task;
179 struct rpc_message msg = { 186 struct rpc_message msg = {
180 .rpc_argp = &data->args, 187 .rpc_argp = &data->args,
181 .rpc_resp = &data->res, 188 .rpc_resp = &data->res,
182 .rpc_cred = data->cred, 189 .rpc_cred = data->header->cred,
183 }; 190 };
184 struct rpc_task_setup task_setup_data = { 191 struct rpc_task_setup task_setup_data = {
185 .task = &data->task, 192 .task = &data->task,
@@ -216,11 +223,11 @@ EXPORT_SYMBOL_GPL(nfs_initiate_read);
216static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, 223static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
217 unsigned int count, unsigned int offset) 224 unsigned int count, unsigned int offset)
218{ 225{
219 struct inode *inode = req->wb_context->dentry->d_inode; 226 struct inode *inode = data->header->inode;
220 227
221 data->req = req; 228 data->header->req = req;
222 data->inode = inode; 229 data->header->inode = inode;
223 data->cred = req->wb_context->cred; 230 data->header->cred = req->wb_context->cred;
224 231
225 data->args.fh = NFS_FH(inode); 232 data->args.fh = NFS_FH(inode);
226 data->args.offset = req_offset(req) + offset; 233 data->args.offset = req_offset(req) + offset;
@@ -239,7 +246,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
239static int nfs_do_read(struct nfs_read_data *data, 246static int nfs_do_read(struct nfs_read_data *data,
240 const struct rpc_call_ops *call_ops) 247 const struct rpc_call_ops *call_ops)
241{ 248{
242 struct inode *inode = data->args.context->dentry->d_inode; 249 struct inode *inode = data->header->inode;
243 250
244 return nfs_initiate_read(NFS_CLIENT(inode), data, call_ops); 251 return nfs_initiate_read(NFS_CLIENT(inode), data, call_ops);
245} 252}
@@ -293,6 +300,7 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head
293{ 300{
294 struct nfs_page *req = nfs_list_entry(desc->pg_list.next); 301 struct nfs_page *req = nfs_list_entry(desc->pg_list.next);
295 struct page *page = req->wb_page; 302 struct page *page = req->wb_page;
303 struct nfs_read_header *rhdr;
296 struct nfs_read_data *data; 304 struct nfs_read_data *data;
297 size_t rsize = desc->pg_bsize, nbytes; 305 size_t rsize = desc->pg_bsize, nbytes;
298 unsigned int offset; 306 unsigned int offset;
@@ -306,9 +314,10 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head
306 do { 314 do {
307 size_t len = min(nbytes,rsize); 315 size_t len = min(nbytes,rsize);
308 316
309 data = nfs_readdata_alloc(1); 317 rhdr = nfs_readhdr_alloc(1);
310 if (!data) 318 if (!rhdr)
311 goto out_bad; 319 goto out_bad;
320 data = &rhdr->rpc_data;
312 data->pagevec[0] = page; 321 data->pagevec[0] = page;
313 nfs_read_rpcsetup(req, data, len, offset); 322 nfs_read_rpcsetup(req, data, len, offset);
314 list_add(&data->list, res); 323 list_add(&data->list, res);
@@ -333,26 +342,28 @@ static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, struct list_head *
333{ 342{
334 struct nfs_page *req; 343 struct nfs_page *req;
335 struct page **pages; 344 struct page **pages;
345 struct nfs_read_header *rhdr;
336 struct nfs_read_data *data; 346 struct nfs_read_data *data;
337 struct list_head *head = &desc->pg_list; 347 struct list_head *head = &desc->pg_list;
338 int ret = 0; 348 int ret = 0;
339 349
340 data = nfs_readdata_alloc(nfs_page_array_len(desc->pg_base, 350 rhdr = nfs_readhdr_alloc(nfs_page_array_len(desc->pg_base,
341 desc->pg_count)); 351 desc->pg_count));
342 if (!data) { 352 if (!rhdr) {
343 nfs_async_read_error(head); 353 nfs_async_read_error(head);
344 ret = -ENOMEM; 354 ret = -ENOMEM;
345 goto out; 355 goto out;
346 } 356 }
347 357
358 data = &rhdr->rpc_data;
348 pages = data->pagevec; 359 pages = data->pagevec;
349 while (!list_empty(head)) { 360 while (!list_empty(head)) {
350 req = nfs_list_entry(head->next); 361 req = nfs_list_entry(head->next);
351 nfs_list_remove_request(req); 362 nfs_list_remove_request(req);
352 nfs_list_add_request(req, &data->pages); 363 nfs_list_add_request(req, &rhdr->header.pages);
353 *pages++ = req->wb_page; 364 *pages++ = req->wb_page;
354 } 365 }
355 req = nfs_list_entry(data->pages.next); 366 req = nfs_list_entry(rhdr->header.pages.next);
356 367
357 nfs_read_rpcsetup(req, data, desc->pg_count, 0); 368 nfs_read_rpcsetup(req, data, desc->pg_count, 0);
358 list_add(&data->list, res); 369 list_add(&data->list, res);
@@ -390,20 +401,21 @@ static const struct nfs_pageio_ops nfs_pageio_read_ops = {
390 */ 401 */
391int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) 402int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data)
392{ 403{
404 struct inode *inode = data->header->inode;
393 int status; 405 int status;
394 406
395 dprintk("NFS: %s: %5u, (status %d)\n", __func__, task->tk_pid, 407 dprintk("NFS: %s: %5u, (status %d)\n", __func__, task->tk_pid,
396 task->tk_status); 408 task->tk_status);
397 409
398 status = NFS_PROTO(data->inode)->read_done(task, data); 410 status = NFS_PROTO(inode)->read_done(task, data);
399 if (status != 0) 411 if (status != 0)
400 return status; 412 return status;
401 413
402 nfs_add_stats(data->inode, NFSIOS_SERVERREADBYTES, data->res.count); 414 nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, data->res.count);
403 415
404 if (task->tk_status == -ESTALE) { 416 if (task->tk_status == -ESTALE) {
405 set_bit(NFS_INO_STALE, &NFS_I(data->inode)->flags); 417 set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
406 nfs_mark_for_revalidate(data->inode); 418 nfs_mark_for_revalidate(inode);
407 } 419 }
408 return 0; 420 return 0;
409} 421}
@@ -417,7 +429,7 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data
417 return; 429 return;
418 430
419 /* This is a short read! */ 431 /* This is a short read! */
420 nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); 432 nfs_inc_stats(data->header->inode, NFSIOS_SHORTREAD);
421 /* Has the server at least made some progress? */ 433 /* Has the server at least made some progress? */
422 if (resp->count == 0) 434 if (resp->count == 0)
423 return; 435 return;
@@ -449,7 +461,7 @@ static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata)
449static void nfs_readpage_release_partial(void *calldata) 461static void nfs_readpage_release_partial(void *calldata)
450{ 462{
451 struct nfs_read_data *data = calldata; 463 struct nfs_read_data *data = calldata;
452 struct nfs_page *req = data->req; 464 struct nfs_page *req = data->header->req;
453 struct page *page = req->wb_page; 465 struct page *page = req->wb_page;
454 int status = data->task.tk_status; 466 int status = data->task.tk_status;
455 467
@@ -461,13 +473,13 @@ static void nfs_readpage_release_partial(void *calldata)
461 SetPageUptodate(page); 473 SetPageUptodate(page);
462 nfs_readpage_release(req); 474 nfs_readpage_release(req);
463 } 475 }
464 nfs_readdata_release(calldata); 476 nfs_readdata_release(data);
465} 477}
466 478
467void nfs_read_prepare(struct rpc_task *task, void *calldata) 479void nfs_read_prepare(struct rpc_task *task, void *calldata)
468{ 480{
469 struct nfs_read_data *data = calldata; 481 struct nfs_read_data *data = calldata;
470 NFS_PROTO(data->inode)->read_rpc_prepare(task, data); 482 NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data);
471} 483}
472 484
473static const struct rpc_call_ops nfs_read_partial_ops = { 485static const struct rpc_call_ops nfs_read_partial_ops = {
@@ -524,9 +536,10 @@ static void nfs_readpage_result_full(struct rpc_task *task, void *calldata)
524static void nfs_readpage_release_full(void *calldata) 536static void nfs_readpage_release_full(void *calldata)
525{ 537{
526 struct nfs_read_data *data = calldata; 538 struct nfs_read_data *data = calldata;
539 struct nfs_pgio_header *hdr = data->header;
527 540
528 while (!list_empty(&data->pages)) { 541 while (!list_empty(&hdr->pages)) {
529 struct nfs_page *req = nfs_list_entry(data->pages.next); 542 struct nfs_page *req = nfs_list_entry(hdr->pages.next);
530 543
531 nfs_list_remove_request(req); 544 nfs_list_remove_request(req);
532 nfs_readpage_release(req); 545 nfs_readpage_release(req);
@@ -685,7 +698,7 @@ out:
685int __init nfs_init_readpagecache(void) 698int __init nfs_init_readpagecache(void)
686{ 699{
687 nfs_rdata_cachep = kmem_cache_create("nfs_read_data", 700 nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
688 sizeof(struct nfs_read_data), 701 sizeof(struct nfs_read_header),
689 0, SLAB_HWCACHE_ALIGN, 702 0, SLAB_HWCACHE_ALIGN,
690 NULL); 703 NULL);
691 if (nfs_rdata_cachep == NULL) 704 if (nfs_rdata_cachep == NULL)