Commit 3802a345 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Darrick J. Wong

xfs: only reclaim unwritten COW extents periodically

We only want to reclaim preallocations from our periodic work item.
Currently this is archived by looking for a dirty inode, but that check
is rather fragile.  Instead add a flag to xfs_reflink_cancel_cow_* so
that the caller can ask for just cancelling unwritten extents in the COW
fork.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
[darrick: fix typos in commit message]
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
parent c771c14b
...@@ -293,7 +293,7 @@ xfs_end_io( ...@@ -293,7 +293,7 @@ xfs_end_io(
goto done; goto done;
if (ioend->io_bio->bi_error) { if (ioend->io_bio->bi_error) {
error = xfs_reflink_cancel_cow_range(ip, error = xfs_reflink_cancel_cow_range(ip,
ioend->io_offset, ioend->io_size); ioend->io_offset, ioend->io_size, true);
goto done; goto done;
} }
error = xfs_reflink_end_cow(ip, ioend->io_offset, error = xfs_reflink_end_cow(ip, ioend->io_offset,
......
...@@ -1608,7 +1608,7 @@ xfs_inode_free_cowblocks( ...@@ -1608,7 +1608,7 @@ xfs_inode_free_cowblocks(
xfs_ilock(ip, XFS_IOLOCK_EXCL); xfs_ilock(ip, XFS_IOLOCK_EXCL);
xfs_ilock(ip, XFS_MMAPLOCK_EXCL); xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
ret = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF); ret = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF, false);
xfs_iunlock(ip, XFS_MMAPLOCK_EXCL); xfs_iunlock(ip, XFS_MMAPLOCK_EXCL);
xfs_iunlock(ip, XFS_IOLOCK_EXCL); xfs_iunlock(ip, XFS_IOLOCK_EXCL);
......
...@@ -1615,7 +1615,7 @@ xfs_itruncate_extents( ...@@ -1615,7 +1615,7 @@ xfs_itruncate_extents(
/* Remove all pending CoW reservations. */ /* Remove all pending CoW reservations. */
error = xfs_reflink_cancel_cow_blocks(ip, &tp, first_unmap_block, error = xfs_reflink_cancel_cow_blocks(ip, &tp, first_unmap_block,
last_block); last_block, true);
if (error) if (error)
goto out; goto out;
......
...@@ -548,14 +548,18 @@ xfs_reflink_trim_irec_to_next_cow( ...@@ -548,14 +548,18 @@ xfs_reflink_trim_irec_to_next_cow(
} }
/* /*
* Cancel all pending CoW reservations for some block range of an inode. * Cancel CoW reservations for some block range of an inode.
*
* If cancel_real is true this function cancels all COW fork extents for the
* inode; if cancel_real is false, real extents are not cleared.
*/ */
int int
xfs_reflink_cancel_cow_blocks( xfs_reflink_cancel_cow_blocks(
struct xfs_inode *ip, struct xfs_inode *ip,
struct xfs_trans **tpp, struct xfs_trans **tpp,
xfs_fileoff_t offset_fsb, xfs_fileoff_t offset_fsb,
xfs_fileoff_t end_fsb) xfs_fileoff_t end_fsb,
bool cancel_real)
{ {
struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
struct xfs_bmbt_irec got, del; struct xfs_bmbt_irec got, del;
...@@ -579,7 +583,7 @@ xfs_reflink_cancel_cow_blocks( ...@@ -579,7 +583,7 @@ xfs_reflink_cancel_cow_blocks(
&idx, &got, &del); &idx, &got, &del);
if (error) if (error)
break; break;
} else { } else if (del.br_state == XFS_EXT_UNWRITTEN || cancel_real) {
xfs_trans_ijoin(*tpp, ip, 0); xfs_trans_ijoin(*tpp, ip, 0);
xfs_defer_init(&dfops, &firstfsb); xfs_defer_init(&dfops, &firstfsb);
...@@ -621,13 +625,17 @@ xfs_reflink_cancel_cow_blocks( ...@@ -621,13 +625,17 @@ xfs_reflink_cancel_cow_blocks(
} }
/* /*
* Cancel all pending CoW reservations for some byte range of an inode. * Cancel CoW reservations for some byte range of an inode.
*
* If cancel_real is true this function cancels all COW fork extents for the
* inode; if cancel_real is false, real extents are not cleared.
*/ */
int int
xfs_reflink_cancel_cow_range( xfs_reflink_cancel_cow_range(
struct xfs_inode *ip, struct xfs_inode *ip,
xfs_off_t offset, xfs_off_t offset,
xfs_off_t count) xfs_off_t count,
bool cancel_real)
{ {
struct xfs_trans *tp; struct xfs_trans *tp;
xfs_fileoff_t offset_fsb; xfs_fileoff_t offset_fsb;
...@@ -653,7 +661,8 @@ xfs_reflink_cancel_cow_range( ...@@ -653,7 +661,8 @@ xfs_reflink_cancel_cow_range(
xfs_trans_ijoin(tp, ip, 0); xfs_trans_ijoin(tp, ip, 0);
/* Scrape out the old CoW reservations */ /* Scrape out the old CoW reservations */
error = xfs_reflink_cancel_cow_blocks(ip, &tp, offset_fsb, end_fsb); error = xfs_reflink_cancel_cow_blocks(ip, &tp, offset_fsb, end_fsb,
cancel_real);
if (error) if (error)
goto out_cancel; goto out_cancel;
...@@ -1450,7 +1459,7 @@ xfs_reflink_clear_inode_flag( ...@@ -1450,7 +1459,7 @@ xfs_reflink_clear_inode_flag(
* We didn't find any shared blocks so turn off the reflink flag. * We didn't find any shared blocks so turn off the reflink flag.
* First, get rid of any leftover CoW mappings. * First, get rid of any leftover CoW mappings.
*/ */
error = xfs_reflink_cancel_cow_blocks(ip, tpp, 0, NULLFILEOFF); error = xfs_reflink_cancel_cow_blocks(ip, tpp, 0, NULLFILEOFF, true);
if (error) if (error)
return error; return error;
......
...@@ -39,9 +39,9 @@ extern void xfs_reflink_trim_irec_to_next_cow(struct xfs_inode *ip, ...@@ -39,9 +39,9 @@ extern void xfs_reflink_trim_irec_to_next_cow(struct xfs_inode *ip,
extern int xfs_reflink_cancel_cow_blocks(struct xfs_inode *ip, extern int xfs_reflink_cancel_cow_blocks(struct xfs_inode *ip,
struct xfs_trans **tpp, xfs_fileoff_t offset_fsb, struct xfs_trans **tpp, xfs_fileoff_t offset_fsb,
xfs_fileoff_t end_fsb); xfs_fileoff_t end_fsb, bool cancel_real);
extern int xfs_reflink_cancel_cow_range(struct xfs_inode *ip, xfs_off_t offset, extern int xfs_reflink_cancel_cow_range(struct xfs_inode *ip, xfs_off_t offset,
xfs_off_t count); xfs_off_t count, bool cancel_real);
extern int xfs_reflink_end_cow(struct xfs_inode *ip, xfs_off_t offset, extern int xfs_reflink_end_cow(struct xfs_inode *ip, xfs_off_t offset,
xfs_off_t count); xfs_off_t count);
extern int xfs_reflink_recover_cow(struct xfs_mount *mp); extern int xfs_reflink_recover_cow(struct xfs_mount *mp);
......
...@@ -953,7 +953,7 @@ xfs_fs_destroy_inode( ...@@ -953,7 +953,7 @@ xfs_fs_destroy_inode(
XFS_STATS_INC(ip->i_mount, vn_remove); XFS_STATS_INC(ip->i_mount, vn_remove);
if (xfs_is_reflink_inode(ip)) { if (xfs_is_reflink_inode(ip)) {
error = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF); error = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF, true);
if (error && !XFS_FORCED_SHUTDOWN(ip->i_mount)) if (error && !XFS_FORCED_SHUTDOWN(ip->i_mount))
xfs_warn(ip->i_mount, xfs_warn(ip->i_mount,
"Error %d while evicting CoW blocks for inode %llu.", "Error %d while evicting CoW blocks for inode %llu.",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment