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

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

xfs: account for the refcount btree in the alloc/free log reservation



Every time we allocate or free a data extent, we might need to split
the refcount btree.  Reserve some blocks in the transaction to handle
this possibility.  Even though the deferred refcount code can roll a
transaction to avoid overloading the transaction, we can still exceed
the reservation.

Certain pathological workloads (1k blocks, no cowextsize hint, random
directio writes), cause a perfect storm wherein a refcount adjustment
of a large range of blocks causes full tree splits in two separate
extents in two separate refcount tree blocks; allocating new refcount
tree blocks causes rmap btree splits; and all the allocation activity
causes the freespace btrees to split, blowing the reservation.

(Reproduced by generic/167 over NFS atop XFS)

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
[darrick.wong@oracle.com: add commit message]
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
parent ac4fef69
Loading
Loading
Loading
Loading
+4 −1
Original line number Original line Diff line number Diff line
@@ -67,7 +67,8 @@ xfs_calc_buf_res(
 * Per-extent log reservation for the btree changes involved in freeing or
 * Per-extent log reservation for the btree changes involved in freeing or
 * allocating an extent.  In classic XFS there were two trees that will be
 * allocating an extent.  In classic XFS there were two trees that will be
 * modified (bnobt + cntbt).  With rmap enabled, there are three trees
 * modified (bnobt + cntbt).  With rmap enabled, there are three trees
 * (rmapbt).  The number of blocks reserved is based on the formula:
 * (rmapbt).  With reflink, there are four trees (refcountbt).  The number of
 * blocks reserved is based on the formula:
 *
 *
 * num trees * ((2 blocks/level * max depth) - 1)
 * num trees * ((2 blocks/level * max depth) - 1)
 *
 *
@@ -83,6 +84,8 @@ xfs_allocfree_log_count(
	blocks = num_ops * 2 * (2 * mp->m_ag_maxlevels - 1);
	blocks = num_ops * 2 * (2 * mp->m_ag_maxlevels - 1);
	if (xfs_sb_version_hasrmapbt(&mp->m_sb))
	if (xfs_sb_version_hasrmapbt(&mp->m_sb))
		blocks += num_ops * (2 * mp->m_rmap_maxlevels - 1);
		blocks += num_ops * (2 * mp->m_rmap_maxlevels - 1);
	if (xfs_sb_version_hasreflink(&mp->m_sb))
		blocks += num_ops * (2 * mp->m_refc_maxlevels - 1);


	return blocks;
	return blocks;
}
}