Răsfoiți Sursa

[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>
Lachlan McIlroy 18 ani în urmă
părinte
comite
6816016137
3 a modificat fișierele cu 20 adăugiri și 20 ștergeri
  1. 18 18
      fs/xfs/linux-2.6/xfs_lrw.c
  2. 1 1
      fs/xfs/linux-2.6/xfs_lrw.h
  3. 1 1
      fs/xfs/xfs_inode.c

+ 18 - 18
fs/xfs/linux-2.6/xfs_lrw.c

@@ -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;

+ 1 - 1
fs/xfs/linux-2.6/xfs_lrw.h

@@ -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
fs/xfs/xfs_inode.c

@@ -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;
 }