diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-09-01 11:19:50 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-10-22 16:41:12 -0700 |
commit | 1111f3c7992ffef84fdec231734676e3bca4d83d (patch) | |
tree | 50e3150b83ab53e872c1869e945f0bfe526d260c /fs/xfs/xfs_iops.c | |
parent | 40863d13b2ca04910de4eddb87c278f6ce0b42ad (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.c | 15 |
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 |