summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-01-05 17:47:13 -0800
committerDarrick J. Wong <djwong@kernel.org>2021-03-25 17:08:53 -0700
commit82344615ed7b67be48389a7a8990b5f9d40a8af1 (patch)
tree6e4169496f21abf7e7f5823313c80a64839f34a0
parent84877b3456f9078784fefd1532da6774e88d8632 (diff)
xfs: extend writeback requests to handle rt cow correctlyrealtime-reflink-extsize_2021-03-25
If we have shared realtime files and the rt extent size is larger than a single fs block, we need to extend writeback requests to be aligned to rt extent size granularity because we cannot share partial rt extents. The front end should have set us up for this by dirtying the relevant ranges. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r--fs/xfs/xfs_aops.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 158d1074e1a8..290cfef0d9dd 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -561,12 +561,41 @@ static const struct iomap_writeback_ops xfs_writeback_ops = {
.discard_page = xfs_discard_page,
};
+/*
+ * Extend the writeback range to allocation unit granularity and alignment.
+ * This is a requirement for blocksize > pagesize scenarios such as realtime
+ * copy on write, since we can only share full rt extents.
+ */
+static void
+xfs_vm_writepage_extend(
+ struct xfs_inode *ip,
+ struct writeback_control *wbc)
+{
+ unsigned int bsize = xfs_inode_alloc_unitsize(ip);
+ long long int pages_to_write;
+
+ wbc->range_start = rounddown_64(wbc->range_start, bsize);
+ if (wbc->range_end != LLONG_MAX)
+ wbc->range_end = roundup_64(wbc->range_end, bsize);
+
+ if (wbc->nr_to_write == LONG_MAX)
+ return;
+
+ pages_to_write = roundup_64(wbc->range_end - wbc->range_start,
+ PAGE_SIZE);
+ if (pages_to_write >= LONG_MAX)
+ pages_to_write = LONG_MAX;
+ if (wbc->nr_to_write < pages_to_write)
+ wbc->nr_to_write = pages_to_write;
+}
+
STATIC int
xfs_vm_writepages(
- struct address_space *mapping,
- struct writeback_control *wbc)
+ struct address_space *mapping,
+ struct writeback_control *wbc)
{
- struct xfs_writepage_ctx wpc = { };
+ struct xfs_writepage_ctx wpc = { };
+ struct xfs_inode *ip = XFS_I(mapping->host);
/*
* Writing back data in a transaction context can result in recursive
@@ -575,7 +604,10 @@ xfs_vm_writepages(
if (WARN_ON_ONCE(current->journal_info))
return 0;
- xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED);
+ if (xfs_reflink_need_unshare_around(ip))
+ xfs_vm_writepage_extend(ip, wbc);
+
+ xfs_iflags_clear(ip, XFS_ITRUNCATED);
return iomap_writepages(mapping, wbc, &wpc.ctx, &xfs_writeback_ops);
}