diff options
author | Fred Isaman <iisaman@netapp.com> | 2012-04-20 14:47:44 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-04-27 14:10:37 -0400 |
commit | cd841605f7a721878d8a2d1362484723d8abf569 (patch) | |
tree | b5c37db575cd545a183577249909e042fe38d646 /fs/nfs/blocklayout | |
parent | b5542849764aa56fd3f05c0041195b637b9d2ac2 (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/blocklayout')
-rw-r--r-- | fs/nfs/blocklayout/blocklayout.c | 79 |
1 files changed, 43 insertions, 36 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 7f6a23f0244e..7a482517f4c6 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
@@ -187,7 +187,6 @@ static void bl_end_io_read(struct bio *bio, int err) | |||
187 | struct parallel_io *par = bio->bi_private; | 187 | struct parallel_io *par = bio->bi_private; |
188 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); | 188 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); |
189 | struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; | 189 | struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; |
190 | struct nfs_read_data *rdata = (struct nfs_read_data *)par->data; | ||
191 | 190 | ||
192 | do { | 191 | do { |
193 | struct page *page = bvec->bv_page; | 192 | struct page *page = bvec->bv_page; |
@@ -198,9 +197,12 @@ static void bl_end_io_read(struct bio *bio, int err) | |||
198 | SetPageUptodate(page); | 197 | SetPageUptodate(page); |
199 | } while (bvec >= bio->bi_io_vec); | 198 | } while (bvec >= bio->bi_io_vec); |
200 | if (!uptodate) { | 199 | if (!uptodate) { |
201 | if (!rdata->pnfs_error) | 200 | struct nfs_read_data *rdata = par->data; |
202 | rdata->pnfs_error = -EIO; | 201 | struct nfs_pgio_header *header = rdata->header; |
203 | pnfs_set_lo_fail(rdata->lseg); | 202 | |
203 | if (!header->pnfs_error) | ||
204 | header->pnfs_error = -EIO; | ||
205 | pnfs_set_lo_fail(header->lseg); | ||
204 | } | 206 | } |
205 | bio_put(bio); | 207 | bio_put(bio); |
206 | put_parallel(par); | 208 | put_parallel(par); |
@@ -221,7 +223,7 @@ bl_end_par_io_read(void *data, int unused) | |||
221 | { | 223 | { |
222 | struct nfs_read_data *rdata = data; | 224 | struct nfs_read_data *rdata = data; |
223 | 225 | ||
224 | rdata->task.tk_status = rdata->pnfs_error; | 226 | rdata->task.tk_status = rdata->header->pnfs_error; |
225 | INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup); | 227 | INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup); |
226 | schedule_work(&rdata->task.u.tk_work); | 228 | schedule_work(&rdata->task.u.tk_work); |
227 | } | 229 | } |
@@ -229,6 +231,7 @@ bl_end_par_io_read(void *data, int unused) | |||
229 | static enum pnfs_try_status | 231 | static enum pnfs_try_status |
230 | bl_read_pagelist(struct nfs_read_data *rdata) | 232 | bl_read_pagelist(struct nfs_read_data *rdata) |
231 | { | 233 | { |
234 | struct nfs_pgio_header *header = rdata->header; | ||
232 | int i, hole; | 235 | int i, hole; |
233 | struct bio *bio = NULL; | 236 | struct bio *bio = NULL; |
234 | struct pnfs_block_extent *be = NULL, *cow_read = NULL; | 237 | struct pnfs_block_extent *be = NULL, *cow_read = NULL; |
@@ -256,10 +259,10 @@ bl_read_pagelist(struct nfs_read_data *rdata) | |||
256 | bl_put_extent(cow_read); | 259 | bl_put_extent(cow_read); |
257 | bio = bl_submit_bio(READ, bio); | 260 | bio = bl_submit_bio(READ, bio); |
258 | /* Get the next one */ | 261 | /* Get the next one */ |
259 | be = bl_find_get_extent(BLK_LSEG2EXT(rdata->lseg), | 262 | be = bl_find_get_extent(BLK_LSEG2EXT(header->lseg), |
260 | isect, &cow_read); | 263 | isect, &cow_read); |
261 | if (!be) { | 264 | if (!be) { |
262 | rdata->pnfs_error = -EIO; | 265 | header->pnfs_error = -EIO; |
263 | goto out; | 266 | goto out; |
264 | } | 267 | } |
265 | extent_length = be->be_length - | 268 | extent_length = be->be_length - |
@@ -286,7 +289,7 @@ bl_read_pagelist(struct nfs_read_data *rdata) | |||
286 | isect, pages[i], be_read, | 289 | isect, pages[i], be_read, |
287 | bl_end_io_read, par); | 290 | bl_end_io_read, par); |
288 | if (IS_ERR(bio)) { | 291 | if (IS_ERR(bio)) { |
289 | rdata->pnfs_error = PTR_ERR(bio); | 292 | header->pnfs_error = PTR_ERR(bio); |
290 | bio = NULL; | 293 | bio = NULL; |
291 | goto out; | 294 | goto out; |
292 | } | 295 | } |
@@ -294,9 +297,9 @@ bl_read_pagelist(struct nfs_read_data *rdata) | |||
294 | isect += PAGE_CACHE_SECTORS; | 297 | isect += PAGE_CACHE_SECTORS; |
295 | extent_length -= PAGE_CACHE_SECTORS; | 298 | extent_length -= PAGE_CACHE_SECTORS; |
296 | } | 299 | } |
297 | if ((isect << SECTOR_SHIFT) >= rdata->inode->i_size) { | 300 | if ((isect << SECTOR_SHIFT) >= header->inode->i_size) { |
298 | rdata->res.eof = 1; | 301 | rdata->res.eof = 1; |
299 | rdata->res.count = rdata->inode->i_size - f_offset; | 302 | rdata->res.count = header->inode->i_size - f_offset; |
300 | } else { | 303 | } else { |
301 | rdata->res.count = (isect << SECTOR_SHIFT) - f_offset; | 304 | rdata->res.count = (isect << SECTOR_SHIFT) - f_offset; |
302 | } | 305 | } |
@@ -345,7 +348,6 @@ static void bl_end_io_write_zero(struct bio *bio, int err) | |||
345 | struct parallel_io *par = bio->bi_private; | 348 | struct parallel_io *par = bio->bi_private; |
346 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); | 349 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); |
347 | struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; | 350 | struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; |
348 | struct nfs_write_data *wdata = (struct nfs_write_data *)par->data; | ||
349 | 351 | ||
350 | do { | 352 | do { |
351 | struct page *page = bvec->bv_page; | 353 | struct page *page = bvec->bv_page; |
@@ -358,9 +360,12 @@ static void bl_end_io_write_zero(struct bio *bio, int err) | |||
358 | } while (bvec >= bio->bi_io_vec); | 360 | } while (bvec >= bio->bi_io_vec); |
359 | 361 | ||
360 | if (unlikely(!uptodate)) { | 362 | if (unlikely(!uptodate)) { |
361 | if (!wdata->pnfs_error) | 363 | struct nfs_write_data *data = par->data; |
362 | wdata->pnfs_error = -EIO; | 364 | struct nfs_pgio_header *header = data->header; |
363 | pnfs_set_lo_fail(wdata->lseg); | 365 | |
366 | if (!header->pnfs_error) | ||
367 | header->pnfs_error = -EIO; | ||
368 | pnfs_set_lo_fail(header->lseg); | ||
364 | } | 369 | } |
365 | bio_put(bio); | 370 | bio_put(bio); |
366 | put_parallel(par); | 371 | put_parallel(par); |
@@ -370,12 +375,13 @@ static void bl_end_io_write(struct bio *bio, int err) | |||
370 | { | 375 | { |
371 | struct parallel_io *par = bio->bi_private; | 376 | struct parallel_io *par = bio->bi_private; |
372 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); | 377 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); |
373 | struct nfs_write_data *wdata = (struct nfs_write_data *)par->data; | 378 | struct nfs_write_data *data = par->data; |
379 | struct nfs_pgio_header *header = data->header; | ||
374 | 380 | ||
375 | if (!uptodate) { | 381 | if (!uptodate) { |
376 | if (!wdata->pnfs_error) | 382 | if (!header->pnfs_error) |
377 | wdata->pnfs_error = -EIO; | 383 | header->pnfs_error = -EIO; |
378 | pnfs_set_lo_fail(wdata->lseg); | 384 | pnfs_set_lo_fail(header->lseg); |
379 | } | 385 | } |
380 | bio_put(bio); | 386 | bio_put(bio); |
381 | put_parallel(par); | 387 | put_parallel(par); |
@@ -391,9 +397,9 @@ static void bl_write_cleanup(struct work_struct *work) | |||
391 | dprintk("%s enter\n", __func__); | 397 | dprintk("%s enter\n", __func__); |
392 | task = container_of(work, struct rpc_task, u.tk_work); | 398 | task = container_of(work, struct rpc_task, u.tk_work); |
393 | wdata = container_of(task, struct nfs_write_data, task); | 399 | wdata = container_of(task, struct nfs_write_data, task); |
394 | if (likely(!wdata->pnfs_error)) { | 400 | if (likely(!wdata->header->pnfs_error)) { |
395 | /* Marks for LAYOUTCOMMIT */ | 401 | /* Marks for LAYOUTCOMMIT */ |
396 | mark_extents_written(BLK_LSEG2EXT(wdata->lseg), | 402 | mark_extents_written(BLK_LSEG2EXT(wdata->header->lseg), |
397 | wdata->args.offset, wdata->args.count); | 403 | wdata->args.offset, wdata->args.count); |
398 | } | 404 | } |
399 | pnfs_ld_write_done(wdata); | 405 | pnfs_ld_write_done(wdata); |
@@ -404,12 +410,12 @@ static void bl_end_par_io_write(void *data, int num_se) | |||
404 | { | 410 | { |
405 | struct nfs_write_data *wdata = data; | 411 | struct nfs_write_data *wdata = data; |
406 | 412 | ||
407 | if (unlikely(wdata->pnfs_error)) { | 413 | if (unlikely(wdata->header->pnfs_error)) { |
408 | bl_free_short_extents(&BLK_LSEG2EXT(wdata->lseg)->bl_inval, | 414 | bl_free_short_extents(&BLK_LSEG2EXT(wdata->header->lseg)->bl_inval, |
409 | num_se); | 415 | num_se); |
410 | } | 416 | } |
411 | 417 | ||
412 | wdata->task.tk_status = wdata->pnfs_error; | 418 | wdata->task.tk_status = wdata->header->pnfs_error; |
413 | wdata->verf.committed = NFS_FILE_SYNC; | 419 | wdata->verf.committed = NFS_FILE_SYNC; |
414 | INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup); | 420 | INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup); |
415 | schedule_work(&wdata->task.u.tk_work); | 421 | schedule_work(&wdata->task.u.tk_work); |
@@ -540,6 +546,7 @@ check_page: | |||
540 | static enum pnfs_try_status | 546 | static enum pnfs_try_status |
541 | bl_write_pagelist(struct nfs_write_data *wdata, int sync) | 547 | bl_write_pagelist(struct nfs_write_data *wdata, int sync) |
542 | { | 548 | { |
549 | struct nfs_pgio_header *header = wdata->header; | ||
543 | int i, ret, npg_zero, pg_index, last = 0; | 550 | int i, ret, npg_zero, pg_index, last = 0; |
544 | struct bio *bio = NULL; | 551 | struct bio *bio = NULL; |
545 | struct pnfs_block_extent *be = NULL, *cow_read = NULL; | 552 | struct pnfs_block_extent *be = NULL, *cow_read = NULL; |
@@ -552,7 +559,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) | |||
552 | pgoff_t index; | 559 | pgoff_t index; |
553 | u64 temp; | 560 | u64 temp; |
554 | int npg_per_block = | 561 | int npg_per_block = |
555 | NFS_SERVER(wdata->inode)->pnfs_blksize >> PAGE_CACHE_SHIFT; | 562 | NFS_SERVER(header->inode)->pnfs_blksize >> PAGE_CACHE_SHIFT; |
556 | 563 | ||
557 | dprintk("%s enter, %Zu@%lld\n", __func__, count, offset); | 564 | dprintk("%s enter, %Zu@%lld\n", __func__, count, offset); |
558 | /* At this point, wdata->pages is a (sequential) list of nfs_pages. | 565 | /* At this point, wdata->pages is a (sequential) list of nfs_pages. |
@@ -566,7 +573,7 @@ bl_write_pagelist(struct nfs_write_data *wdata, int sync) | |||
566 | /* At this point, have to be more careful with error handling */ | 573 | /* At this point, have to be more careful with error handling */ |
567 | 574 | ||
568 | isect = (sector_t) ((offset & (long)PAGE_CACHE_MASK) >> SECTOR_SHIFT); | 575 | isect = (sector_t) ((offset & (long)PAGE_CACHE_MASK) >> SECTOR_SHIFT); |
569 | be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg), isect, &cow_read); | 576 | be = bl_find_get_extent(BLK_LSEG2EXT(header->lseg), isect, &cow_read); |
570 | if (!be || !is_writable(be, isect)) { | 577 | if (!be || !is_writable(be, isect)) { |
571 | dprintk("%s no matching extents!\n", __func__); | 578 | dprintk("%s no matching extents!\n", __func__); |
572 | goto out_mds; | 579 | goto out_mds; |
@@ -597,10 +604,10 @@ fill_invalid_ext: | |||
597 | dprintk("%s zero %dth page: index %lu isect %llu\n", | 604 | dprintk("%s zero %dth page: index %lu isect %llu\n", |
598 | __func__, npg_zero, index, | 605 | __func__, npg_zero, index, |
599 | (unsigned long long)isect); | 606 | (unsigned long long)isect); |
600 | page = bl_find_get_zeroing_page(wdata->inode, index, | 607 | page = bl_find_get_zeroing_page(header->inode, index, |
601 | cow_read); | 608 | cow_read); |
602 | if (unlikely(IS_ERR(page))) { | 609 | if (unlikely(IS_ERR(page))) { |
603 | wdata->pnfs_error = PTR_ERR(page); | 610 | header->pnfs_error = PTR_ERR(page); |
604 | goto out; | 611 | goto out; |
605 | } else if (page == NULL) | 612 | } else if (page == NULL) |
606 | goto next_page; | 613 | goto next_page; |
@@ -612,7 +619,7 @@ fill_invalid_ext: | |||
612 | __func__, ret); | 619 | __func__, ret); |
613 | end_page_writeback(page); | 620 | end_page_writeback(page); |
614 | page_cache_release(page); | 621 | page_cache_release(page); |
615 | wdata->pnfs_error = ret; | 622 | header->pnfs_error = ret; |
616 | goto out; | 623 | goto out; |
617 | } | 624 | } |
618 | if (likely(!bl_push_one_short_extent(be->be_inval))) | 625 | if (likely(!bl_push_one_short_extent(be->be_inval))) |
@@ -620,11 +627,11 @@ fill_invalid_ext: | |||
620 | else { | 627 | else { |
621 | end_page_writeback(page); | 628 | end_page_writeback(page); |
622 | page_cache_release(page); | 629 | page_cache_release(page); |
623 | wdata->pnfs_error = -ENOMEM; | 630 | header->pnfs_error = -ENOMEM; |
624 | goto out; | 631 | goto out; |
625 | } | 632 | } |
626 | /* FIXME: This should be done in bi_end_io */ | 633 | /* FIXME: This should be done in bi_end_io */ |
627 | mark_extents_written(BLK_LSEG2EXT(wdata->lseg), | 634 | mark_extents_written(BLK_LSEG2EXT(header->lseg), |
628 | page->index << PAGE_CACHE_SHIFT, | 635 | page->index << PAGE_CACHE_SHIFT, |
629 | PAGE_CACHE_SIZE); | 636 | PAGE_CACHE_SIZE); |
630 | 637 | ||
@@ -632,7 +639,7 @@ fill_invalid_ext: | |||
632 | isect, page, be, | 639 | isect, page, be, |
633 | bl_end_io_write_zero, par); | 640 | bl_end_io_write_zero, par); |
634 | if (IS_ERR(bio)) { | 641 | if (IS_ERR(bio)) { |
635 | wdata->pnfs_error = PTR_ERR(bio); | 642 | header->pnfs_error = PTR_ERR(bio); |
636 | bio = NULL; | 643 | bio = NULL; |
637 | goto out; | 644 | goto out; |
638 | } | 645 | } |
@@ -653,10 +660,10 @@ next_page: | |||
653 | bl_put_extent(be); | 660 | bl_put_extent(be); |
654 | bio = bl_submit_bio(WRITE, bio); | 661 | bio = bl_submit_bio(WRITE, bio); |
655 | /* Get the next one */ | 662 | /* Get the next one */ |
656 | be = bl_find_get_extent(BLK_LSEG2EXT(wdata->lseg), | 663 | be = bl_find_get_extent(BLK_LSEG2EXT(header->lseg), |
657 | isect, NULL); | 664 | isect, NULL); |
658 | if (!be || !is_writable(be, isect)) { | 665 | if (!be || !is_writable(be, isect)) { |
659 | wdata->pnfs_error = -EINVAL; | 666 | header->pnfs_error = -EINVAL; |
660 | goto out; | 667 | goto out; |
661 | } | 668 | } |
662 | if (be->be_state == PNFS_BLOCK_INVALID_DATA) { | 669 | if (be->be_state == PNFS_BLOCK_INVALID_DATA) { |
@@ -664,7 +671,7 @@ next_page: | |||
664 | be->be_inval))) | 671 | be->be_inval))) |
665 | par->bse_count++; | 672 | par->bse_count++; |
666 | else { | 673 | else { |
667 | wdata->pnfs_error = -ENOMEM; | 674 | header->pnfs_error = -ENOMEM; |
668 | goto out; | 675 | goto out; |
669 | } | 676 | } |
670 | } | 677 | } |
@@ -677,7 +684,7 @@ next_page: | |||
677 | if (unlikely(ret)) { | 684 | if (unlikely(ret)) { |
678 | dprintk("%s bl_mark_sectors_init fail %d\n", | 685 | dprintk("%s bl_mark_sectors_init fail %d\n", |
679 | __func__, ret); | 686 | __func__, ret); |
680 | wdata->pnfs_error = ret; | 687 | header->pnfs_error = ret; |
681 | goto out; | 688 | goto out; |
682 | } | 689 | } |
683 | } | 690 | } |
@@ -685,7 +692,7 @@ next_page: | |||
685 | isect, pages[i], be, | 692 | isect, pages[i], be, |
686 | bl_end_io_write, par); | 693 | bl_end_io_write, par); |
687 | if (IS_ERR(bio)) { | 694 | if (IS_ERR(bio)) { |
688 | wdata->pnfs_error = PTR_ERR(bio); | 695 | header->pnfs_error = PTR_ERR(bio); |
689 | bio = NULL; | 696 | bio = NULL; |
690 | goto out; | 697 | goto out; |
691 | } | 698 | } |