aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Scott <nathans@sgi.com>2005-05-05 16:33:20 -0400
committerChristoph Hellwig <hch@melbourne.sgi.com>2005-05-05 16:33:20 -0400
commit24e17b5fb99d4d1b47fe0847a3a801e36d431ff6 (patch)
tree0ac181b6ddc64a04fe55aa79efceecc6e4d90451
parent775bf6c99a4ebde13bdb8dfa528ed241483b49ef (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> .
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c68
-rw-r--r--fs/xfs/xfs_iomap.c20
-rw-r--r--fs/xfs/xfs_iomap.h7
-rw-r--r--fs/xfs/xfs_mount.h7
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:
746int 747int
747xfs_iomap_write_allocate( 748xfs_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
891trans_cancel: 893trans_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);
101extern int xfs_iomap_write_delay(struct xfs_inode *, loff_t, size_t, int, 98extern 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 *);
103extern int xfs_iomap_write_allocate(struct xfs_inode *, 100extern int xfs_iomap_write_allocate(struct xfs_inode *, loff_t, size_t,
104 struct xfs_bmbt_irec *, int *); 101 struct xfs_bmbt_irec *, int *);
105extern int xfs_iomap_write_unwritten(struct xfs_inode *, loff_t, size_t); 102extern 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 *);
218typedef int (*xfs_iomap_write_allocate_t)( 218typedef 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 *);
220typedef int (*xfs_iomap_write_unwritten_t)( 221typedef int (*xfs_iomap_write_unwritten_t)(
221 void *, loff_t, size_t); 222 void *, loff_t, size_t);
222typedef uint (*xfs_lck_map_shared_t)(void *); 223typedef 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)