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 | |
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')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 68 | ||||
-rw-r--r-- | fs/xfs/xfs_iomap.c | 20 | ||||
-rw-r--r-- | fs/xfs/xfs_iomap.h | 7 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 7 |
4 files changed, 56 insertions, 46 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) >> |
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 3826e8f0e28a..b291a2b53579 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
@@ -308,7 +308,8 @@ phase2: | |||
308 | break; | 308 | break; |
309 | } | 309 | } |
310 | 310 | ||
311 | error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, &imap, &nimaps); | 311 | error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count, |
312 | &imap, &nimaps); | ||
312 | break; | 313 | break; |
313 | case BMAPI_UNWRITTEN: | 314 | case BMAPI_UNWRITTEN: |
314 | lockmode = 0; | 315 | lockmode = 0; |
@@ -746,6 +747,8 @@ write_map: | |||
746 | int | 747 | int |
747 | xfs_iomap_write_allocate( | 748 | xfs_iomap_write_allocate( |
748 | xfs_inode_t *ip, | 749 | xfs_inode_t *ip, |
750 | loff_t offset, | ||
751 | size_t count, | ||
749 | xfs_bmbt_irec_t *map, | 752 | xfs_bmbt_irec_t *map, |
750 | int *retmap) | 753 | int *retmap) |
751 | { | 754 | { |
@@ -770,9 +773,9 @@ xfs_iomap_write_allocate( | |||
770 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) | 773 | if ((error = XFS_QM_DQATTACH(mp, ip, 0))) |
771 | return XFS_ERROR(error); | 774 | return XFS_ERROR(error); |
772 | 775 | ||
773 | offset_fsb = map->br_startoff; | 776 | offset_fsb = XFS_B_TO_FSBT(mp, offset); |
774 | count_fsb = map->br_blockcount; | 777 | count_fsb = map->br_blockcount; |
775 | map_start_fsb = offset_fsb; | 778 | map_start_fsb = map->br_startoff; |
776 | 779 | ||
777 | XFS_STATS_ADD(xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb)); | 780 | XFS_STATS_ADD(xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb)); |
778 | 781 | ||
@@ -868,9 +871,9 @@ xfs_iomap_write_allocate( | |||
868 | imap[i].br_startoff, | 871 | imap[i].br_startoff, |
869 | imap[i].br_blockcount,imap[i].br_state); | 872 | imap[i].br_blockcount,imap[i].br_state); |
870 | } | 873 | } |
871 | if ((map->br_startoff >= imap[i].br_startoff) && | 874 | if ((offset_fsb >= imap[i].br_startoff) && |
872 | (map->br_startoff < (imap[i].br_startoff + | 875 | (offset_fsb < (imap[i].br_startoff + |
873 | imap[i].br_blockcount))) { | 876 | imap[i].br_blockcount))) { |
874 | *map = imap[i]; | 877 | *map = imap[i]; |
875 | *retmap = 1; | 878 | *retmap = 1; |
876 | XFS_STATS_INC(xs_xstrat_quick); | 879 | XFS_STATS_INC(xs_xstrat_quick); |
@@ -883,9 +886,8 @@ xfs_iomap_write_allocate( | |||
883 | * file, just surrounding data, try again. | 886 | * file, just surrounding data, try again. |
884 | */ | 887 | */ |
885 | nimaps--; | 888 | nimaps--; |
886 | offset_fsb = imap[nimaps].br_startoff + | 889 | map_start_fsb = imap[nimaps].br_startoff + |
887 | imap[nimaps].br_blockcount; | 890 | imap[nimaps].br_blockcount; |
888 | map_start_fsb = offset_fsb; | ||
889 | } | 891 | } |
890 | 892 | ||
891 | trans_cancel: | 893 | trans_cancel: |
diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h index 31c91087cb33..287895a3adc1 100644 --- a/fs/xfs/xfs_iomap.h +++ b/fs/xfs/xfs_iomap.h | |||
@@ -29,9 +29,6 @@ | |||
29 | * | 29 | * |
30 | * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ | 30 | * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ |
31 | */ | 31 | */ |
32 | |||
33 | |||
34 | |||
35 | #ifndef __XFS_IOMAP_H__ | 32 | #ifndef __XFS_IOMAP_H__ |
36 | #define __XFS_IOMAP_H__ | 33 | #define __XFS_IOMAP_H__ |
37 | 34 | ||
@@ -56,7 +53,7 @@ typedef enum { | |||
56 | BMAPI_UNWRITTEN = (1 << 3), /* unwritten extents to real extents */ | 53 | BMAPI_UNWRITTEN = (1 << 3), /* unwritten extents to real extents */ |
57 | /* modifiers */ | 54 | /* modifiers */ |
58 | BMAPI_IGNSTATE = (1 << 4), /* ignore unwritten state on read */ | 55 | BMAPI_IGNSTATE = (1 << 4), /* ignore unwritten state on read */ |
59 | BMAPI_DIRECT = (1 << 5), /* direct instead of buffered write */ | 56 | BMAPI_DIRECT = (1 << 5), /* direct instead of buffered write */ |
60 | BMAPI_MMAP = (1 << 6), /* allocate for mmap write */ | 57 | BMAPI_MMAP = (1 << 6), /* allocate for mmap write */ |
61 | BMAPI_SYNC = (1 << 7), /* sync write to flush delalloc space */ | 58 | BMAPI_SYNC = (1 << 7), /* sync write to flush delalloc space */ |
62 | BMAPI_TRYLOCK = (1 << 8), /* non-blocking request */ | 59 | BMAPI_TRYLOCK = (1 << 8), /* non-blocking request */ |
@@ -100,7 +97,7 @@ extern int xfs_iomap_write_direct(struct xfs_inode *, loff_t, size_t, | |||
100 | int, struct xfs_bmbt_irec *, int *, int); | 97 | int, struct xfs_bmbt_irec *, int *, int); |
101 | extern int xfs_iomap_write_delay(struct xfs_inode *, loff_t, size_t, int, | 98 | extern int xfs_iomap_write_delay(struct xfs_inode *, loff_t, size_t, int, |
102 | struct xfs_bmbt_irec *, int *); | 99 | struct xfs_bmbt_irec *, int *); |
103 | extern int xfs_iomap_write_allocate(struct xfs_inode *, | 100 | extern int xfs_iomap_write_allocate(struct xfs_inode *, loff_t, size_t, |
104 | struct xfs_bmbt_irec *, int *); | 101 | struct xfs_bmbt_irec *, int *); |
105 | extern int xfs_iomap_write_unwritten(struct xfs_inode *, loff_t, size_t); | 102 | extern int xfs_iomap_write_unwritten(struct xfs_inode *, loff_t, size_t); |
106 | 103 | ||
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 1b968471ec8b..8ffb65dc110d 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -216,7 +216,8 @@ typedef int (*xfs_iomap_write_delay_t)( | |||
216 | void *, loff_t, size_t, int, | 216 | void *, loff_t, size_t, int, |
217 | struct xfs_bmbt_irec *, int *); | 217 | struct xfs_bmbt_irec *, int *); |
218 | typedef int (*xfs_iomap_write_allocate_t)( | 218 | typedef int (*xfs_iomap_write_allocate_t)( |
219 | void *, struct xfs_bmbt_irec *, int *); | 219 | void *, loff_t, size_t, |
220 | struct xfs_bmbt_irec *, int *); | ||
220 | typedef int (*xfs_iomap_write_unwritten_t)( | 221 | typedef int (*xfs_iomap_write_unwritten_t)( |
221 | void *, loff_t, size_t); | 222 | void *, loff_t, size_t); |
222 | typedef uint (*xfs_lck_map_shared_t)(void *); | 223 | typedef uint (*xfs_lck_map_shared_t)(void *); |
@@ -258,9 +259,9 @@ typedef struct xfs_ioops { | |||
258 | #define XFS_IOMAP_WRITE_DELAY(mp, io, offset, count, flags, mval, nmap) \ | 259 | #define XFS_IOMAP_WRITE_DELAY(mp, io, offset, count, flags, mval, nmap) \ |
259 | (*(mp)->m_io_ops.xfs_iomap_write_delay) \ | 260 | (*(mp)->m_io_ops.xfs_iomap_write_delay) \ |
260 | ((io)->io_obj, offset, count, flags, mval, nmap) | 261 | ((io)->io_obj, offset, count, flags, mval, nmap) |
261 | #define XFS_IOMAP_WRITE_ALLOCATE(mp, io, mval, nmap) \ | 262 | #define XFS_IOMAP_WRITE_ALLOCATE(mp, io, offset, count, mval, nmap) \ |
262 | (*(mp)->m_io_ops.xfs_iomap_write_allocate) \ | 263 | (*(mp)->m_io_ops.xfs_iomap_write_allocate) \ |
263 | ((io)->io_obj, mval, nmap) | 264 | ((io)->io_obj, offset, count, mval, nmap) |
264 | #define XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count) \ | 265 | #define XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count) \ |
265 | (*(mp)->m_io_ops.xfs_iomap_write_unwritten) \ | 266 | (*(mp)->m_io_ops.xfs_iomap_write_unwritten) \ |
266 | ((io)->io_obj, offset, count) | 267 | ((io)->io_obj, offset, count) |