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>

+19 -9
+19 -9
fs/xfs/xfs_inode.c
··· 1487 return error; 1488 } 1489 1490 /* 1491 * Free up the underlying blocks past new_size. The new size must be smaller 1492 * than the current size. This routine can be used both for the attribute and ··· 1601 if (error) 1602 goto out; 1603 1604 - /* 1605 - * Clear the reflink flag if there are no data fork blocks and 1606 - * there are no extents staged in the cow fork. 1607 - */ 1608 - if (xfs_is_reflink_inode(ip) && ip->i_cnextents == 0) { 1609 - if (ip->i_d.di_nblocks == 0) 1610 - ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; 1611 - xfs_inode_clear_cowblocks_tag(ip); 1612 - } 1613 1614 /* 1615 * Always re-log the inode so that our permanent transaction can keep
··· 1487 return error; 1488 } 1489 1490 + /* Clear the reflink flag and the cowblocks tag if possible. */ 1491 + static void 1492 + xfs_itruncate_clear_reflink_flags( 1493 + struct xfs_inode *ip) 1494 + { 1495 + struct xfs_ifork *dfork; 1496 + struct xfs_ifork *cfork; 1497 + 1498 + if (!xfs_is_reflink_inode(ip)) 1499 + return; 1500 + dfork = XFS_IFORK_PTR(ip, XFS_DATA_FORK); 1501 + cfork = XFS_IFORK_PTR(ip, XFS_COW_FORK); 1502 + if (dfork->if_bytes == 0 && cfork->if_bytes == 0) 1503 + ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; 1504 + if (cfork->if_bytes == 0) 1505 + xfs_inode_clear_cowblocks_tag(ip); 1506 + } 1507 + 1508 /* 1509 * Free up the underlying blocks past new_size. The new size must be smaller 1510 * than the current size. This routine can be used both for the attribute and ··· 1583 if (error) 1584 goto out; 1585 1586 + xfs_itruncate_clear_reflink_flags(ip); 1587 1588 /* 1589 * Always re-log the inode so that our permanent transaction can keep