xfs: only reclaim unwritten COW extents periodically

commit 3802a34532 upstream.

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: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
[darrick: fix typos in commit message]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Christoph Hellwig 2017-03-07 16:45:58 -08:00 committed by Greg Kroah-Hartman
parent a240293694
commit 3b83a02af2
6 changed files with 22 additions and 13 deletions

View file

@ -298,7 +298,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,

View file

@ -1610,7 +1610,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);

View file

@ -1624,7 +1624,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;

View file

@ -571,14 +571,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, prev, del; struct xfs_bmbt_irec got, prev, del;
@ -605,7 +609,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);
@ -648,13 +652,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;
@ -680,7 +688,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;
@ -1686,7 +1695,7 @@ next:
* 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;

View file

@ -39,9 +39,9 @@ extern int 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);

View file

@ -948,7 +948,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.",