Skip to content

Commit 388bb26

Browse files
Brian Fostercmaiolino
authored andcommitted
xfs: report cow mappings with dirty pagecache for iomap zero range
XFS has long supported the case where it is possible to have dirty data in pagecache backed by COW fork blocks and a hole in the data fork. This occurs for two reasons. On reflink enabled files, COW fork blocks are allocated with preallocation to help avoid fragmention. Second, if a mapping lookup for a write finds blocks in the COW fork, it consumes those blocks unconditionally. This might mean that COW fork blocks are backed by non-shared blocks or even a hole in the data fork, both of which are perfectly fine. This leaves an odd corner case for zero range, however, because it needs to distinguish between ranges that are sparse and thus do not require zeroing and those that are not. A range backed by COW fork blocks and a data fork hole might either be a legitimate hole in the file or a range with pending buffered writes that will be written back (which will remap COW fork blocks into the data fork). This "COW fork blocks over data fork hole" situation has historically been reported as a hole to iomap, which then has grown a flush hack as a workaround to ensure zeroing occurs correctly. Now that this has been lifted into the filesystem and replaced by the dirty folio lookup mechanism, we can do better and use the pagecache state to decide how to report the mapping. If a COW fork range exists with dirty folios in cache, then report a typical shared mapping. If the range is clean in cache, then we can consider the COW blocks preallocation and call it a hole. This doesn't fundamentally change behavior, but makes mapping reporting more accurate. Note that this does require splitting across the EOF boundary (similar to normal zero range) to ensure we don't spuriously perform post-eof zeroing. iomap will warn about zeroing beyond EOF because folios beyond i_size may not be written back. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Carlos Maiolino <cem@kernel.org>
1 parent ce9d27c commit 388bb26

1 file changed

Lines changed: 22 additions & 4 deletions

File tree

fs/xfs/xfs_iomap.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,6 +1786,7 @@ xfs_buffered_write_iomap_begin(
17861786
xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset);
17871787
xfs_fileoff_t end_fsb = xfs_iomap_end_fsb(mp, offset, count);
17881788
xfs_fileoff_t cow_fsb = NULLFILEOFF;
1789+
xfs_fileoff_t eof_fsb = XFS_B_TO_FSB(mp, XFS_ISIZE(ip));
17891790
struct xfs_bmbt_irec imap, cmap;
17901791
struct xfs_iext_cursor icur, ccur;
17911792
xfs_fsblock_t prealloc_blocks = 0;
@@ -1868,7 +1869,8 @@ xfs_buffered_write_iomap_begin(
18681869
* cache and fill the iomap batch with folios that need zeroing.
18691870
*/
18701871
if ((flags & IOMAP_ZERO) && imap.br_startoff > offset_fsb) {
1871-
loff_t start, end;
1872+
loff_t start, end;
1873+
unsigned int fbatch_count;
18721874

18731875
imap.br_blockcount = imap.br_startoff - offset_fsb;
18741876
imap.br_startoff = offset_fsb;
@@ -1883,15 +1885,33 @@ xfs_buffered_write_iomap_begin(
18831885
goto found_imap;
18841886
}
18851887

1888+
/* no zeroing beyond eof, so split at the boundary */
1889+
if (offset_fsb >= eof_fsb)
1890+
goto found_imap;
1891+
if (offset_fsb < eof_fsb && end_fsb > eof_fsb)
1892+
xfs_trim_extent(&imap, offset_fsb,
1893+
eof_fsb - offset_fsb);
1894+
18861895
/* COW fork blocks overlap the hole */
18871896
xfs_trim_extent(&imap, offset_fsb,
18881897
cmap.br_startoff + cmap.br_blockcount - offset_fsb);
18891898
start = XFS_FSB_TO_B(mp, imap.br_startoff);
18901899
end = XFS_FSB_TO_B(mp, imap.br_startoff + imap.br_blockcount);
1891-
iomap_fill_dirty_folios(iter, &start, end, &iomap_flags);
1900+
fbatch_count = iomap_fill_dirty_folios(iter, &start, end,
1901+
&iomap_flags);
18921902
xfs_trim_extent(&imap, offset_fsb,
18931903
XFS_B_TO_FSB(mp, start) - offset_fsb);
18941904

1905+
/*
1906+
* Report the COW mapping if we have folios to zero. Otherwise
1907+
* ignore the COW blocks as preallocation and report a hole.
1908+
*/
1909+
if (fbatch_count) {
1910+
xfs_trim_extent(&cmap, imap.br_startoff,
1911+
imap.br_blockcount);
1912+
imap.br_startoff = end_fsb; /* fake hole */
1913+
goto found_cow;
1914+
}
18951915
goto found_imap;
18961916
}
18971917

@@ -1901,8 +1921,6 @@ xfs_buffered_write_iomap_begin(
19011921
* unwritten extent.
19021922
*/
19031923
if (flags & IOMAP_ZERO) {
1904-
xfs_fileoff_t eof_fsb = XFS_B_TO_FSB(mp, XFS_ISIZE(ip));
1905-
19061924
if (isnullstartblock(imap.br_startblock) &&
19071925
offset_fsb >= eof_fsb)
19081926
goto convert_delay;

0 commit comments

Comments
 (0)