xfs_repair: support more than 2^32 owners per physical block
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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
diff --git a/repair/rmap.c b/repair/rmap.c
index c908429..032bf49 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -713,14 +713,13 @@
/*
* 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 @@
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 @@
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 @@
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 @@
/*
* 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 b074e2e..1bc8c12 100644
--- a/repair/rmap.h
+++ b/repair/rmap.h
@@ -37,7 +37,7 @@
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);