]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: prepare refcount functions to deal with rtrefcountbt
authorDarrick J. Wong <djwong@kernel.org>
Mon, 23 Sep 2024 20:42:25 +0000 (13:42 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 2 Oct 2024 01:11:02 +0000 (18:11 -0700)
Prepare the high-level refcount functions to deal with the new realtime
refcountbt and its slightly different conventions.  Provide the ability
to talk to either refcountbt or rtrefcountbt formats from the same high
level code.

Note that we leave the _recover_cow_leftovers functions for a separate
patch so that we can convert it all at once.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
fs/xfs/libxfs/xfs_refcount.c
fs/xfs/libxfs/xfs_refcount.h

index 4f0281c6baa5c653cd946668d0603618dcb32cdf..7468256f7dffa6fb98b6256ceaa8ad01cc6f65f9 100644 (file)
@@ -25,6 +25,7 @@
 #include "xfs_ag.h"
 #include "xfs_health.h"
 #include "xfs_refcount_item.h"
+#include "xfs_rtgroup.h"
 
 struct kmem_cache      *xfs_refcount_intent_cache;
 
@@ -41,6 +42,16 @@ STATIC int __xfs_refcount_cow_alloc(struct xfs_btree_cur *rcur,
 STATIC int __xfs_refcount_cow_free(struct xfs_btree_cur *rcur,
                xfs_agblock_t agbno, xfs_extlen_t aglen);
 
+/* Return the maximum startblock number of the refcountbt. */
+static inline xfs_agblock_t
+xrefc_max_startblock(
+       struct xfs_btree_cur    *cur)
+{
+       if (xfs_btree_is_rtrefcount(cur->bc_ops))
+               return cur->bc_mp->m_rgblocks;
+       return cur->bc_mp->m_sb.sb_agblocks;
+}
+
 /*
  * Look up the first record less than or equal to [bno, len] in the btree
  * given by cur.
@@ -144,6 +155,37 @@ xfs_refcount_check_irec(
        return NULL;
 }
 
+xfs_failaddr_t
+xfs_rtrefcount_check_irec(
+       struct xfs_rtgroup              *rtg,
+       const struct xfs_refcount_irec  *irec)
+{
+       if (irec->rc_blockcount == 0 || irec->rc_blockcount > XFS_REFC_LEN_MAX)
+               return __this_address;
+
+       if (!xfs_refcount_check_domain(irec))
+               return __this_address;
+
+       /* check for valid extent range, including overflow */
+       if (!xfs_verify_rgbext(rtg, irec->rc_startblock, irec->rc_blockcount))
+               return __this_address;
+
+       if (irec->rc_refcount == 0 || irec->rc_refcount > XFS_REFC_REFCOUNT_MAX)
+               return __this_address;
+
+       return NULL;
+}
+
+static inline xfs_failaddr_t
+xfs_refcount_check_btrec(
+       struct xfs_btree_cur            *cur,
+       const struct xfs_refcount_irec  *irec)
+{
+       if (xfs_btree_is_rtrefcount(cur->bc_ops))
+               return xfs_rtrefcount_check_irec(to_rtg(cur->bc_group), irec);
+       return xfs_refcount_check_irec(to_perag(cur->bc_group), irec);
+}
+
 static inline int
 xfs_refcount_complain_bad_rec(
        struct xfs_btree_cur            *cur,
@@ -152,9 +194,15 @@ xfs_refcount_complain_bad_rec(
 {
        struct xfs_mount                *mp = cur->bc_mp;
 
-       xfs_warn(mp,
+       if (xfs_btree_is_rtrefcount(cur->bc_ops)) {
+               xfs_warn(mp,
+ "RT Refcount BTree record corruption in rtgroup %u detected at %pS!",
+                               cur->bc_group->xg_index, fa);
+       } else {
+               xfs_warn(mp,
  "Refcount BTree record corruption in AG %d detected at %pS!",
                                cur->bc_group->xg_index, fa);
+       }
        xfs_warn(mp,
                "Start block 0x%x, block count 0x%x, references 0x%x",
                irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount);
@@ -180,7 +228,7 @@ xfs_refcount_get_rec(
                return error;
 
        xfs_refcount_btrec_to_irec(rec, irec);
-       fa = xfs_refcount_check_irec(to_perag(cur->bc_group), irec);
+       fa = xfs_refcount_check_btrec(cur, irec);
        if (fa)
                return xfs_refcount_complain_bad_rec(cur, fa, irec);
 
@@ -1065,7 +1113,7 @@ xfs_refcount_still_have_space(
         */
        overhead = xfs_allocfree_block_count(cur->bc_mp,
                                cur->bc_refc.shape_changes);
-       overhead += cur->bc_mp->m_refc_maxlevels;
+       overhead += cur->bc_maxlevels;
        overhead *= cur->bc_mp->m_sb.sb_blocksize;
 
        /*
@@ -1117,7 +1165,7 @@ xfs_refcount_adjust_extents(
                if (error)
                        goto out_error;
                if (!found_rec || ext.rc_domain != XFS_REFC_DOMAIN_SHARED) {
-                       ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks;
+                       ext.rc_startblock = xrefc_max_startblock(cur);
                        ext.rc_blockcount = 0;
                        ext.rc_refcount = 0;
                        ext.rc_domain = XFS_REFC_DOMAIN_SHARED;
@@ -1666,7 +1714,7 @@ xfs_refcount_adjust_cow_extents(
                goto out_error;
        }
        if (!found_rec) {
-               ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks;
+               ext.rc_startblock = xrefc_max_startblock(cur);
                ext.rc_blockcount = 0;
                ext.rc_refcount = 0;
                ext.rc_domain = XFS_REFC_DOMAIN_COW;
@@ -1877,8 +1925,7 @@ xfs_refcount_recover_extent(
        INIT_LIST_HEAD(&rr->rr_list);
        xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec);
 
-       if (xfs_refcount_check_irec(to_perag(cur->bc_group), &rr->rr_rrec) !=
-                       NULL ||
+       if (xfs_refcount_check_btrec(cur, &rr->rr_rrec) != NULL ||
            XFS_IS_CORRUPT(cur->bc_mp,
                           rr->rr_rrec.rc_domain != XFS_REFC_DOMAIN_COW)) {
                xfs_btree_mark_sick(cur);
@@ -2026,7 +2073,7 @@ xfs_refcount_query_range_helper(
        xfs_failaddr_t                  fa;
 
        xfs_refcount_btrec_to_irec(rec, &irec);
-       fa = xfs_refcount_check_irec(to_perag(cur->bc_group), &irec);
+       fa = xfs_refcount_check_btrec(cur, &irec);
        if (fa)
                return xfs_refcount_complain_bad_rec(cur, fa, &irec);
 
index 62d78afcf1f3ff2e1569cd85f50c78365f001816..9cd58d48716f835ac4a177c07a1ffe723e34df9f 100644 (file)
@@ -12,6 +12,7 @@ struct xfs_perag;
 struct xfs_btree_cur;
 struct xfs_bmbt_irec;
 struct xfs_refcount_irec;
+struct xfs_rtgroup;
 
 extern int xfs_refcount_lookup_le(struct xfs_btree_cur *cur,
                enum xfs_refc_domain domain, xfs_agblock_t bno, int *stat);
@@ -120,6 +121,8 @@ extern void xfs_refcount_btrec_to_irec(const union xfs_btree_rec *rec,
                struct xfs_refcount_irec *irec);
 xfs_failaddr_t xfs_refcount_check_irec(struct xfs_perag *pag,
                const struct xfs_refcount_irec *irec);
+xfs_failaddr_t xfs_rtrefcount_check_irec(struct xfs_rtgroup *rtg,
+               const struct xfs_refcount_irec *irec);
 extern int xfs_refcount_insert(struct xfs_btree_cur *cur,
                struct xfs_refcount_irec *irec, int *stat);