xfs: clear delalloc and cache on buffered write failure
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 <bfoster@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
parent
4560e78f40
commit
fa7f138ac4
|
@ -1078,7 +1078,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);
|
||||
|
||||
/*
|
||||
|
@ -1090,6 +1098,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);
|
||||
|
|
Loading…
Reference in New Issue