[PATCH RFC 05/10] xfs: Reflink CoW-based atomic write support

From: John Garry
Date: Tue Feb 04 2025 - 07:05:13 EST


For CoW-based atomic write support, always allocate a cow hole in
xfs_reflink_allocate_cow() to write the new data.

Signed-off-by: John Garry <john.g.garry@xxxxxxxxxx>
---
fs/xfs/xfs_iomap.c | 2 +-
fs/xfs/xfs_reflink.c | 12 +++++++-----
fs/xfs/xfs_reflink.h | 2 +-
3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 50fa3ef89f6c..ae3755ed00e6 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -865,7 +865,7 @@ xfs_direct_write_iomap_begin(
/* may drop and re-acquire the ilock */
error = xfs_reflink_allocate_cow(ip, &imap, &cmap, &shared,
&lockmode,
- (flags & IOMAP_DIRECT) || IS_DAX(inode));
+ (flags & IOMAP_DIRECT) || IS_DAX(inode), false);
if (error)
goto out_unlock;
if (shared)
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index b28fb632b9e6..dbce333b60eb 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -435,7 +435,8 @@ xfs_reflink_fill_cow_hole(
struct xfs_bmbt_irec *cmap,
bool *shared,
uint *lockmode,
- bool convert_now)
+ bool convert_now,
+ bool atomic)
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_trans *tp;
@@ -466,7 +467,7 @@ xfs_reflink_fill_cow_hole(
*lockmode = XFS_ILOCK_EXCL;

error = xfs_find_trim_cow_extent(ip, imap, cmap, shared, &found);
- if (error || !*shared)
+ if (error || (!*shared && !atomic))
goto out_trans_cancel;

if (found) {
@@ -566,7 +567,8 @@ xfs_reflink_allocate_cow(
struct xfs_bmbt_irec *cmap,
bool *shared,
uint *lockmode,
- bool convert_now)
+ bool convert_now,
+ bool atomic)
{
int error;
bool found;
@@ -578,7 +580,7 @@ xfs_reflink_allocate_cow(
}

error = xfs_find_trim_cow_extent(ip, imap, cmap, shared, &found);
- if (error || !*shared)
+ if (error || (!*shared && !atomic))
return error;

/* CoW fork has a real extent */
@@ -592,7 +594,7 @@ xfs_reflink_allocate_cow(
*/
if (cmap->br_startoff > imap->br_startoff)
return xfs_reflink_fill_cow_hole(ip, imap, cmap, shared,
- lockmode, convert_now);
+ lockmode, convert_now, atomic);

/*
* CoW fork has a delalloc reservation. Replace it with a real extent.
diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h
index a328b25e68da..ef5c8b2398d8 100644
--- a/fs/xfs/xfs_reflink.h
+++ b/fs/xfs/xfs_reflink.h
@@ -32,7 +32,7 @@ int xfs_bmap_trim_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap,

int xfs_reflink_allocate_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap,
struct xfs_bmbt_irec *cmap, bool *shared, uint *lockmode,
- bool convert_now);
+ bool convert_now, bool atomic);
extern int xfs_reflink_convert_cow(struct xfs_inode *ip, xfs_off_t offset,
xfs_off_t count);
int xfs_find_trim_cow_extent(struct xfs_inode *ip, struct xfs_bmbt_irec *imap,
--
2.31.1