4.10-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Brian Foster <bfos...@redhat.com>

commit fa7f138ac4c70dc00519c124cf7cd4862a0a5b0e upstream.

The buffered write failure handling code in
xfs_file_iomap_end_delalloc() has a couple minor problems. First, if
written == 0, start_fsb is not rounded down and it fails to kill off a
delalloc block if the start offset is block unaligned. This results in a
lingering delalloc block and broken delalloc block accounting detected
at unmount time. Fix this by rounding down start_fsb in the unlikely
event that written == 0.

Second, it is possible for a failed overwrite of a delalloc extent to
leave dirty pagecache around over a hole in the file. This is because is
possible to hit ->iomap_end() on write failure before the iomap code has
attempted to allocate pagecache, and thus has no need to clean it up. If
the targeted delalloc extent was successfully written by a previous
write, however, then it does still have dirty pages when ->iomap_end()
punches out the underlying blocks. This ultimately results in writeback
over a hole. To fix this problem, unconditionally punch out the
pagecache from XFS before the associated delalloc range.

Signed-off-by: Brian Foster <bfos...@redhat.com>
Reviewed-by: Christoph Hellwig <h...@lst.de>
Reviewed-by: Darrick J. Wong <darrick.w...@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.w...@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 fs/xfs/xfs_iomap.c |   13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -1102,7 +1102,15 @@ xfs_file_iomap_end_delalloc(
        xfs_fileoff_t           end_fsb;
        int                     error = 0;
 
-       start_fsb = XFS_B_TO_FSB(mp, offset + written);
+       /*
+        * start_fsb refers to the first unused block after a short write. If
+        * nothing was written, round offset down to point at the first block in
+        * the range.
+        */
+       if (unlikely(!written))
+               start_fsb = XFS_B_TO_FSBT(mp, offset);
+       else
+               start_fsb = XFS_B_TO_FSB(mp, offset + written);
        end_fsb = XFS_B_TO_FSB(mp, offset + length);
 
        /*
@@ -1114,6 +1122,9 @@ xfs_file_iomap_end_delalloc(
         * blocks in the range, they are ours.
         */
        if (start_fsb < end_fsb) {
+               truncate_pagecache_range(VFS_I(ip), XFS_FSB_TO_B(mp, start_fsb),
+                                        XFS_FSB_TO_B(mp, end_fsb) - 1);
+
                xfs_ilock(ip, XFS_ILOCK_EXCL);
                error = xfs_bmap_punch_delalloc_range(ip, start_fsb,
                                               end_fsb - start_fsb);


Reply via email to