summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_super.c
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-09-01 11:20:13 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-10-22 16:41:12 -0700
commit76cb8880d21a94561d0708ce026109b20bae36bc (patch)
tree16077a673d3d83b74e9058f378741fd07777de65 /fs/xfs/xfs_super.c
parentf505d79cf1f1a66c920e91a3e1e5c5a850381965 (diff)
xfs: allow reflink on the rt volume when extent size is larger than 1 rt blockrealtime-reflink-extsize_2021-10-22
Make the necessary tweaks to the reflink remapping code to support remapping on the realtime volume when the rt extent size is larger than a single rt block. We need to check that the remap arguments from userspace are aligned to a rt extent boundary, and that the length is always aligned, even if the kernel tried to round it up to EOF for us. XFS can only map and remap full rt extents, so we have to be a little more strict about the alignment there. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs/xfs/xfs_super.c')
-rw-r--r--fs/xfs/xfs_super.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 108d0d6865a6..4b31bce078c9 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1690,13 +1690,23 @@ xfs_fs_fill_super(
if (xfs_has_reflink(mp)) {
/*
- * Reflink doesn't support rt extent sizes larger than a single
- * block because we would have to perform unshare-around for
- * rtext-unaligned write requests.
+ * Reflink doesn't support pagecache pages that span multiple
+ * realtime extents because iomap doesn't track subpage dirty
+ * state. This means that we cannot dirty all the pages
+ * backing an rt extent without dirtying the adjoining rt
+ * extents. If those rt extents are shared and extend into
+ * other pages, this leads to crazy write amplification. The
+ * VFS remap_range checks assume power-of-two block sizes, so
+ * we don't support that either.
+ *
+ * Hence we only support rt extent sizes that are an integer
+ * power of two because we know those will align with the page
+ * size.
*/
- if (xfs_has_realtime(mp) && mp->m_sb.sb_rextsize != 1) {
+ if (xfs_has_realtime(mp) &&
+ !is_power_of_2(mp->m_sb.sb_rextsize)) {
xfs_alert(mp,
- "reflink not compatible with realtime extent size %u!",
+ "reflink not compatible with non-power-of-2 realtime extent size %u!",
mp->m_sb.sb_rextsize);
error = -EINVAL;
goto out_filestream_unmount;
@@ -1715,7 +1725,6 @@ xfs_fs_fill_super(
}
}
-
error = xfs_mountfs(mp);
if (error)
goto out_filestream_unmount;