Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+18 −18
Original line number Diff line number Diff line
@@ -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 @@ xfs_write(
	 */

	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;
+1 −1
Original line number Diff line number Diff line
@@ -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 *);
+1 −1
Original line number Diff line number Diff line
@@ -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;
}