On Tue, Apr 26, 2022 at 05:51:58PM -0700, Darrick J. Wong wrote: > From: Darrick J. Wong <djwong@xxxxxxxxxx> > > A long time ago, I added to XFS the ability to use deferred reference > count operations as part of a transaction chain. This enabled us to > avoid blowing out the transaction reservation when the blocks in a > physical extent all had different reference counts because we could ask > the deferred operation manager for a continuation, which would get us a > clean transaction. > > The refcount code asks for a continuation when the number of refcount > record updates reaches the point where we think that the transaction has > logged enough full btree blocks due to refcount (and free space) btree > shape changes and refcount record updates that we're in danger of > overflowing the transaction. > > We did not previously count the EFIs logged to the refcount update > transaction because the clamps on the length of a bunmap operation were > sufficient to avoid overflowing the transaction reservation even in the > worst case situation where every other block of the unmapped extent is > shared. > > Unfortunately, the restrictions on bunmap length avoid failure in the > worst case by imposing a maximum unmap length of ~3000 blocks, even for > non-pathological cases. This seriously limits performance when freeing > large extents. > > Therefore, track EFIs with the same counter as refcount record updates, > and use that information as input into when we should ask for a > continuation. This enables the next patch to drop the clumsy bunmap > limitation. > > Depends: 27dada070d59 ("xfs: change the order in which child and parent defer ops ar finished") > Depends: 74f4d6a1e065 ("xfs: only relog deferred intent items if free space in the log gets low") > Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> > Reviewed-by: Dave Chinner <dchinner@xxxxxxxxxx> > --- > fs/xfs/libxfs/xfs_refcount.c | 5 ++--- > fs/xfs/libxfs/xfs_refcount.h | 13 ++++++++----- > 2 files changed, 10 insertions(+), 8 deletions(-) > > > diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c > index 327ba25e9e17..a07ebaecba73 100644 > --- a/fs/xfs/libxfs/xfs_refcount.c > +++ b/fs/xfs/libxfs/xfs_refcount.c > @@ -960,6 +960,7 @@ xfs_refcount_adjust_extents( > * Either cover the hole (increment) or > * delete the range (decrement). > */ > + cur->bc_ag.refc.nr_ops++; > if (tmp.rc_refcount) { > error = xfs_refcount_insert(cur, &tmp, > &found_tmp); > @@ -970,7 +971,6 @@ xfs_refcount_adjust_extents( > error = -EFSCORRUPTED; > goto out_error; > } > - cur->bc_ag.refc.nr_ops++; > } else { > fsbno = XFS_AGB_TO_FSB(cur->bc_mp, > cur->bc_ag.pag->pag_agno, > @@ -1001,11 +1001,11 @@ xfs_refcount_adjust_extents( > ext.rc_refcount += adj; > trace_xfs_refcount_modify_extent(cur->bc_mp, > cur->bc_ag.pag->pag_agno, &ext); > + cur->bc_ag.refc.nr_ops++; > if (ext.rc_refcount > 1) { > error = xfs_refcount_update(cur, &ext); > if (error) > goto out_error; > - cur->bc_ag.refc.nr_ops++; > } else if (ext.rc_refcount == 1) { > error = xfs_refcount_delete(cur, &found_rec); > if (error) > @@ -1014,7 +1014,6 @@ xfs_refcount_adjust_extents( > error = -EFSCORRUPTED; > goto out_error; > } > - cur->bc_ag.refc.nr_ops++; > goto advloop; > } else { > fsbno = XFS_AGB_TO_FSB(cur->bc_mp, > diff --git a/fs/xfs/libxfs/xfs_refcount.h b/fs/xfs/libxfs/xfs_refcount.h > index 9eb01edbd89d..e8b322de7f3d 100644 > --- a/fs/xfs/libxfs/xfs_refcount.h > +++ b/fs/xfs/libxfs/xfs_refcount.h > @@ -67,14 +67,17 @@ extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp, > * log (plus any key updates) so we'll conservatively assume 32 bytes > * per record. We must also leave space for btree splits on both ends > * of the range and space for the CUD and a new CUI. > + * > + * Each EFI that we attach to the transaction is assumed to consume ~32 bytes. > + * This is a low estimate for an EFI tracking a single extent (16 bytes for the > + * EFI header, 16 for the extent, and 12 for the xlog op header), but the > + * estimate is acceptable if there's more than one extent being freed. > + * In the worst case of freeing every other block during a refcount decrease > + * operation, we amortize the space used for one EFI log item across 16 > + * extents. > */ > #define XFS_REFCOUNT_ITEM_OVERHEAD 32 > > -static inline xfs_fileoff_t xfs_refcount_max_unmap(int log_res) > -{ > - return (log_res * 3 / 4) / XFS_REFCOUNT_ITEM_OVERHEAD; > -} Oops, this helper should not have been deleted until the next patch. I'll fix that before I send Dave a pull request. --D > - > extern int xfs_refcount_has_record(struct xfs_btree_cur *cur, > xfs_agblock_t bno, xfs_extlen_t len, bool *exists); > union xfs_btree_rec; >