diff options
| author | Christoph Hellwig <hch@sgi.com> | 2006-01-11 04:48:47 -0500 |
|---|---|---|
| committer | Nathan Scott <nathans@sgi.com> | 2006-01-11 04:48:47 -0500 |
| commit | 9260dc6b2ee011f728bae50edce11022567be096 (patch) | |
| tree | e9422f63e7d15077feeaa6cc8e0a6a394e06cb85 | |
| parent | 1defeac9d4fffa3eabc4fba887e8ff5b1da7f361 (diff) | |
[XFS] various fixes for xfs_convert_page fix various bogusities in
handling offets From David Chinner and Christoph Hellwig
SGI-PV: 947118
SGI-Modid: xfs-linux-melb:xfs-kern:203826a
Signed-off-by: Christoph Hellwig <hch@sgi.com>
Signed-off-by: Nathan Scott <nathans@sgi.com>
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 89 |
1 files changed, 52 insertions, 37 deletions
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index b306e25f0f07..64c909e5c1e5 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
| @@ -624,12 +624,13 @@ xfs_convert_page( | |||
| 624 | int all_bh) | 624 | int all_bh) |
| 625 | { | 625 | { |
| 626 | struct buffer_head *bh, *head; | 626 | struct buffer_head *bh, *head; |
| 627 | unsigned long p_offset, end_offset; | 627 | xfs_off_t end_offset; |
| 628 | unsigned long p_offset; | ||
| 628 | unsigned int type; | 629 | unsigned int type; |
| 629 | int bbits = inode->i_blkbits; | 630 | int bbits = inode->i_blkbits; |
| 630 | int len, page_dirty; | 631 | int len, page_dirty; |
| 631 | int count = 0, done = 0, uptodate = 1; | 632 | int count = 0, done = 0, uptodate = 1; |
| 632 | xfs_off_t f_offset = page_offset(page); | 633 | xfs_off_t offset = page_offset(page); |
| 633 | 634 | ||
| 634 | if (page->index != tindex) | 635 | if (page->index != tindex) |
| 635 | goto fail; | 636 | goto fail; |
| @@ -642,21 +643,33 @@ xfs_convert_page( | |||
| 642 | if (!xfs_is_delayed_page(page, (*ioendp)->io_type)) | 643 | if (!xfs_is_delayed_page(page, (*ioendp)->io_type)) |
| 643 | goto fail_unlock_page; | 644 | goto fail_unlock_page; |
| 644 | 645 | ||
| 645 | end_offset = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)); | ||
| 646 | |||
| 647 | /* | 646 | /* |
| 648 | * page_dirty is initially a count of buffers on the page before | 647 | * page_dirty is initially a count of buffers on the page before |
| 649 | * EOF and is decrememted as we move each into a cleanable state. | 648 | * EOF and is decrememted as we move each into a cleanable state. |
| 649 | * | ||
| 650 | * Derivation: | ||
| 651 | * | ||
| 652 | * End offset is the highest offset that this page should represent. | ||
| 653 | * If we are on the last page, (end_offset & (PAGE_CACHE_SIZE - 1)) | ||
| 654 | * will evaluate non-zero and be less than PAGE_CACHE_SIZE and | ||
| 655 | * hence give us the correct page_dirty count. On any other page, | ||
| 656 | * it will be zero and in that case we need page_dirty to be the | ||
| 657 | * count of buffers on the page. | ||
| 650 | */ | 658 | */ |
| 659 | end_offset = min_t(unsigned long long, | ||
| 660 | (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT, | ||
| 661 | i_size_read(inode)); | ||
| 662 | |||
| 651 | len = 1 << inode->i_blkbits; | 663 | len = 1 << inode->i_blkbits; |
| 652 | end_offset = max(end_offset, PAGE_CACHE_SIZE); | 664 | p_offset = min_t(unsigned long, end_offset & (PAGE_CACHE_SIZE - 1), |
| 653 | end_offset = roundup(end_offset, len); | 665 | PAGE_CACHE_SIZE); |
| 654 | page_dirty = end_offset / len; | 666 | p_offset = p_offset ? roundup(p_offset, len) : PAGE_CACHE_SIZE; |
| 667 | page_dirty = p_offset / len; | ||
| 655 | 668 | ||
| 656 | p_offset = 0; | 669 | p_offset = 0; |
| 657 | bh = head = page_buffers(page); | 670 | bh = head = page_buffers(page); |
| 658 | do { | 671 | do { |
| 659 | if (p_offset >= end_offset) | 672 | if (offset >= end_offset) |
| 660 | break; | 673 | break; |
| 661 | if (!buffer_uptodate(bh)) | 674 | if (!buffer_uptodate(bh)) |
| 662 | uptodate = 0; | 675 | uptodate = 0; |
| @@ -665,43 +678,45 @@ xfs_convert_page( | |||
| 665 | continue; | 678 | continue; |
| 666 | } | 679 | } |
| 667 | 680 | ||
| 668 | if (buffer_unwritten(bh)) | 681 | if (buffer_unwritten(bh) || buffer_delay(bh)) { |
| 669 | type = IOMAP_UNWRITTEN; | 682 | if (buffer_unwritten(bh)) |
| 670 | else if (buffer_delay(bh)) | 683 | type = IOMAP_UNWRITTEN; |
| 671 | type = IOMAP_DELAY; | 684 | else |
| 672 | else { | 685 | type = IOMAP_DELAY; |
| 673 | type = 0; | 686 | |
| 674 | if (!(buffer_mapped(bh) && all_bh && startio)) { | 687 | if (!xfs_iomap_valid(mp, offset)) { |
| 675 | done = 1; | 688 | done = 1; |
| 676 | } else if (startio) { | 689 | continue; |
| 690 | } | ||
| 691 | |||
| 692 | ASSERT(!(mp->iomap_flags & IOMAP_HOLE)); | ||
| 693 | ASSERT(!(mp->iomap_flags & IOMAP_DELAY)); | ||
| 694 | |||
| 695 | xfs_map_at_offset(bh, offset, bbits, mp); | ||
| 696 | if (startio) { | ||
| 697 | xfs_add_to_ioend(inode, bh, p_offset, | ||
| 698 | type, ioendp, done); | ||
| 699 | } else { | ||
| 700 | set_buffer_dirty(bh); | ||
| 701 | unlock_buffer(bh); | ||
| 702 | mark_buffer_dirty(bh); | ||
| 703 | } | ||
| 704 | page_dirty--; | ||
| 705 | count++; | ||
| 706 | } else { | ||
| 707 | type = 0; | ||
| 708 | if (buffer_mapped(bh) && all_bh && startio) { | ||
| 677 | lock_buffer(bh); | 709 | lock_buffer(bh); |
| 678 | xfs_add_to_ioend(inode, bh, p_offset, | 710 | xfs_add_to_ioend(inode, bh, p_offset, |
| 679 | type, ioendp, done); | 711 | type, ioendp, done); |
| 680 | count++; | 712 | count++; |
| 681 | page_dirty--; | 713 | page_dirty--; |
| 714 | } else { | ||
| 715 | done = 1; | ||
| 682 | } | 716 | } |
| 683 | continue; | ||
| 684 | } | ||
| 685 | |||
| 686 | if (!xfs_iomap_valid(mp, f_offset + p_offset)) { | ||
| 687 | done = 1; | ||
| 688 | continue; | ||
| 689 | } | ||
| 690 | ASSERT(!(mp->iomap_flags & IOMAP_HOLE)); | ||
| 691 | ASSERT(!(mp->iomap_flags & IOMAP_DELAY)); | ||
| 692 | |||
| 693 | xfs_map_at_offset(bh, f_offset + p_offset, bbits, mp); | ||
| 694 | if (startio) { | ||
| 695 | xfs_add_to_ioend(inode, bh, p_offset, | ||
| 696 | type, ioendp, done); | ||
| 697 | count++; | ||
| 698 | } else { | ||
| 699 | set_buffer_dirty(bh); | ||
| 700 | unlock_buffer(bh); | ||
| 701 | mark_buffer_dirty(bh); | ||
| 702 | } | 717 | } |
| 703 | page_dirty--; | 718 | } while (offset += len, p_offset += len, |
| 704 | } while (p_offset += len, (bh = bh->b_this_page) != head); | 719 | (bh = bh->b_this_page) != head); |
| 705 | 720 | ||
| 706 | if (uptodate && bh == head) | 721 | if (uptodate && bh == head) |
| 707 | SetPageUptodate(page); | 722 | SetPageUptodate(page); |
