]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: support more than 2^32 owners per physical block
authorDarrick J. Wong <djwong@djwong.org>
Mon, 15 Apr 2024 23:07:50 +0000 (16:07 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 17 Apr 2024 21:06:28 +0000 (14:06 -0700)
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>
repair/rmap.c
repair/rmap.h

index c908429c9bf75b494bf1fee449ad9721d7d0d3bc..032bf494250ad8fae479e655e356c87264a198ee 100644 (file)
@@ -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);
index b074e2e878603cd9111f5fa932d6d27319d7a83c..1bc8c127d0e5a6e60a5904fcd729504a2e686bc2 100644 (file)
@@ -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);