mirror of
https://abf.rosa.ru/djam/kernel-5.10.git
synced 2025-02-25 09:42:49 +00:00
67 lines
2.6 KiB
Diff
67 lines
2.6 KiB
Diff
![]() |
From fa7f138ac4c70dc00519c124cf7cd4862a0a5b0e Mon Sep 17 00:00:00 2001
|
||
|
From: Brian Foster <bfoster@redhat.com>
|
||
|
Date: Thu, 16 Feb 2017 17:19:12 -0800
|
||
|
Subject: xfs: clear delalloc and cache on buffered write failure
|
||
|
|
||
|
From: Brian Foster <bfoster@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 <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>
|
||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@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
|
||
|
@@ -1068,7 +1068,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);
|
||
|
|
||
|
/*
|
||
|
@@ -1080,6 +1088,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);
|