Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b4c1326 authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: treat CoW fork operations as delalloc for quota accounting



Since the CoW fork only exists in memory, it is incorrect to update the
on-disk quota block counts when we modify the CoW fork.  Unlike the data
fork, even real extents in the CoW fork are only delalloc-style
reservations (on-disk they're owned by the refcountbt) so they must not
be tracked in the on disk quota info.  Ensure the i_delayed_blks
accounting reflects this too.

Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 01c2e13d
Loading
Loading
Loading
Loading
+30 −2
Original line number Diff line number Diff line
@@ -3343,7 +3343,34 @@ xfs_bmap_btalloc_accounting(
	struct xfs_bmalloca	*ap,
	struct xfs_alloc_arg	*args)
{
	if (!(ap->flags & XFS_BMAPI_COWFORK))
	if (ap->flags & XFS_BMAPI_COWFORK) {
		/*
		 * COW fork blocks are in-core only and thus are treated as
		 * in-core quota reservation (like delalloc blocks) even when
		 * converted to real blocks. The quota reservation is not
		 * accounted to disk until blocks are remapped to the data
		 * fork. So if these blocks were previously delalloc, we
		 * already have quota reservation and there's nothing to do
		 * yet.
		 */
		if (ap->wasdel)
			return;

		/*
		 * Otherwise, we've allocated blocks in a hole. The transaction
		 * has acquired in-core quota reservation for this extent.
		 * Rather than account these as real blocks, however, we reduce
		 * the transaction quota reservation based on the allocation.
		 * This essentially transfers the transaction quota reservation
		 * to that of a delalloc extent.
		 */
		ap->ip->i_delayed_blks += args->len;
		xfs_trans_mod_dquot_byino(ap->tp, ap->ip, XFS_TRANS_DQ_RES_BLKS,
				-(long)args->len);
		return;
	}

	/* data/attr fork only */
	ap->ip->i_d.di_nblocks += args->len;
	xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
	if (ap->wasdel)
@@ -4820,6 +4847,7 @@ xfs_bmap_del_extent_cow(
		xfs_iext_insert(ip, icur, &new, state);
		break;
	}
	ip->i_delayed_blks -= del->br_blockcount;
}

/*
+11 −4
Original line number Diff line number Diff line
@@ -599,10 +599,6 @@ xfs_reflink_cancel_cow_blocks(
					del.br_startblock, del.br_blockcount,
					NULL);

			/* Update quota accounting */
			xfs_trans_mod_dquot_byino(*tpp, ip, XFS_TRANS_DQ_BCOUNT,
					-(long)del.br_blockcount);

			/* Roll the transaction */
			xfs_defer_ijoin(&dfops, ip);
			error = xfs_defer_finish(tpp, &dfops);
@@ -613,6 +609,13 @@ xfs_reflink_cancel_cow_blocks(

			/* Remove the mapping from the CoW fork. */
			xfs_bmap_del_extent_cow(ip, &icur, &got, &del);

			/* Remove the quota reservation */
			error = xfs_trans_reserve_quota_nblks(NULL, ip,
					-(long)del.br_blockcount, 0,
					XFS_QMOPT_RES_REGBLKS);
			if (error)
				break;
		} else {
			/* Didn't do anything, push cursor back. */
			xfs_iext_prev(ifp, &icur);
@@ -795,6 +798,10 @@ xfs_reflink_end_cow(
		if (error)
			goto out_defer;

		/* Charge this new data fork mapping to the on-disk quota. */
		xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_DELBCOUNT,
				(long)del.br_blockcount);

		/* Remove the mapping from the CoW fork. */
		xfs_bmap_del_extent_cow(ip, &icur, &got, &del);