aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Chinner <dgc@sgi.com>2007-07-19 02:28:58 -0400
committerTim Shimmin <tes@chook.melbourne.sgi.com>2007-07-19 05:52:05 -0400
commitc32676eea19ce29cb74dba0f97b085e83f6b8915 (patch)
tree5eddf206e10b0b1857c899fd9939c517aa758359
parent91ebecc74eeeeea0a2aa50bf1964ec2214a229c9 (diff)
[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: David Chinner <dgc@sgi.com> Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Tim Shimmin <tes@sgi.com>
-rw-r--r--fs/xfs/xfs_vnodeops.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 401cb00a55d6..1a5ad8cd97b0 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -589,7 +589,30 @@ xfs_setattr(
589 code = xfs_igrow_start(ip, vap->va_size, credp); 589 code = xfs_igrow_start(ip, vap->va_size, credp);
590 } 590 }
591 xfs_iunlock(ip, XFS_ILOCK_EXCL); 591 xfs_iunlock(ip, XFS_ILOCK_EXCL);
592 vn_iowait(vp); /* wait for the completion of any pending DIOs */ 592
593 /*
594 * We are going to log the inode size change in this
595 * transaction so any previous writes that are beyond the on
596 * disk EOF and the new EOF that have not been written out need
597 * to be written here. If we do not write the data out, we
598 * expose ourselves to the null files problem.
599 *
600 * Only flush from the on disk size to the smaller of the in
601 * memory file size or the new size as that's the range we
602 * really care about here and prevents waiting for other data
603 * not within the range we care about here.
604 */
605 if (!code &&
606 (ip->i_size != ip->i_d.di_size) &&
607 (vap->va_size > ip->i_d.di_size)) {
608 code = bhv_vop_flush_pages(XFS_ITOV(ip),
609 ip->i_d.di_size, vap->va_size,
610 XFS_B_ASYNC, FI_NONE);
611 }
612
613 /* wait for all I/O to complete */
614 vn_iowait(vp);
615
593 if (!code) 616 if (!code)
594 code = xfs_itruncate_data(ip, vap->va_size); 617 code = xfs_itruncate_data(ip, vap->va_size);
595 if (code) { 618 if (code) {