summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index aa4bc2b5aab1..f6e44d203786 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -6406,6 +6406,28 @@ xfs_get_cowextsz_hint(
if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE)
a = ip->i_cowextsize;
if (XFS_IS_REALTIME_INODE(ip)) {
+ /*
+ * For realtime files, the realtime extent is the fundamental
+ * unit of allocation. This means that data sharing and CoW
+ * remapping can only be done in those units. For filesystems
+ * where the extent size is larger than one block, write
+ * requests that are not aligned to an extent boundary employ
+ * an unshare-around strategy to ensure that all pages for a
+ * shared extent are fully dirtied.
+ *
+ * Because the remapping alignment requirement applies equally
+ * to all CoW writes, any regular overwrites that could be
+ * turned (by a speculative CoW preallocation) into a CoW write
+ * must either employ this dirty-around strategy, or be smart
+ * enough to ignore the CoW fork mapping unless the entire
+ * extent is dirty or becomes shared by writeback time. Doing
+ * the first would dramatically increase write amplification,
+ * and the second would require deeper insight into the state
+ * of the page cache during a writeback request. For now, we
+ * ignore the hint.
+ */
+ if (ip->i_mount->m_sb.sb_rextsize > 1)
+ return ip->i_mount->m_sb.sb_rextsize;
b = 0;
if (ip->i_diflags & XFS_DIFLAG_EXTSIZE)
b = ip->i_extsize;