diff options
author | Nathan Scott <nathans@sgi.com> | 2005-05-05 16:33:20 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@melbourne.sgi.com> | 2005-05-05 16:33:20 -0400 |
commit | 24e17b5fb99d4d1b47fe0847a3a801e36d431ff6 (patch) | |
tree | 0ac181b6ddc64a04fe55aa79efceecc6e4d90451 /fs/xfs/linux-2.6 | |
parent | 775bf6c99a4ebde13bdb8dfa528ed241483b49ef (diff) |
[XFS] Use the right offset when ensuring a delayed allocate conversion has covered the offset originally requested. Can cause data corruption when multiple processes are performing writeout on different areas of the same file. Quite difficult to hit though.
SGI Modid: xfs-linux:xfs-kern:22377a
Signed-off-by: Nathan Scott <nathans@sgi.com>
Signed-off-by: Christoph Hellwig <hch@sgi.com>
.
Diffstat (limited to 'fs/xfs/linux-2.6')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 68 |
1 files changed, 39 insertions, 29 deletions
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 1edd3b694332..9278e9aba9ba 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -558,7 +558,8 @@ xfs_submit_page( | |||
558 | int i; | 558 | int i; |
559 | 559 | ||
560 | BUG_ON(PageWriteback(page)); | 560 | BUG_ON(PageWriteback(page)); |
561 | set_page_writeback(page); | 561 | if (bh_count) |
562 | set_page_writeback(page); | ||
562 | if (clear_dirty) | 563 | if (clear_dirty) |
563 | clear_page_dirty(page); | 564 | clear_page_dirty(page); |
564 | unlock_page(page); | 565 | unlock_page(page); |
@@ -578,9 +579,6 @@ xfs_submit_page( | |||
578 | 579 | ||
579 | if (probed_page && clear_dirty) | 580 | if (probed_page && clear_dirty) |
580 | wbc->nr_to_write--; /* Wrote an "extra" page */ | 581 | wbc->nr_to_write--; /* Wrote an "extra" page */ |
581 | } else { | ||
582 | end_page_writeback(page); | ||
583 | wbc->pages_skipped++; /* We didn't write this page */ | ||
584 | } | 582 | } |
585 | } | 583 | } |
586 | 584 | ||
@@ -602,21 +600,26 @@ xfs_convert_page( | |||
602 | { | 600 | { |
603 | struct buffer_head *bh_arr[MAX_BUF_PER_PAGE], *bh, *head; | 601 | struct buffer_head *bh_arr[MAX_BUF_PER_PAGE], *bh, *head; |
604 | xfs_iomap_t *mp = iomapp, *tmp; | 602 | xfs_iomap_t *mp = iomapp, *tmp; |
605 | unsigned long end, offset; | 603 | unsigned long offset, end_offset; |
606 | pgoff_t end_index; | 604 | int index = 0; |
607 | int i = 0, index = 0; | ||
608 | int bbits = inode->i_blkbits; | 605 | int bbits = inode->i_blkbits; |
606 | int len, page_dirty; | ||
609 | 607 | ||
610 | end_index = i_size_read(inode) >> PAGE_CACHE_SHIFT; | 608 | end_offset = (i_size_read(inode) & (PAGE_CACHE_SIZE - 1)); |
611 | if (page->index < end_index) { | 609 | |
612 | end = PAGE_CACHE_SIZE; | 610 | /* |
613 | } else { | 611 | * page_dirty is initially a count of buffers on the page before |
614 | end = i_size_read(inode) & (PAGE_CACHE_SIZE-1); | 612 | * EOF and is decrememted as we move each into a cleanable state. |
615 | } | 613 | */ |
614 | len = 1 << inode->i_blkbits; | ||
615 | end_offset = max(end_offset, PAGE_CACHE_SIZE); | ||
616 | end_offset = roundup(end_offset, len); | ||
617 | page_dirty = end_offset / len; | ||
618 | |||
619 | offset = 0; | ||
616 | bh = head = page_buffers(page); | 620 | bh = head = page_buffers(page); |
617 | do { | 621 | do { |
618 | offset = i << bbits; | 622 | if (offset >= end_offset) |
619 | if (offset >= end) | ||
620 | break; | 623 | break; |
621 | if (!(PageUptodate(page) || buffer_uptodate(bh))) | 624 | if (!(PageUptodate(page) || buffer_uptodate(bh))) |
622 | continue; | 625 | continue; |
@@ -625,6 +628,7 @@ xfs_convert_page( | |||
625 | if (startio) { | 628 | if (startio) { |
626 | lock_buffer(bh); | 629 | lock_buffer(bh); |
627 | bh_arr[index++] = bh; | 630 | bh_arr[index++] = bh; |
631 | page_dirty--; | ||
628 | } | 632 | } |
629 | continue; | 633 | continue; |
630 | } | 634 | } |
@@ -657,10 +661,11 @@ xfs_convert_page( | |||
657 | unlock_buffer(bh); | 661 | unlock_buffer(bh); |
658 | mark_buffer_dirty(bh); | 662 | mark_buffer_dirty(bh); |
659 | } | 663 | } |
660 | } while (i++, (bh = bh->b_this_page) != head); | 664 | page_dirty--; |
665 | } while (offset += len, (bh = bh->b_this_page) != head); | ||
661 | 666 | ||
662 | if (startio) { | 667 | if (startio && index) { |
663 | xfs_submit_page(page, wbc, bh_arr, index, 1, index == i); | 668 | xfs_submit_page(page, wbc, bh_arr, index, 1, !page_dirty); |
664 | } else { | 669 | } else { |
665 | unlock_page(page); | 670 | unlock_page(page); |
666 | } | 671 | } |
@@ -743,19 +748,22 @@ xfs_page_state_convert( | |||
743 | } | 748 | } |
744 | } | 749 | } |
745 | 750 | ||
746 | offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | ||
747 | end_offset = min_t(unsigned long long, | 751 | end_offset = min_t(unsigned long long, |
748 | offset + PAGE_CACHE_SIZE, i_size_read(inode)); | 752 | (loff_t)(page->index + 1) << PAGE_CACHE_SHIFT, offset); |
749 | 753 | offset = (loff_t)page->index << PAGE_CACHE_SHIFT; | |
750 | bh = head = page_buffers(page); | ||
751 | iomp = NULL; | ||
752 | 754 | ||
753 | /* | 755 | /* |
754 | * page_dirty is initially a count of buffers on the page and | 756 | * page_dirty is initially a count of buffers on the page before |
755 | * is decrememted as we move each into a cleanable state. | 757 | * EOF and is decrememted as we move each into a cleanable state. |
756 | */ | 758 | */ |
757 | len = bh->b_size; | 759 | len = 1 << inode->i_blkbits; |
758 | page_dirty = PAGE_CACHE_SIZE / len; | 760 | p_offset = max(p_offset, PAGE_CACHE_SIZE); |
761 | p_offset = roundup(p_offset, len); | ||
762 | page_dirty = p_offset / len; | ||
763 | |||
764 | iomp = NULL; | ||
765 | p_offset = 0; | ||
766 | bh = head = page_buffers(page); | ||
759 | 767 | ||
760 | do { | 768 | do { |
761 | if (offset >= end_offset) | 769 | if (offset >= end_offset) |
@@ -877,8 +885,10 @@ xfs_page_state_convert( | |||
877 | if (uptodate && bh == head) | 885 | if (uptodate && bh == head) |
878 | SetPageUptodate(page); | 886 | SetPageUptodate(page); |
879 | 887 | ||
880 | if (startio) | 888 | if (startio) { |
881 | xfs_submit_page(page, wbc, bh_arr, cnt, 0, 1); | 889 | WARN_ON(page_dirty); |
890 | xfs_submit_page(page, wbc, bh_arr, cnt, 0, !page_dirty); | ||
891 | } | ||
882 | 892 | ||
883 | if (iomp) { | 893 | if (iomp) { |
884 | offset = (iomp->iomap_offset + iomp->iomap_bsize - 1) >> | 894 | offset = (iomp->iomap_offset + iomp->iomap_bsize - 1) >> |