[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>
This commit is contained in:
Lachlan McIlroy 2007-02-10 18:36:47 +11:00 committed by Tim Shimmin
parent 2823945fda
commit 6816016137
3 changed files with 20 additions and 20 deletions

View File

@ -134,8 +134,7 @@ STATIC int
xfs_iozero(
struct inode *ip, /* inode */
loff_t pos, /* offset in file */
size_t count, /* size of data to zero */
loff_t end_size) /* max file size to set */
size_t count) /* size of data to zero */
{
unsigned bytes;
struct page *page;
@ -172,8 +171,6 @@ xfs_iozero(
if (!status) {
pos += bytes;
count -= bytes;
if (pos > i_size_read(ip))
i_size_write(ip, pos < end_size ? pos : end_size);
}
unlock:
@ -449,8 +446,8 @@ STATIC int /* error (positive) */
xfs_zero_last_block(
struct inode *ip,
xfs_iocore_t *io,
xfs_fsize_t isize,
xfs_fsize_t end_size)
xfs_fsize_t offset,
xfs_fsize_t isize)
{
xfs_fileoff_t last_fsb;
xfs_mount_t *mp = io->io_mount;
@ -459,7 +456,6 @@ xfs_zero_last_block(
int zero_len;
int error = 0;
xfs_bmbt_irec_t imap;
loff_t loff;
ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0);
@ -494,9 +490,10 @@ xfs_zero_last_block(
*/
XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD);
loff = XFS_FSB_TO_B(mp, last_fsb);
zero_len = mp->m_sb.sb_blocksize - zero_offset;
error = xfs_iozero(ip, loff + zero_offset, zero_len, end_size);
if (isize + zero_len > offset)
zero_len = offset - isize;
error = xfs_iozero(ip, isize, zero_len);
XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
ASSERT(error >= 0);
@ -519,14 +516,15 @@ xfs_zero_eof(
bhv_vnode_t *vp,
xfs_iocore_t *io,
xfs_off_t offset, /* starting I/O offset */
xfs_fsize_t isize, /* current inode size */
xfs_fsize_t end_size) /* terminal inode size */
xfs_fsize_t isize) /* current inode size */
{
struct inode *ip = vn_to_inode(vp);
xfs_fileoff_t start_zero_fsb;
xfs_fileoff_t end_zero_fsb;
xfs_fileoff_t zero_count_fsb;
xfs_fileoff_t last_fsb;
xfs_fileoff_t zero_off;
xfs_fsize_t zero_len;
xfs_mount_t *mp = io->io_mount;
int nimaps;
int error = 0;
@ -540,7 +538,7 @@ xfs_zero_eof(
* First handle zeroing the block on which isize resides.
* We only zero a part of that block so it is handled specially.
*/
error = xfs_zero_last_block(ip, io, isize, end_size);
error = xfs_zero_last_block(ip, io, offset, isize);
if (error) {
ASSERT(ismrlocked(io->io_lock, MR_UPDATE));
ASSERT(ismrlocked(io->io_iolock, MR_UPDATE));
@ -601,10 +599,13 @@ xfs_zero_eof(
*/
XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
error = xfs_iozero(ip,
XFS_FSB_TO_B(mp, start_zero_fsb),
XFS_FSB_TO_B(mp, imap.br_blockcount),
end_size);
zero_off = XFS_FSB_TO_B(mp, start_zero_fsb);
zero_len = XFS_FSB_TO_B(mp, imap.br_blockcount);
if ((zero_off + zero_len) > offset)
zero_len = offset - zero_off;
error = xfs_iozero(ip, zero_off, zero_len);
if (error) {
goto out_lock;
}
@ -783,8 +784,7 @@ start:
*/
if (pos > isize) {
error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos,
isize, pos + count);
error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, isize);
if (error) {
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
goto out_unlock_mutex;

View File

@ -83,7 +83,7 @@ extern int xfs_bdstrat_cb(struct xfs_buf *);
extern int xfs_dev_is_read_only(struct xfs_mount *, char *);
extern int xfs_zero_eof(struct bhv_vnode *, struct xfs_iocore *, xfs_off_t,
xfs_fsize_t, xfs_fsize_t);
xfs_fsize_t);
extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *,
const struct iovec *, unsigned int,
loff_t *, int, struct cred *);

View File

@ -1810,7 +1810,7 @@ xfs_igrow_start(
* and any blocks between the old and new file sizes.
*/
error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size,
ip->i_d.di_size, new_size);
ip->i_d.di_size);
return error;
}