From: Darrick J. Wong <djwong@xxxxxxxxxx> Now that the incore structures handle more than 2^32 records correctly, fix the refcountbt generation code to handle the case of that many rmap records pointing to a piece of space in an AG. This fixes the problem where the refcountbt cannot be rebuilt properly because of integer truncation if there are more than 4.3 billion owners of a piece of space. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> Reviewed-by: Christoph Hellwig <hch@xxxxxx> --- v24.5.1: use min() instead of open coding it --- repair/rmap.c | 17 ++++++++--------- repair/rmap.h | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/repair/rmap.c b/repair/rmap.c index c908429c9bf7..032bf494250a 100644 --- a/repair/rmap.c +++ b/repair/rmap.c @@ -713,14 +713,13 @@ mark_inode_rl( /* * Emit a refcount object for refcntbt reconstruction during phase 5. */ -#define REFCOUNT_CLAMP(nr) ((nr) > MAXREFCOUNT ? MAXREFCOUNT : (nr)) static void refcount_emit( - struct xfs_mount *mp, + struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno, xfs_extlen_t len, - size_t nr_rmaps) + uint64_t nr_rmaps) { struct xfs_refcount_irec rlrec; int error; @@ -733,7 +732,8 @@ refcount_emit( agno, agbno, len, nr_rmaps); rlrec.rc_startblock = agbno; rlrec.rc_blockcount = len; - rlrec.rc_refcount = REFCOUNT_CLAMP(nr_rmaps); + nr_rmaps = min(nr_rmaps, MAXREFCOUNT); + rlrec.rc_refcount = nr_rmaps; rlrec.rc_domain = XFS_REFC_DOMAIN_SHARED; error = slab_add(rlslab, &rlrec); @@ -741,7 +741,6 @@ refcount_emit( do_error( _("Insufficient memory while recreating refcount tree.")); } -#undef REFCOUNT_CLAMP /* * Transform a pile of physical block mapping observations into refcount data @@ -758,11 +757,11 @@ compute_refcounts( struct xfs_slab_cursor *rmaps_cur; struct xfs_rmap_irec *array_cur; struct xfs_rmap_irec *rmap; + uint64_t n, idx; + uint64_t old_stack_nr; xfs_agblock_t sbno; /* first bno of this rmap set */ xfs_agblock_t cbno; /* first bno of this refcount set */ xfs_agblock_t nbno; /* next bno where rmap set changes */ - size_t n, idx; - size_t old_stack_nr; int error; if (!xfs_has_reflink(mp)) @@ -1312,9 +1311,9 @@ _("Unable to fix reflink flag on inode %"PRIu64".\n"), /* * Return the number of refcount objects for an AG. */ -size_t +uint64_t refcount_record_count( - struct xfs_mount *mp, + struct xfs_mount *mp, xfs_agnumber_t agno) { return slab_count(ag_rmaps[agno].ar_refcount_items); diff --git a/repair/rmap.h b/repair/rmap.h index b074e2e87860..1bc8c127d0e5 100644 --- a/repair/rmap.h +++ b/repair/rmap.h @@ -37,7 +37,7 @@ extern void rmap_high_key_from_rec(struct xfs_rmap_irec *rec, struct xfs_rmap_irec *key); extern int compute_refcounts(struct xfs_mount *, xfs_agnumber_t); -extern size_t refcount_record_count(struct xfs_mount *, xfs_agnumber_t); +uint64_t refcount_record_count(struct xfs_mount *mp, xfs_agnumber_t agno); extern int init_refcount_cursor(xfs_agnumber_t, struct xfs_slab_cursor **); extern void refcount_avoid_check(void); void check_refcounts(struct xfs_mount *mp, xfs_agnumber_t agno);