]> git.apps.os.sepia.ceph.com Git - xfsprogs-dev.git/commitdiff
xfs: repair refcount btrees
authorDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 23:07:38 +0000 (16:07 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 17 Apr 2024 21:06:25 +0000 (14:06 -0700)
Source kernel commit: 9099cd38002f8029c9a1da08e6832d1cd18e8451

Reconstruct the refcount data from the rmap btree.

Link: https://docs.kernel.org/filesystems/xfs-online-fsck-design.html#case-study-rebuilding-the-space-reference-counts
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Bill O'Donnell <bodonnel@redhat.com>
libxfs/xfs_ag.h
libxfs/xfs_btree.c
libxfs/xfs_btree.h
libxfs/xfs_refcount.c
libxfs/xfs_refcount.h
libxfs/xfs_refcount_btree.c

index f16cb7a174d40094a31fed5f3699c505fb1584e9..67c3260ee789f821b9ab801d56da49db501f7230 100644 (file)
@@ -87,6 +87,7 @@ struct xfs_perag {
         * verifiers while rebuilding the AG btrees.
         */
        uint8_t         pagf_repair_levels[XFS_BTNUM_AGF];
+       uint8_t         pagf_repair_refcount_level;
 #endif
 
        spinlock_t      pag_state_lock;
index 97962fc16ec47581fa0c451cd5828f76404c15c3..0022bb641bee8ae54dd8c83bb4bec88bde1b0d21 100644 (file)
@@ -5209,3 +5209,29 @@ xfs_btree_destroy_cur_caches(void)
        xfs_rmapbt_destroy_cur_cache();
        xfs_refcountbt_destroy_cur_cache();
 }
+
+/* Move the btree cursor before the first record. */
+int
+xfs_btree_goto_left_edge(
+       struct xfs_btree_cur    *cur)
+{
+       int                     stat = 0;
+       int                     error;
+
+       memset(&cur->bc_rec, 0, sizeof(cur->bc_rec));
+       error = xfs_btree_lookup(cur, XFS_LOOKUP_LE, &stat);
+       if (error)
+               return error;
+       if (!stat)
+               return 0;
+
+       error = xfs_btree_decrement(cur, 0, &stat);
+       if (error)
+               return error;
+       if (stat != 0) {
+               ASSERT(0);
+               return -EFSCORRUPTED;
+       }
+
+       return 0;
+}
index e0875cec4939255cfd579032c3e8c71e58ea05d0..d906324e25c860f7ee89aa56c7267a4fe2e1ed49 100644 (file)
@@ -738,4 +738,6 @@ xfs_btree_alloc_cursor(
 int __init xfs_btree_init_cur_caches(void);
 void xfs_btree_destroy_cur_caches(void);
 
+int xfs_btree_goto_left_edge(struct xfs_btree_cur *cur);
+
 #endif /* __XFS_BTREE_H__ */
index 45f8134e4314aa43e47dd1f60c758e14219ac981..3377fac1283b73dbc511a1bee35a1ed4f46e1158 100644 (file)
@@ -122,11 +122,9 @@ xfs_refcount_btrec_to_irec(
 /* Simple checks for refcount records. */
 xfs_failaddr_t
 xfs_refcount_check_irec(
-       struct xfs_btree_cur            *cur,
+       struct xfs_perag                *pag,
        const struct xfs_refcount_irec  *irec)
 {
-       struct xfs_perag                *pag = cur->bc_ag.pag;
-
        if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
                return __this_address;
 
@@ -178,7 +176,7 @@ xfs_refcount_get_rec(
                return error;
 
        xfs_refcount_btrec_to_irec(rec, irec);
-       fa = xfs_refcount_check_irec(cur, irec);
+       fa = xfs_refcount_check_irec(cur->bc_ag.pag, irec);
        if (fa)
                return xfs_refcount_complain_bad_rec(cur, fa, irec);
 
@@ -1898,7 +1896,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(cur, &rr->rr_rrec) != NULL ||
+       if (xfs_refcount_check_irec(cur->bc_ag.pag, &rr->rr_rrec) != NULL ||
            XFS_IS_CORRUPT(cur->bc_mp,
                           rr->rr_rrec.rc_domain != XFS_REFC_DOMAIN_COW)) {
                kfree(rr);
index 783cd89ca1951c634c36efad3cf8168dd4c88923..5c207f1c619c71ab3101c58823ab756cfb5bf564 100644 (file)
@@ -117,7 +117,7 @@ extern int xfs_refcount_has_records(struct xfs_btree_cur *cur,
 union xfs_btree_rec;
 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_btree_cur *cur,
+xfs_failaddr_t xfs_refcount_check_irec(struct xfs_perag *pag,
                const struct xfs_refcount_irec *irec);
 extern int xfs_refcount_insert(struct xfs_btree_cur *cur,
                struct xfs_refcount_irec *irec, int *stat);
index bc8bd867eee730691c83661a84559cb1396d8176..ac1c3ab868e01c2f1ec47864c4fd70c4494958da 100644 (file)
@@ -225,7 +225,18 @@ xfs_refcountbt_verify(
 
        level = be16_to_cpu(block->bb_level);
        if (pag && xfs_perag_initialised_agf(pag)) {
-               if (level >= pag->pagf_refcount_level)
+               unsigned int    maxlevel = pag->pagf_refcount_level;
+
+#ifdef CONFIG_XFS_ONLINE_REPAIR
+               /*
+                * Online repair could be rewriting the refcount btree, so
+                * we'll validate against the larger of either tree while this
+                * is going on.
+                */
+               maxlevel = max_t(unsigned int, maxlevel,
+                               pag->pagf_repair_refcount_level);
+#endif
+               if (level >= maxlevel)
                        return __this_address;
        } else if (level >= mp->m_refc_maxlevels)
                return __this_address;