xfs: don't be so eager to clear the cowblocks tag on truncate
Currently, xfs_itruncate_extents clears the cowblocks tag if i_cnextents is zero. This is wrong, since i_cnextents only tracks real extents in the CoW fork, which means that we could have some delayed CoW reservations still in there that will now never get cleaned. Fix a further bug where we /don't/ clear the reflink iflag if there are any attribute blocks -- really, it's only safe to clear the reflink flag if there are no data fork extents and no cow fork extents. Found by adding clonerange to fsstress in xfs/017. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Родитель
91aae6be41
Коммит
363e59baa4
|
@ -1487,6 +1487,24 @@ xfs_link(
|
|||
return error;
|
||||
}
|
||||
|
||||
/* Clear the reflink flag and the cowblocks tag if possible. */
|
||||
static void
|
||||
xfs_itruncate_clear_reflink_flags(
|
||||
struct xfs_inode *ip)
|
||||
{
|
||||
struct xfs_ifork *dfork;
|
||||
struct xfs_ifork *cfork;
|
||||
|
||||
if (!xfs_is_reflink_inode(ip))
|
||||
return;
|
||||
dfork = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
|
||||
cfork = XFS_IFORK_PTR(ip, XFS_COW_FORK);
|
||||
if (dfork->if_bytes == 0 && cfork->if_bytes == 0)
|
||||
ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK;
|
||||
if (cfork->if_bytes == 0)
|
||||
xfs_inode_clear_cowblocks_tag(ip);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up the underlying blocks past new_size. The new size must be smaller
|
||||
* than the current size. This routine can be used both for the attribute and
|
||||
|
@ -1583,15 +1601,7 @@ xfs_itruncate_extents(
|
|||
if (error)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Clear the reflink flag if there are no data fork blocks and
|
||||
* there are no extents staged in the cow fork.
|
||||
*/
|
||||
if (xfs_is_reflink_inode(ip) && ip->i_cnextents == 0) {
|
||||
if (ip->i_d.di_nblocks == 0)
|
||||
ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK;
|
||||
xfs_inode_clear_cowblocks_tag(ip);
|
||||
}
|
||||
xfs_itruncate_clear_reflink_flags(ip);
|
||||
|
||||
/*
|
||||
* Always re-log the inode so that our permanent transaction can keep
|
||||
|
|
Загрузка…
Ссылка в новой задаче