Skip to content

Commit

Permalink
xfs: only reclaim unwritten COW extents periodically
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Christoph Hellwig authored and Darrick J. Wong committed Mar 8, 2017
1 parent c771c14 commit 3802a34
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 13 deletions.
2 changes: 1 addition & 1 deletion fs/xfs/xfs_aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ xfs_end_io(
goto done;
if (ioend->io_bio->bi_error) {
error = xfs_reflink_cancel_cow_range(ip,
ioend->io_offset, ioend->io_size);
ioend->io_offset, ioend->io_size, true);
goto done;
}
error = xfs_reflink_end_cow(ip, ioend->io_offset,
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_icache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1608,7 +1608,7 @@ xfs_inode_free_cowblocks(
xfs_ilock(ip, XFS_IOLOCK_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_IOLOCK_EXCL);
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1615,7 +1615,7 @@ xfs_itruncate_extents(

/* Remove all pending CoW reservations. */
error = xfs_reflink_cancel_cow_blocks(ip, &tp, first_unmap_block,
last_block);
last_block, true);
if (error)
goto out;

Expand Down
23 changes: 16 additions & 7 deletions fs/xfs/xfs_reflink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
xfs_reflink_cancel_cow_blocks(
struct xfs_inode *ip,
struct xfs_trans **tpp,
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_bmbt_irec got, del;
Expand All @@ -579,7 +583,7 @@ xfs_reflink_cancel_cow_blocks(
&idx, &got, &del);
if (error)
break;
} else {
} else if (del.br_state == XFS_EXT_UNWRITTEN || cancel_real) {
xfs_trans_ijoin(*tpp, ip, 0);
xfs_defer_init(&dfops, &firstfsb);

Expand Down Expand Up @@ -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
xfs_reflink_cancel_cow_range(
struct xfs_inode *ip,
xfs_off_t offset,
xfs_off_t count)
xfs_off_t count,
bool cancel_real)
{
struct xfs_trans *tp;
xfs_fileoff_t offset_fsb;
Expand All @@ -653,7 +661,8 @@ xfs_reflink_cancel_cow_range(
xfs_trans_ijoin(tp, ip, 0);

/* 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)
goto out_cancel;

Expand Down Expand Up @@ -1450,7 +1459,7 @@ xfs_reflink_clear_inode_flag(
* We didn't find any shared blocks so turn off the reflink flag.
* 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)
return error;

Expand Down
4 changes: 2 additions & 2 deletions fs/xfs/xfs_reflink.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
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,
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,
xfs_off_t count);
extern int xfs_reflink_recover_cow(struct xfs_mount *mp);
Expand Down
2 changes: 1 addition & 1 deletion fs/xfs/xfs_super.c
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,7 @@ xfs_fs_destroy_inode(
XFS_STATS_INC(ip->i_mount, vn_remove);

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))
xfs_warn(ip->i_mount,
"Error %d while evicting CoW blocks for inode %llu.",
Expand Down

0 comments on commit 3802a34

Please sign in to comment.