[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>

authored by Christoph Hellwig and committed by Nathan Scott 9260dc6b 1defeac9

+52 -37
+52 -37
fs/xfs/linux-2.6/xfs_aops.c
··· 624 624 int all_bh) 625 625 { 626 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 629 unsigned int type; 629 630 int bbits = inode->i_blkbits; 630 631 int len, page_dirty; 631 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 635 if (page->index != tindex) 635 636 goto fail; ··· 643 642 if (!xfs_is_delayed_page(page, (*ioendp)->io_type)) 644 643 goto fail_unlock_page; 645 644 646 - end_offset = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)); 647 - 648 645 /* 649 646 * page_dirty is initially a count of buffers on the page before 650 647 * EOF and is decrememted as we move each into a cleanable state. 648 + * 649 + * Derivation: 650 + * 651 + * End offset is the highest offset that this page should represent. 652 + * If we are on the last page, (end_offset & (PAGE_CACHE_SIZE - 1)) 653 + * will evaluate non-zero and be less than PAGE_CACHE_SIZE and 654 + * hence give us the correct page_dirty count. On any other page, 655 + * it will be zero and in that case we need page_dirty to be the 656 + * count of buffers on the page. 651 657 */ 658 + end_offset = min_t(unsigned long long, 659 + (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT, 660 + i_size_read(inode)); 661 + 652 662 len = 1 << inode->i_blkbits; 653 - end_offset = max(end_offset, PAGE_CACHE_SIZE); 654 - end_offset = roundup(end_offset, len); 655 - page_dirty = end_offset / len; 663 + p_offset = min_t(unsigned long, end_offset & (PAGE_CACHE_SIZE - 1), 664 + PAGE_CACHE_SIZE); 665 + p_offset = p_offset ? roundup(p_offset, len) : PAGE_CACHE_SIZE; 666 + page_dirty = p_offset / len; 656 667 657 668 p_offset = 0; 658 669 bh = head = page_buffers(page); 659 670 do { 660 - if (p_offset >= end_offset) 671 + if (offset >= end_offset) 661 672 break; 662 673 if (!buffer_uptodate(bh)) 663 674 uptodate = 0; ··· 678 665 continue; 679 666 } 680 667 681 - if (buffer_unwritten(bh)) 682 - type = IOMAP_UNWRITTEN; 683 - else if (buffer_delay(bh)) 684 - type = IOMAP_DELAY; 685 - else { 686 - type = 0; 687 - if (!(buffer_mapped(bh) && all_bh && startio)) { 668 + if (buffer_unwritten(bh) || buffer_delay(bh)) { 669 + if (buffer_unwritten(bh)) 670 + type = IOMAP_UNWRITTEN; 671 + else 672 + type = IOMAP_DELAY; 673 + 674 + if (!xfs_iomap_valid(mp, offset)) { 688 675 done = 1; 689 - } else if (startio) { 676 + continue; 677 + } 678 + 679 + ASSERT(!(mp->iomap_flags & IOMAP_HOLE)); 680 + ASSERT(!(mp->iomap_flags & IOMAP_DELAY)); 681 + 682 + xfs_map_at_offset(bh, offset, bbits, mp); 683 + if (startio) { 684 + xfs_add_to_ioend(inode, bh, p_offset, 685 + type, ioendp, done); 686 + } else { 687 + set_buffer_dirty(bh); 688 + unlock_buffer(bh); 689 + mark_buffer_dirty(bh); 690 + } 691 + page_dirty--; 692 + count++; 693 + } else { 694 + type = 0; 695 + if (buffer_mapped(bh) && all_bh && startio) { 690 696 lock_buffer(bh); 691 697 xfs_add_to_ioend(inode, bh, p_offset, 692 698 type, ioendp, done); 693 699 count++; 694 700 page_dirty--; 701 + } else { 702 + done = 1; 695 703 } 696 - continue; 697 704 } 698 - 699 - if (!xfs_iomap_valid(mp, f_offset + p_offset)) { 700 - done = 1; 701 - continue; 702 - } 703 - ASSERT(!(mp->iomap_flags & IOMAP_HOLE)); 704 - ASSERT(!(mp->iomap_flags & IOMAP_DELAY)); 705 - 706 - xfs_map_at_offset(bh, f_offset + p_offset, bbits, mp); 707 - if (startio) { 708 - xfs_add_to_ioend(inode, bh, p_offset, 709 - type, ioendp, done); 710 - count++; 711 - } else { 712 - set_buffer_dirty(bh); 713 - unlock_buffer(bh); 714 - mark_buffer_dirty(bh); 715 - } 716 - page_dirty--; 717 - } while (p_offset += len, (bh = bh->b_this_page) != head); 705 + } while (offset += len, p_offset += len, 706 + (bh = bh->b_this_page) != head); 718 707 719 708 if (uptodate && bh == head) 720 709 SetPageUptodate(page);