xfs: fix reflink quota reservation accounting error

Quota reservations are supposed to account for the blocks that might be
allocated due to a bmap btree split.  Reflink doesn't do this, so fix
this to make the quota accounting more accurate before we start
rearranging things.

Fixes: 862bb360ef ("xfs: reflink extents from one file to another")
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
This commit is contained in:
Darrick J. Wong 2020-06-29 14:47:18 -07:00
parent eb0efe5063
commit 83895227ab
1 changed files with 14 additions and 7 deletions

View File

@ -1003,6 +1003,7 @@ xfs_reflink_remap_extent(
xfs_filblks_t rlen;
xfs_filblks_t unmap_len;
xfs_off_t newlen;
int64_t qres;
int error;
unmap_len = irec->br_startoff + irec->br_blockcount - destoff;
@ -1025,13 +1026,19 @@ xfs_reflink_remap_extent(
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0);
/* If we're not just clearing space, then do we have enough quota? */
if (real_extent) {
error = xfs_trans_reserve_quota_nblks(tp, ip,
irec->br_blockcount, 0, XFS_QMOPT_RES_REGBLKS);
if (error)
goto out_cancel;
}
/*
* Reserve quota for this operation. We don't know if the first unmap
* in the dest file will cause a bmap btree split, so we always reserve
* at least enough blocks for that split. If the extent being mapped
* in is written, we need to reserve quota for that too.
*/
qres = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK);
if (real_extent)
qres += irec->br_blockcount;
error = xfs_trans_reserve_quota_nblks(tp, ip, qres, 0,
XFS_QMOPT_RES_REGBLKS);
if (error)
goto out_cancel;
trace_xfs_reflink_remap(ip, irec->br_startoff,
irec->br_blockcount, irec->br_startblock);