aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2014-04-14 04:14:11 -0400
committerDave Chinner <david@fromorbit.com>2014-04-14 04:14:11 -0400
commitaad3f3755e7f043789b772856d1a2935f2b41a4b (patch)
tree36d8fdb1bf1f6214148ab791353427c3bf0847a1
parent72ab70a19b4ebb19dbe2a79faaa6a4ccead58e70 (diff)
xfs: xfs_vm_write_end truncates too much on failure
Similar to the write_begin problem, xfs-vm_write_end will truncate back to the old EOF, potentially removing page cache from over the top of delalloc blocks with valid data in them. Fix this by truncating back to just the start of the failed write. Signed-off-by: Dave Chinner <dchinner@redhat.com> Tested-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/xfs/xfs_aops.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 5f296934879f..e0a793113ea9 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -1634,9 +1634,12 @@ xfs_vm_write_begin(
1634} 1634}
1635 1635
1636/* 1636/*
1637 * On failure, we only need to kill delalloc blocks beyond EOF because they 1637 * On failure, we only need to kill delalloc blocks beyond EOF in the range of
1638 * will never be written. For blocks within EOF, generic_write_end() zeros them 1638 * this specific write because they will never be written. Previous writes
1639 * so they are safe to leave alone and be written with all the other valid data. 1639 * beyond EOF where block allocation succeeded do not need to be trashed, so
1640 * only new blocks from this write should be trashed. For blocks within
1641 * EOF, generic_write_end() zeros them so they are safe to leave alone and be
1642 * written with all the other valid data.
1640 */ 1643 */
1641STATIC int 1644STATIC int
1642xfs_vm_write_end( 1645xfs_vm_write_end(
@@ -1659,8 +1662,11 @@ xfs_vm_write_end(
1659 loff_t to = pos + len; 1662 loff_t to = pos + len;
1660 1663
1661 if (to > isize) { 1664 if (to > isize) {
1662 truncate_pagecache(inode, isize); 1665 /* only kill blocks in this write beyond EOF */
1666 if (pos > isize)
1667 isize = pos;
1663 xfs_vm_kill_delalloc_range(inode, isize, to); 1668 xfs_vm_kill_delalloc_range(inode, isize, to);
1669 truncate_pagecache_range(inode, isize, to);
1664 } 1670 }
1665 } 1671 }
1666 return ret; 1672 return ret;