When we're unmapping blocks from a reflinked file, decrease the refcount of the affected blocks and free the extents that are no longer in use. Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --- fs/xfs/libxfs/xfs_bmap.c | 16 +++++++++++++--- fs/xfs/libxfs/xfs_refcount.c | 42 ++++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_refcount.h | 4 ++++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 5d1290e..6cc4aeb 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -46,6 +46,7 @@ #include "xfs_attr_leaf.h" #include "xfs_filestream.h" #include "xfs_rmap_btree.h" +#include "xfs_refcount.h" kmem_zone_t *xfs_bmap_free_item_zone; @@ -5144,9 +5145,18 @@ xfs_bmap_del_extent( /* * If we need to, add to list of extents to delete. */ - if (do_fx) - xfs_bmap_add_free(mp, flist, del->br_startblock, - del->br_blockcount, NULL); + if (do_fx) { + if (xfs_is_reflink_inode(ip)) { + error = xfs_refcount_put_extent(mp, tp, flist, + del->br_startblock, + del->br_blockcount, NULL); + if (error) + goto done; + } else + xfs_bmap_add_free(mp, flist, del->br_startblock, + del->br_blockcount, NULL); + } + /* * Adjust inode # blocks in the file. */ diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c index dae6453..c9d6e5d 100644 --- a/fs/xfs/libxfs/xfs_refcount.c +++ b/fs/xfs/libxfs/xfs_refcount.c @@ -970,3 +970,45 @@ xfs_refcount_decrease( return xfs_refcountbt_adjust_refcount(mp, tp, agbp, agno, agbno, aglen, -1, flist, oinfo); } + +/** + * xfs_refcount_put_extent() - release a range of blocks + * + * @mp: XFS mount object + * @tp: transaction that goes with the free operation + * @flist: List of blocks to be freed at the end of the transaction + * @fsbno: First fs block of the range to release + * @len: Length of range + * @owner: owner of the extent + */ +int +xfs_refcount_put_extent( + struct xfs_mount *mp, + struct xfs_trans *tp, + struct xfs_bmap_free *flist, + xfs_fsblock_t fsbno, + xfs_filblks_t fslen, + struct xfs_owner_info *oinfo) +{ + int error; + struct xfs_buf *agbp; + xfs_agnumber_t agno; /* allocation group number */ + xfs_agblock_t agbno; /* ag start of range to free */ + xfs_extlen_t aglen; /* ag length of range to free */ + + agno = XFS_FSB_TO_AGNO(mp, fsbno); + agbno = XFS_FSB_TO_AGBNO(mp, fsbno); + aglen = fslen; + + /* + * Drop reference counts in the refcount tree. + */ + error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); + if (error) + return error; + + error = xfs_refcount_decrease(mp, tp, agbp, agno, agbno, aglen, flist, + oinfo); + xfs_trans_brelse(tp, agbp); + return error; +} diff --git a/fs/xfs/libxfs/xfs_refcount.h b/fs/xfs/libxfs/xfs_refcount.h index 6640e3d..074d620 100644 --- a/fs/xfs/libxfs/xfs_refcount.h +++ b/fs/xfs/libxfs/xfs_refcount.h @@ -34,4 +34,8 @@ extern int xfs_refcount_decrease(struct xfs_mount *mp, struct xfs_trans *tp, xfs_extlen_t aglen, struct xfs_bmap_free *flist, struct xfs_owner_info *oinfo); +extern int xfs_refcount_put_extent(struct xfs_mount *mp, struct xfs_trans *tp, + struct xfs_bmap_free *flist, xfs_fsblock_t fsbno, + xfs_filblks_t len, struct xfs_owner_info *oinfo); + #endif /* __XFS_REFCOUNT_H__ */ _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs