[PATCH 4/8] xfs_repair: support more than 2^32 owners per physical block

Darrick J. Wong
2024-03-13T02:15:43Z

From: Darrick J. Wong <djwong@djwong.org>

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@djwong.org>
---
repair/rmap.c | 18 +++++++++---------
repair/rmap.h | 2 +-
2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/repair/rmap.c b/repair/rmap.c
index c908429c9bf7..564e1cbf294e 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,9 @@ refcount_emit(
agno, agbno, len, nr_rmaps);
rlrec.rc_startblock = agbno;
rlrec.rc_blockcount = len;
- rlrec.rc_refcount = REFCOUNT_CLAMP(nr_rmaps);
+ if (nr_rmaps > MAXREFCOUNT)
+ nr_rmaps = MAXREFCOUNT;
+ rlrec.rc_refcount = nr_rmaps;
rlrec.rc_domain = XFS_REFC_DOMAIN_SHARED;

error = slab_add(rlslab, &rlrec);
@@ -741,7 +742,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 +758,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 +1312,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);