]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: repair the rmapbt
authorDarrick J. Wong <djwong@kernel.org>
Mon, 22 Apr 2024 17:01:11 +0000 (10:01 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 3 Jun 2024 18:37:40 +0000 (11:37 -0700)
Source kernel commit: 32080a9b9b2ef8f4089e8e28a2c307334431757e

Rebuild the reverse mapping btree from all primary metadata.  This first
patch establishes the bare mechanics of finding records and putting
together a new ondisk tree; more complex pieces are needed to make it
work properly.

Link: Documentation/filesystems/xfs-online-fsck-design.rst
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
libxfs/xfs_ag.h
libxfs/xfs_bmap.c
libxfs/xfs_bmap.h
libxfs/xfs_rmap.c
libxfs/xfs_rmap.h
libxfs/xfs_rmap_btree.c

index 29bfa6273decb05b1fa335774d3e6093f9b19195..e019b79dbbe3d5b1c0e90d5cad5fe12ed2040e94 100644 (file)
@@ -90,6 +90,7 @@ struct xfs_perag {
        uint8_t         pagf_repair_bno_level;
        uint8_t         pagf_repair_cnt_level;
        uint8_t         pagf_repair_refcount_level;
+       uint8_t         pagf_repair_rmap_level;
 #endif
 
        spinlock_t      pag_state_lock;
index 85f1deac280755705b97893b92af29d5adc4695c..a82a41249fd3b6ddc7804cef32944d3f680a62e6 100644 (file)
@@ -6373,3 +6373,46 @@ xfs_bunmapi_range(
 out:
        return error;
 }
+
+struct xfs_bmap_query_range {
+       xfs_bmap_query_range_fn fn;
+       void                    *priv;
+};
+
+/* Format btree record and pass to our callback. */
+STATIC int
+xfs_bmap_query_range_helper(
+       struct xfs_btree_cur            *cur,
+       const union xfs_btree_rec       *rec,
+       void                            *priv)
+{
+       struct xfs_bmap_query_range     *query = priv;
+       struct xfs_bmbt_irec            irec;
+       xfs_failaddr_t                  fa;
+
+       xfs_bmbt_disk_get_all(&rec->bmbt, &irec);
+       fa = xfs_bmap_validate_extent(cur->bc_ino.ip, cur->bc_ino.whichfork,
+                       &irec);
+       if (fa) {
+               xfs_btree_mark_sick(cur);
+               return xfs_bmap_complain_bad_rec(cur->bc_ino.ip,
+                               cur->bc_ino.whichfork, fa, &irec);
+       }
+
+       return query->fn(cur, &irec, query->priv);
+}
+
+/* Find all bmaps. */
+int
+xfs_bmap_query_all(
+       struct xfs_btree_cur            *cur,
+       xfs_bmap_query_range_fn         fn,
+       void                            *priv)
+{
+       struct xfs_bmap_query_range     query = {
+               .priv                   = priv,
+               .fn                     = fn,
+       };
+
+       return xfs_btree_query_all(cur, xfs_bmap_query_range_helper, &query);
+}
index f6b73f1bad5f742f9aa2e832594122543c1376a6..10b85865204d6792b6e3cd2057f0c9b03f22cf43 100644 (file)
@@ -280,4 +280,12 @@ extern struct kmem_cache   *xfs_bmap_intent_cache;
 int __init xfs_bmap_intent_init_cache(void);
 void xfs_bmap_intent_destroy_cache(void);
 
+typedef int (*xfs_bmap_query_range_fn)(
+       struct xfs_btree_cur    *cur,
+       struct xfs_bmbt_irec    *rec,
+       void                    *priv);
+
+int xfs_bmap_query_all(struct xfs_btree_cur *cur, xfs_bmap_query_range_fn fn,
+               void *priv);
+
 #endif /* __XFS_BMAP_H__ */
index 2d96cb60c22594e141abb7fe5b13df684333071c..a0b4280fe58438f34d3c7377d84d3efba0b2b623 100644 (file)
@@ -214,10 +214,10 @@ xfs_rmap_btrec_to_irec(
 /* Simple checks for rmap records. */
 xfs_failaddr_t
 xfs_rmap_check_irec(
-       struct xfs_btree_cur            *cur,
+       struct xfs_perag                *pag,
        const struct xfs_rmap_irec      *irec)
 {
-       struct xfs_mount                *mp = cur->bc_mp;
+       struct xfs_mount                *mp = pag->pag_mount;
        bool                            is_inode;
        bool                            is_unwritten;
        bool                            is_bmbt;
@@ -232,8 +232,8 @@ xfs_rmap_check_irec(
                        return __this_address;
        } else {
                /* check for valid extent range, including overflow */
-               if (!xfs_verify_agbext(cur->bc_ag.pag, irec->rm_startblock,
-                                                      irec->rm_blockcount))
+               if (!xfs_verify_agbext(pag, irec->rm_startblock,
+                                           irec->rm_blockcount))
                        return __this_address;
        }
 
@@ -306,7 +306,7 @@ xfs_rmap_get_rec(
 
        fa = xfs_rmap_btrec_to_irec(rec, irec);
        if (!fa)
-               fa = xfs_rmap_check_irec(cur, irec);
+               fa = xfs_rmap_check_irec(cur->bc_ag.pag, irec);
        if (fa)
                return xfs_rmap_complain_bad_rec(cur, fa, irec);
 
@@ -2441,7 +2441,7 @@ xfs_rmap_query_range_helper(
 
        fa = xfs_rmap_btrec_to_irec(rec, &irec);
        if (!fa)
-               fa = xfs_rmap_check_irec(cur, &irec);
+               fa = xfs_rmap_check_irec(cur->bc_ag.pag, &irec);
        if (fa)
                return xfs_rmap_complain_bad_rec(cur, fa, &irec);
 
index 3c98d9d50afb8b54230249ee34ad2619314d72bb..58c67896d12cb3ffafb9a9147c2efa6ab6f557c3 100644 (file)
@@ -195,7 +195,7 @@ int xfs_rmap_compare(const struct xfs_rmap_irec *a,
 union xfs_btree_rec;
 xfs_failaddr_t xfs_rmap_btrec_to_irec(const union xfs_btree_rec *rec,
                struct xfs_rmap_irec *irec);
-xfs_failaddr_t xfs_rmap_check_irec(struct xfs_btree_cur *cur,
+xfs_failaddr_t xfs_rmap_check_irec(struct xfs_perag *pag,
                const struct xfs_rmap_irec *irec);
 
 int xfs_rmap_has_records(struct xfs_btree_cur *cur, xfs_agblock_t bno,
index 2b7504f7a083b468f7e5dcfd13aadda2f2226bdd..956cdc2fd5960dc1190ef10b916deb1ab0af3941 100644 (file)
@@ -340,7 +340,18 @@ xfs_rmapbt_verify(
 
        level = be16_to_cpu(block->bb_level);
        if (pag && xfs_perag_initialised_agf(pag)) {
-               if (level >= pag->pagf_rmap_level)
+               unsigned int    maxlevel = pag->pagf_rmap_level;
+
+#ifdef CONFIG_XFS_ONLINE_REPAIR
+               /*
+                * Online repair could be rewriting the free space btrees, so
+                * we'll validate against the larger of either tree while this
+                * is going on.
+                */
+               maxlevel = max_t(unsigned int, maxlevel,
+                               pag->pagf_repair_rmap_level);
+#endif
+               if (level >= maxlevel)
                        return __this_address;
        } else if (level >= mp->m_rmap_maxlevels)
                return __this_address;