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:
parent
a240293694
commit
3b83a02af2
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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.",
|
||||||
|
|
Loading…
Reference in a new issue