diff options
author | Lachlan McIlroy <lachlan@sgi.com> | 2007-02-10 02:36:47 -0500 |
---|---|---|
committer | Tim Shimmin <tes@sgi.com> | 2007-02-10 02:36:47 -0500 |
commit | 681601613759accffd8e8ddbc6f942eba7ecbfe5 (patch) | |
tree | 8495ec3a648ca6ea2dce55ed7baf0127fb2ea486 | |
parent | 2823945fda94e0636be573a037c45cb7b6495af2 (diff) |
[XFS] Fix callers of xfs_iozero() to zero the correct range.
The problem is the two callers of xfs_iozero() are rounding out the range
to be zeroed to the end of a fsb and in some cases this extends past the
new eof. The call to commit_write() in xfs_iozero() will cause the Linux
inode's file size to be set too high.
SGI-PV: 960788
SGI-Modid: xfs-linux-melb:xfs-kern:28013a
Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
-rw-r--r-- | fs/xfs/linux-2.6/xfs_lrw.c | 36 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_lrw.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.c | 2 |
3 files changed, 20 insertions, 20 deletions
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 65e79b471d49..50ba4794f19f 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c | |||
@@ -134,8 +134,7 @@ STATIC int | |||
134 | xfs_iozero( | 134 | xfs_iozero( |
135 | struct inode *ip, /* inode */ | 135 | struct inode *ip, /* inode */ |
136 | loff_t pos, /* offset in file */ | 136 | loff_t pos, /* offset in file */ |
137 | size_t count, /* size of data to zero */ | 137 | size_t count) /* size of data to zero */ |
138 | loff_t end_size) /* max file size to set */ | ||
139 | { | 138 | { |
140 | unsigned bytes; | 139 | unsigned bytes; |
141 | struct page *page; | 140 | struct page *page; |
@@ -172,8 +171,6 @@ xfs_iozero( | |||
172 | if (!status) { | 171 | if (!status) { |
173 | pos += bytes; | 172 | pos += bytes; |
174 | count -= bytes; | 173 | count -= bytes; |
175 | if (pos > i_size_read(ip)) | ||
176 | i_size_write(ip, pos < end_size ? pos : end_size); | ||
177 | } | 174 | } |
178 | 175 | ||
179 | unlock: | 176 | unlock: |
@@ -449,8 +446,8 @@ STATIC int /* error (positive) */ | |||
449 | xfs_zero_last_block( | 446 | xfs_zero_last_block( |
450 | struct inode *ip, | 447 | struct inode *ip, |
451 | xfs_iocore_t *io, | 448 | xfs_iocore_t *io, |
452 | xfs_fsize_t isize, | 449 | xfs_fsize_t offset, |
453 | xfs_fsize_t end_size) | 450 | xfs_fsize_t isize) |
454 | { | 451 | { |
455 | xfs_fileoff_t last_fsb; | 452 | xfs_fileoff_t last_fsb; |
456 | xfs_mount_t *mp = io->io_mount; | 453 | xfs_mount_t *mp = io->io_mount; |
@@ -459,7 +456,6 @@ xfs_zero_last_block( | |||
459 | int zero_len; | 456 | int zero_len; |
460 | int error = 0; | 457 | int error = 0; |
461 | xfs_bmbt_irec_t imap; | 458 | xfs_bmbt_irec_t imap; |
462 | loff_t loff; | ||
463 | 459 | ||
464 | ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0); | 460 | ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0); |
465 | 461 | ||
@@ -494,9 +490,10 @@ xfs_zero_last_block( | |||
494 | */ | 490 | */ |
495 | XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD); | 491 | XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD); |
496 | 492 | ||
497 | loff = XFS_FSB_TO_B(mp, last_fsb); | ||
498 | zero_len = mp->m_sb.sb_blocksize - zero_offset; | 493 | zero_len = mp->m_sb.sb_blocksize - zero_offset; |
499 | error = xfs_iozero(ip, loff + zero_offset, zero_len, end_size); | 494 | if (isize + zero_len > offset) |
495 | zero_len = offset - isize; | ||
496 | error = xfs_iozero(ip, isize, zero_len); | ||
500 | 497 | ||
501 | XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); | 498 | XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); |
502 | ASSERT(error >= 0); | 499 | ASSERT(error >= 0); |
@@ -519,14 +516,15 @@ xfs_zero_eof( | |||
519 | bhv_vnode_t *vp, | 516 | bhv_vnode_t *vp, |
520 | xfs_iocore_t *io, | 517 | xfs_iocore_t *io, |
521 | xfs_off_t offset, /* starting I/O offset */ | 518 | xfs_off_t offset, /* starting I/O offset */ |
522 | xfs_fsize_t isize, /* current inode size */ | 519 | xfs_fsize_t isize) /* current inode size */ |
523 | xfs_fsize_t end_size) /* terminal inode size */ | ||
524 | { | 520 | { |
525 | struct inode *ip = vn_to_inode(vp); | 521 | struct inode *ip = vn_to_inode(vp); |
526 | xfs_fileoff_t start_zero_fsb; | 522 | xfs_fileoff_t start_zero_fsb; |
527 | xfs_fileoff_t end_zero_fsb; | 523 | xfs_fileoff_t end_zero_fsb; |
528 | xfs_fileoff_t zero_count_fsb; | 524 | xfs_fileoff_t zero_count_fsb; |
529 | xfs_fileoff_t last_fsb; | 525 | xfs_fileoff_t last_fsb; |
526 | xfs_fileoff_t zero_off; | ||
527 | xfs_fsize_t zero_len; | ||
530 | xfs_mount_t *mp = io->io_mount; | 528 | xfs_mount_t *mp = io->io_mount; |
531 | int nimaps; | 529 | int nimaps; |
532 | int error = 0; | 530 | int error = 0; |
@@ -540,7 +538,7 @@ xfs_zero_eof( | |||
540 | * First handle zeroing the block on which isize resides. | 538 | * First handle zeroing the block on which isize resides. |
541 | * We only zero a part of that block so it is handled specially. | 539 | * We only zero a part of that block so it is handled specially. |
542 | */ | 540 | */ |
543 | error = xfs_zero_last_block(ip, io, isize, end_size); | 541 | error = xfs_zero_last_block(ip, io, offset, isize); |
544 | if (error) { | 542 | if (error) { |
545 | ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); | 543 | ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); |
546 | ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); | 544 | ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); |
@@ -601,10 +599,13 @@ xfs_zero_eof( | |||
601 | */ | 599 | */ |
602 | XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); | 600 | XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); |
603 | 601 | ||
604 | error = xfs_iozero(ip, | 602 | zero_off = XFS_FSB_TO_B(mp, start_zero_fsb); |
605 | XFS_FSB_TO_B(mp, start_zero_fsb), | 603 | zero_len = XFS_FSB_TO_B(mp, imap.br_blockcount); |
606 | XFS_FSB_TO_B(mp, imap.br_blockcount), | 604 | |
607 | end_size); | 605 | if ((zero_off + zero_len) > offset) |
606 | zero_len = offset - zero_off; | ||
607 | |||
608 | error = xfs_iozero(ip, zero_off, zero_len); | ||
608 | if (error) { | 609 | if (error) { |
609 | goto out_lock; | 610 | goto out_lock; |
610 | } | 611 | } |
@@ -783,8 +784,7 @@ start: | |||
783 | */ | 784 | */ |
784 | 785 | ||
785 | if (pos > isize) { | 786 | if (pos > isize) { |
786 | error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, | 787 | error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, isize); |
787 | isize, pos + count); | ||
788 | if (error) { | 788 | if (error) { |
789 | xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); | 789 | xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); |
790 | goto out_unlock_mutex; | 790 | goto out_unlock_mutex; |
diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index c77e62efb742..7ac51b1d2161 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h | |||
@@ -83,7 +83,7 @@ extern int xfs_bdstrat_cb(struct xfs_buf *); | |||
83 | extern int xfs_dev_is_read_only(struct xfs_mount *, char *); | 83 | extern int xfs_dev_is_read_only(struct xfs_mount *, char *); |
84 | 84 | ||
85 | extern int xfs_zero_eof(struct bhv_vnode *, struct xfs_iocore *, xfs_off_t, | 85 | extern int xfs_zero_eof(struct bhv_vnode *, struct xfs_iocore *, xfs_off_t, |
86 | xfs_fsize_t, xfs_fsize_t); | 86 | xfs_fsize_t); |
87 | extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *, | 87 | extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *, |
88 | const struct iovec *, unsigned int, | 88 | const struct iovec *, unsigned int, |
89 | loff_t *, int, struct cred *); | 89 | loff_t *, int, struct cred *); |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index e42418f92215..295577d67ea0 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -1810,7 +1810,7 @@ xfs_igrow_start( | |||
1810 | * and any blocks between the old and new file sizes. | 1810 | * and any blocks between the old and new file sizes. |
1811 | */ | 1811 | */ |
1812 | error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size, | 1812 | error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size, |
1813 | ip->i_d.di_size, new_size); | 1813 | ip->i_d.di_size); |
1814 | return error; | 1814 | return error; |
1815 | } | 1815 | } |
1816 | 1816 | ||