xfs
[Top] [All Lists]

[PATCH 3/6] xfs: xfs_vm_write_end truncates too much on failure

To: xfs@xxxxxxxxxxx
Subject: [PATCH 3/6] xfs: xfs_vm_write_end truncates too much on failure
From: Dave Chinner <david@xxxxxxxxxxxxx>
Date: Thu, 10 Apr 2014 15:00:50 +1000
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <1397106053-7489-1-git-send-email-david@xxxxxxxxxxxxx>
References: <1397106053-7489-1-git-send-email-david@xxxxxxxxxxxxx>
From: Dave Chinner <dchinner@xxxxxxxxxx>

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@xxxxxxxxxx>
---
 fs/xfs/xfs_aops.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 5f29693..e0a7931 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -1634,9 +1634,12 @@ xfs_vm_write_begin(
 }
 
 /*
- * On failure, we only need to kill delalloc blocks beyond EOF because they
- * will never be written. For blocks within EOF, generic_write_end() zeros them
- * so they are safe to leave alone and be written with all the other valid 
data.
+ * On failure, we only need to kill delalloc blocks beyond EOF in the range of
+ * this specific write because they will never be written. Previous writes
+ * beyond EOF where block allocation succeeded do not need to be trashed, so
+ * only new blocks from this write should be trashed. For blocks within
+ * EOF, generic_write_end() zeros them so they are safe to leave alone and be
+ * written with all the other valid data.
  */
 STATIC int
 xfs_vm_write_end(
@@ -1659,8 +1662,11 @@ xfs_vm_write_end(
                loff_t          to = pos + len;
 
                if (to > isize) {
-                       truncate_pagecache(inode, isize);
+                       /* only kill blocks in this write beyond EOF */
+                       if (pos > isize)
+                               isize = pos;
                        xfs_vm_kill_delalloc_range(inode, isize, to);
+                       truncate_pagecache_range(inode, isize, to);
                }
        }
        return ret;
-- 
1.9.0

<Prev in Thread] Current Thread [Next in Thread>