Skip to content

Commit c770f99

Browse files
Brian Fostercmaiolino
authored andcommitted
xfs: only flush when COW fork blocks overlap data fork holes
The zero range hole mapping flush case has been lifted from iomap into XFS. Now that we have more mapping context available from the ->iomap_begin() handler, we can isolate the flush further to when we know a hole is fronted by COW blocks. Rather than purely rely on pagecache dirty state, explicitly check for the case where a range is a hole in both forks. Otherwise trim to the range where there does happen to be overlap and use that for the pagecache writeback check. This might prevent some spurious zeroing, but more importantly makes it easier to remove the flush entirely. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Carlos Maiolino <cem@kernel.org>
1 parent a8eb413 commit c770f99

1 file changed

Lines changed: 30 additions & 6 deletions

File tree

fs/xfs/xfs_iomap.c

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,10 +1781,12 @@ xfs_buffered_write_iomap_begin(
17811781
{
17821782
struct iomap_iter *iter = container_of(iomap, struct iomap_iter,
17831783
iomap);
1784+
struct address_space *mapping = inode->i_mapping;
17841785
struct xfs_inode *ip = XFS_I(inode);
17851786
struct xfs_mount *mp = ip->i_mount;
17861787
xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset);
17871788
xfs_fileoff_t end_fsb = xfs_iomap_end_fsb(mp, offset, count);
1789+
xfs_fileoff_t cow_fsb = NULLFILEOFF;
17881790
struct xfs_bmbt_irec imap, cmap;
17891791
struct xfs_iext_cursor icur, ccur;
17901792
xfs_fsblock_t prealloc_blocks = 0;
@@ -1852,6 +1854,8 @@ xfs_buffered_write_iomap_begin(
18521854
}
18531855
cow_eof = !xfs_iext_lookup_extent(ip, ip->i_cowfp, offset_fsb,
18541856
&ccur, &cmap);
1857+
if (!cow_eof)
1858+
cow_fsb = cmap.br_startoff;
18551859
}
18561860

18571861
/* We never need to allocate blocks for unsharing a hole. */
@@ -1866,17 +1870,37 @@ xfs_buffered_write_iomap_begin(
18661870
* writeback to remap pending blocks and restart the lookup.
18671871
*/
18681872
if ((flags & IOMAP_ZERO) && imap.br_startoff > offset_fsb) {
1869-
if (filemap_range_needs_writeback(inode->i_mapping, offset,
1870-
offset + count - 1)) {
1873+
loff_t start, end;
1874+
1875+
imap.br_blockcount = imap.br_startoff - offset_fsb;
1876+
imap.br_startoff = offset_fsb;
1877+
imap.br_startblock = HOLESTARTBLOCK;
1878+
imap.br_state = XFS_EXT_NORM;
1879+
1880+
if (cow_fsb == NULLFILEOFF)
1881+
goto found_imap;
1882+
if (cow_fsb > offset_fsb) {
1883+
xfs_trim_extent(&imap, offset_fsb,
1884+
cow_fsb - offset_fsb);
1885+
goto found_imap;
1886+
}
1887+
1888+
/* COW fork blocks overlap the hole */
1889+
xfs_trim_extent(&imap, offset_fsb,
1890+
cmap.br_startoff + cmap.br_blockcount - offset_fsb);
1891+
start = XFS_FSB_TO_B(mp, imap.br_startoff);
1892+
end = XFS_FSB_TO_B(mp,
1893+
imap.br_startoff + imap.br_blockcount) - 1;
1894+
if (filemap_range_needs_writeback(mapping, start, end)) {
18711895
xfs_iunlock(ip, lockmode);
1872-
error = filemap_write_and_wait_range(inode->i_mapping,
1873-
offset, offset + count - 1);
1896+
error = filemap_write_and_wait_range(mapping, start,
1897+
end);
18741898
if (error)
18751899
return error;
18761900
goto restart;
18771901
}
1878-
xfs_hole_to_iomap(ip, iomap, offset_fsb, imap.br_startoff);
1879-
goto out_unlock;
1902+
1903+
goto found_imap;
18801904
}
18811905

18821906
/*

0 commit comments

Comments
 (0)