summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_iops.c
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-09-01 11:19:50 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-10-22 16:41:12 -0700
commit1111f3c7992ffef84fdec231734676e3bca4d83d (patch)
tree50e3150b83ab53e872c1869e945f0bfe526d260c /fs/xfs/xfs_iops.c
parent40863d13b2ca04910de4eddb87c278f6ce0b42ad (diff)
xfs: enable CoW when rt extent size is larger than 1 block
Copy on write encounters a major plot twist when the file being CoW'd lives on the realtime volume and the realtime extent size is larger than a single filesystem block. XFS can only unmap and remap full rt extents, which means that allocations are always done in units of full rt extents, and a request to unmap less than one extent is treated as a request to convert an extent to unwritten status. This behavioral quirk is not compatible with the existing CoW mechanism, so we have to intercept every path through which files can be modified to ensure that we dirty an entire rt extent at once so that we can remap a full rt extent. Use the existing VFS unshare functions to dirty the page cache to set that up. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs/xfs/xfs_iops.c')
-rw-r--r--fs/xfs/xfs_iops.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 1f7c275ec894..e4ccef86fe28 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -24,6 +24,7 @@
#include "xfs_ioctl.h"
#include "xfs_health.h"
#include "xfs_bmap.h"
+#include "xfs_reflink.h"
#include <linux/posix_acl.h>
#include <linux/security.h>
@@ -935,10 +936,24 @@ xfs_setattr_size(
* truncate.
*/
if (newsize > oldsize) {
+ if (xfs_inode_needs_cow_around(ip)) {
+ error = xfs_file_cow_around(ip, oldsize,
+ newsize - oldsize);
+ if (error)
+ return error;
+ }
+
trace_xfs_zero_eof(ip, oldsize, newsize - oldsize);
error = iomap_zero_range(inode, oldsize, newsize - oldsize,
&did_zeroing, &xfs_buffered_write_iomap_ops);
} else {
+ if (xfs_inode_needs_cow_around(ip)) {
+ error = xfs_file_cow_around(ip, newsize,
+ oldsize - newsize);
+ if (error)
+ return error;
+ }
+
/*
* iomap won't detect a dirty page over an unwritten block (or a
* cow block over a hole) and subsequently skips zeroing the