Commit 68160161 authored by Lachlan McIlroy's avatar Lachlan McIlroy Committed by Tim Shimmin

[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: default avatarLachlan McIlroy <lachlan@sgi.com>
Signed-off-by: default avatarDavid Chinner <dgc@sgi.com>
Signed-off-by: default avatarTim Shimmin <tes@sgi.com>
parent 2823945f
...@@ -134,8 +134,7 @@ STATIC int ...@@ -134,8 +134,7 @@ STATIC int
xfs_iozero( xfs_iozero(
struct inode *ip, /* inode */ struct inode *ip, /* inode */
loff_t pos, /* offset in file */ loff_t pos, /* offset in file */
size_t count, /* size of data to zero */ size_t count) /* size of data to zero */
loff_t end_size) /* max file size to set */
{ {
unsigned bytes; unsigned bytes;
struct page *page; struct page *page;
...@@ -172,8 +171,6 @@ xfs_iozero( ...@@ -172,8 +171,6 @@ xfs_iozero(
if (!status) { if (!status) {
pos += bytes; pos += bytes;
count -= bytes; count -= bytes;
if (pos > i_size_read(ip))
i_size_write(ip, pos < end_size ? pos : end_size);
} }
unlock: unlock:
...@@ -449,8 +446,8 @@ STATIC int /* error (positive) */ ...@@ -449,8 +446,8 @@ STATIC int /* error (positive) */
xfs_zero_last_block( xfs_zero_last_block(
struct inode *ip, struct inode *ip,
xfs_iocore_t *io, xfs_iocore_t *io,
xfs_fsize_t isize, xfs_fsize_t offset,
xfs_fsize_t end_size) xfs_fsize_t isize)
{ {
xfs_fileoff_t last_fsb; xfs_fileoff_t last_fsb;
xfs_mount_t *mp = io->io_mount; xfs_mount_t *mp = io->io_mount;
...@@ -459,7 +456,6 @@ xfs_zero_last_block( ...@@ -459,7 +456,6 @@ xfs_zero_last_block(
int zero_len; int zero_len;
int error = 0; int error = 0;
xfs_bmbt_irec_t imap; xfs_bmbt_irec_t imap;
loff_t loff;
ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0); ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0);
...@@ -494,9 +490,10 @@ xfs_zero_last_block( ...@@ -494,9 +490,10 @@ xfs_zero_last_block(
*/ */
XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD); 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; 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); XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
ASSERT(error >= 0); ASSERT(error >= 0);
...@@ -519,14 +516,15 @@ xfs_zero_eof( ...@@ -519,14 +516,15 @@ xfs_zero_eof(
bhv_vnode_t *vp, bhv_vnode_t *vp,
xfs_iocore_t *io, xfs_iocore_t *io,
xfs_off_t offset, /* starting I/O offset */ xfs_off_t offset, /* starting I/O offset */
xfs_fsize_t isize, /* current inode size */ xfs_fsize_t isize) /* current inode size */
xfs_fsize_t end_size) /* terminal inode size */
{ {
struct inode *ip = vn_to_inode(vp); struct inode *ip = vn_to_inode(vp);
xfs_fileoff_t start_zero_fsb; xfs_fileoff_t start_zero_fsb;
xfs_fileoff_t end_zero_fsb; xfs_fileoff_t end_zero_fsb;
xfs_fileoff_t zero_count_fsb; xfs_fileoff_t zero_count_fsb;
xfs_fileoff_t last_fsb; xfs_fileoff_t last_fsb;
xfs_fileoff_t zero_off;
xfs_fsize_t zero_len;
xfs_mount_t *mp = io->io_mount; xfs_mount_t *mp = io->io_mount;
int nimaps; int nimaps;
int error = 0; int error = 0;
...@@ -540,7 +538,7 @@ xfs_zero_eof( ...@@ -540,7 +538,7 @@ xfs_zero_eof(
* First handle zeroing the block on which isize resides. * First handle zeroing the block on which isize resides.
* We only zero a part of that block so it is handled specially. * 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) { if (error) {
ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); ASSERT(ismrlocked(io->io_lock, MR_UPDATE));
ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); ASSERT(ismrlocked(io->io_iolock, MR_UPDATE));
...@@ -601,10 +599,13 @@ xfs_zero_eof( ...@@ -601,10 +599,13 @@ xfs_zero_eof(
*/ */
XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
error = xfs_iozero(ip, zero_off = XFS_FSB_TO_B(mp, start_zero_fsb);
XFS_FSB_TO_B(mp, start_zero_fsb), zero_len = XFS_FSB_TO_B(mp, imap.br_blockcount);
XFS_FSB_TO_B(mp, imap.br_blockcount),
end_size); if ((zero_off + zero_len) > offset)
zero_len = offset - zero_off;
error = xfs_iozero(ip, zero_off, zero_len);
if (error) { if (error) {
goto out_lock; goto out_lock;
} }
...@@ -783,8 +784,7 @@ xfs_write( ...@@ -783,8 +784,7 @@ xfs_write(
*/ */
if (pos > isize) { if (pos > isize) {
error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, isize);
isize, pos + count);
if (error) { if (error) {
xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
goto out_unlock_mutex; goto out_unlock_mutex;
......
...@@ -83,7 +83,7 @@ extern int xfs_bdstrat_cb(struct xfs_buf *); ...@@ -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_dev_is_read_only(struct xfs_mount *, char *);
extern int xfs_zero_eof(struct bhv_vnode *, struct xfs_iocore *, xfs_off_t, 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 *, extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *,
const struct iovec *, unsigned int, const struct iovec *, unsigned int,
loff_t *, int, struct cred *); loff_t *, int, struct cred *);
......
...@@ -1810,7 +1810,7 @@ xfs_igrow_start( ...@@ -1810,7 +1810,7 @@ xfs_igrow_start(
* and any blocks between the old and new file sizes. * and any blocks between the old and new file sizes.
*/ */
error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size, 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; return error;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment