From: Darrick J. Wong <darrick.wong@xxxxxxxxxx> Reflink should force the log out to disk if the filesystem was mounted with wsync, the same as most other operations in xfs. Fixes: 3fc9f5e409319 ("xfs: remove xfs_reflink_remap_range") Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --- fs/xfs/xfs_file.c | 21 +++++++++++++++++++-- fs/xfs/xfs_reflink.c | 15 ++++++++++++++- fs/xfs/xfs_reflink.h | 3 ++- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index b8a4a3f29b36..17bdc5bbc2ae 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -1029,8 +1029,10 @@ xfs_file_remap_range( struct inode *inode_out = file_inode(file_out); struct xfs_inode *dest = XFS_I(inode_out); struct xfs_mount *mp = src->i_mount; + xfs_lsn_t sync_lsn = 0; loff_t remapped = 0; xfs_extlen_t cowextsize; + bool need_sync; int ret; if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) @@ -1068,13 +1070,28 @@ xfs_file_remap_range( cowextsize = src->i_d.di_cowextsize; ret = xfs_reflink_update_dest(dest, pos_out + len, cowextsize, - remap_flags); + remap_flags, &need_sync); + if (ret) + goto out_unlock; + + /* + * If this is a synchronous mount and xfs_reflink_update_dest didn't + * already take care of this, make sure that the transaction goes to + * disk before returning to the user. + */ + if (need_sync && xfs_ipincount(dest)) + sync_lsn = dest->i_itemp->ili_last_lsn; out_unlock: xfs_reflink_remap_unlock(file_in, file_out); if (ret) trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_); - return remapped > 0 ? remapped : ret; + if (remapped > 0) { + if (sync_lsn) + xfs_log_force_lsn(mp, sync_lsn, XFS_LOG_SYNC, NULL); + return remapped; + } + return ret; } STATIC int diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index b0ce04ffd3cd..4f148d58ff98 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -919,12 +919,19 @@ xfs_reflink_update_dest( struct xfs_inode *dest, xfs_off_t newlen, xfs_extlen_t cowextsize, - unsigned int remap_flags) + unsigned int remap_flags, + bool *need_sync) { struct xfs_mount *mp = dest->i_mount; struct xfs_trans *tp; int error; + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + */ + *need_sync = (mp->m_flags & XFS_MOUNT_WSYNC); + if (newlen <= i_size_read(VFS_I(dest)) && cowextsize == 0) return 0; @@ -948,6 +955,12 @@ xfs_reflink_update_dest( xfs_trans_log_inode(tp, dest, XFS_ILOG_CORE); + /* We can force the transaction to disk here. */ + if (*need_sync) { + xfs_trans_set_sync(tp); + *need_sync = false; + } + error = xfs_trans_commit(tp); if (error) goto out_error; diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h index 3e4fd46373ab..e9b505e0ad7a 100644 --- a/fs/xfs/xfs_reflink.h +++ b/fs/xfs/xfs_reflink.h @@ -55,7 +55,8 @@ extern int xfs_reflink_remap_blocks(struct xfs_inode *src, loff_t pos_in, struct xfs_inode *dest, loff_t pos_out, loff_t remap_len, loff_t *remapped); extern int xfs_reflink_update_dest(struct xfs_inode *dest, xfs_off_t newlen, - xfs_extlen_t cowextsize, unsigned int remap_flags); + xfs_extlen_t cowextsize, unsigned int remap_flags, + bool *need_sync); extern void xfs_reflink_remap_unlock(struct file *file_in, struct file *file_out);