When we're freeing blocks (truncate, punch, etc.), clear all CoW reservations in the range being freed. If the file block count drops to zero, also clear the inode reflink flag. Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --- fs/xfs/xfs_bmap_util.c | 34 ++++++++++++++++++++++++++++++++++ fs/xfs/xfs_inode.c | 13 +++++++++++++ 2 files changed, 47 insertions(+) diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 79225fb..9285111 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c @@ -1147,6 +1147,32 @@ xfs_zero_remaining_bytes( return error; } +STATIC int +xfs_free_cow_space( + struct xfs_inode *ip, + struct xfs_trans **tpp, + xfs_fileoff_t startoffset_fsb, + xfs_fileoff_t endoffset_fsb) +{ + int error; + + /* Remove any pending CoW reservations. */ + error = xfs_reflink_cancel_cow_blocks(ip, tpp, startoffset_fsb, + endoffset_fsb); + if (error) + goto out; + + /* + * Clear the reflink flag if we freed everything. + */ + if (ip->i_d.di_nblocks == 0) { + ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; + xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE); + } +out: + return error; +} + int xfs_free_file_space( struct xfs_inode *ip, @@ -1294,6 +1320,14 @@ xfs_free_file_space( if (error) goto error0; + /* Remove CoW reservations and inode flag if applicable. */ + if (done && xfs_is_reflink_inode(ip)) { + error = xfs_free_cow_space(ip, &tp, startoffset_fsb, + endoffset_fsb); + if (error) + goto error0; + } + error = xfs_trans_commit(tp); xfs_iunlock(ip, XFS_ILOCK_EXCL); } diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index e08eaea..b8d3c4f 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -49,6 +49,7 @@ #include "xfs_trans_priv.h" #include "xfs_log.h" #include "xfs_bmap_btree.h" +#include "xfs_reflink.h" kmem_zone_t *xfs_inode_zone; @@ -1586,6 +1587,18 @@ xfs_itruncate_extents( goto out; } + /* Remove all pending CoW reservations. */ + error = xfs_reflink_cancel_cow_blocks(ip, &tp, first_unmap_block, + last_block); + if (error) + goto out; + + /* + * Clear the reflink flag if we truncated everything. + */ + if (ip->i_d.di_nblocks == 0 && xfs_is_reflink_inode(ip)) + ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; + /* * Always re-log the inode so that our permanent transaction can keep * on rolling it forward in the log. -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html