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

Commit c32676ee authored by David Chinner's avatar David Chinner Committed by Tim Shimmin
Browse files

[XFS] Fix inode size update before data write in xfs_setattr



When changing the file size by a truncate() call, we log the change in the
inode size. However, we do not flush any outstanding data that might not
have been written to disk, thereby violating the data/inode size update
order. This can leave files full of NULLs on crash.

Hence if we are truncating the file, flush any unwritten data that may lie
between the curret on disk inode size and the new inode size that is being
logged to ensure that ordering is preserved.

SGI-PV: 966308
SGI-Modid: xfs-linux-melb:xfs-kern:29174a

Signed-off-by: default avatarDavid Chinner <dgc@sgi.com>
Signed-off-by: default avatarChristoph Hellwig <hch@infradead.org>
Signed-off-by: default avatarTim Shimmin <tes@sgi.com>
parent 91ebecc7
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -589,7 +589,30 @@ xfs_setattr(
			code = xfs_igrow_start(ip, vap->va_size, credp);
		}
		xfs_iunlock(ip, XFS_ILOCK_EXCL);
		vn_iowait(vp); /* wait for the completion of any pending DIOs */

		/*
		 * We are going to log the inode size change in this
		 * transaction so any previous writes that are beyond the on
		 * disk EOF and the new EOF that have not been written out need
		 * to be written here. If we do not write the data out, we
		 * expose ourselves to the null files problem.
		 *
		 * Only flush from the on disk size to the smaller of the in
		 * memory file size or the new size as that's the range we
		 * really care about here and prevents waiting for other data
		 * not within the range we care about here.
		 */
		if (!code &&
		    (ip->i_size != ip->i_d.di_size) &&
		    (vap->va_size > ip->i_d.di_size)) {
			code = bhv_vop_flush_pages(XFS_ITOV(ip),
					ip->i_d.di_size, vap->va_size,
					XFS_B_ASYNC, FI_NONE);
		}

		/* wait for all I/O to complete */
		vn_iowait(vp);

		if (!code)
			code = xfs_itruncate_data(ip, vap->va_size);
		if (code) {