]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_repair: check existing realtime rmapbt entries against observed rmaps
authorDarrick J. Wong <djwong@kernel.org>
Wed, 3 Jul 2024 21:22:24 +0000 (14:22 -0700)
committerChristoph Hellwig <hch@lst.de>
Mon, 12 Aug 2024 11:53:50 +0000 (13:53 +0200)
Once we've finished collecting reverse mapping observations from the
metadata scan, check those observations against the realtime rmap btree
(particularly if we're in -n mode) to detect rtrmapbt problems.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
repair/phase4.c
repair/rmap.c
repair/rmap.h

index 06c2737c894433904e485001d3e03c9fb5075a5a..3845c612d95e2dd8894c6d154cfe624c4fbe6976 100644 (file)
@@ -155,6 +155,16 @@ check_rmap_btrees(
        rmaps_verify_btree(wq->wq_ctx, agno);
 }
 
+static void
+check_rtrmap_btrees(
+       struct workqueue *wq,
+       xfs_agnumber_t  agno,
+       void            *arg)
+{
+       rmap_add_fixed_rtgroup_rec(wq->wq_ctx, agno);
+       rtrmaps_verify_btree(wq->wq_ctx, agno);
+}
+
 static void
 compute_ag_refcounts(
        struct workqueue*wq,
@@ -207,6 +217,10 @@ process_rmap_data(
        create_work_queue(&wq, mp, platform_nproc());
        for (i = 0; i < mp->m_sb.sb_agcount; i++)
                queue_work(&wq, check_rmap_btrees, i, NULL);
+       if (xfs_has_rtrmapbt(mp)) {
+               for (i = 0; i < mp->m_sb.sb_rgcount; i++)
+                       queue_work(&wq, check_rtrmap_btrees, i, NULL);
+       }
        destroy_work_queue(&wq);
 
        if (!xfs_has_reflink(mp))
index 9d135f472c3a8d36d2df8569bde863854ec3e40f..f33b64a2a1cfc47ebbcca32559e1e972bbce3ce3 100644 (file)
@@ -16,6 +16,7 @@
 #include "libfrog/platform.h"
 #include "rcbag.h"
 #include "rt.h"
+#include "prefetch.h"
 
 #undef RMAP_DEBUG
 
@@ -195,8 +196,6 @@ rmaps_init(
 
        for (i = 0; i < mp->m_sb.sb_rgcount; i++)
                rmaps_init_rt(mp, i, &rg_rmaps[i]);
-
-       discover_rtgroup_inodes(mp);
 }
 
 /*
@@ -573,6 +572,27 @@ rmap_add_fixed_ag_rec(
        }
 }
 
+/* Add this realtime group's fixed metadata to the incore data. */
+void
+rmap_add_fixed_rtgroup_rec(
+       struct xfs_mount        *mp,
+       xfs_rgnumber_t          rgno)
+{
+       struct xfs_rmap_irec    rmap = {
+               .rm_startblock  = 0,
+               .rm_blockcount  = mp->m_sb.sb_rextsize,
+               .rm_owner       = XFS_RMAP_OWN_FS,
+               .rm_offset      = 0,
+               .rm_flags       = 0,
+       };
+
+       if (!rmap_needs_work(mp))
+               return;
+
+       if (xfs_has_rtsb(mp) && rgno == 0)
+               rmap_add_mem_rec(mp, true, rgno, &rmap);
+}
+
 /*
  * Copy the per-AG btree reverse-mapping data into the rmapbt.
  *
@@ -1213,62 +1233,25 @@ rmap_is_good(
 #undef NEXTP
 #undef NEXTL
 
-/*
- * Compare the observed reverse mappings against what's in the ag btree.
- */
-void
-rmaps_verify_btree(
-       struct xfs_mount        *mp,
-       xfs_agnumber_t          agno)
+static int
+rmap_compare_records(
+       struct xfs_btree_cur    *rm_cur,
+       struct xfs_btree_cur    *bt_cur,
+       unsigned int            group)
 {
-       struct xfs_btree_cur    *rm_cur;
        struct xfs_rmap_irec    rm_rec;
        struct xfs_rmap_irec    tmp;
-       struct xfs_btree_cur    *bt_cur = NULL;
-       struct xfs_buf          *agbp = NULL;
-       struct xfs_perag        *pag = NULL;
        int                     have;
        int                     error;
 
-       if (!xfs_has_rmapbt(mp) || add_rmapbt)
-               return;
-       if (rmapbt_suspect) {
-               if (no_modify && agno == 0)
-                       do_warn(_("would rebuild corrupt rmap btrees.\n"));
-               return;
-       }
-
-       /* Create cursors to rmap structures */
-       error = rmap_init_mem_cursor(mp, NULL, false, agno, &rm_cur);
-       if (error) {
-               do_warn(_("Not enough memory to check reverse mappings.\n"));
-               return;
-       }
-
-       pag = libxfs_perag_get(mp, agno);
-       error = -libxfs_alloc_read_agf(pag, NULL, 0, &agbp);
-       if (error) {
-               do_warn(_("Could not read AGF %u to check rmap btree.\n"),
-                               agno);
-               goto err_pag;
-       }
-
-       /* Leave the per-ag data "uninitialized" since we rewrite it later */
-       clear_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate);
-
-       bt_cur = libxfs_rmapbt_init_cursor(mp, NULL, agbp, pag);
-       if (!bt_cur) {
-               do_warn(_("Not enough memory to check reverse mappings.\n"));
-               goto err_agf;
-       }
-
        while ((error = rmap_get_mem_rec(rm_cur, &rm_rec)) == 1) {
                error = rmap_lookup(bt_cur, &rm_rec, &tmp, &have);
                if (error) {
                        do_warn(
 _("Could not read reverse-mapping record for (%u/%u).\n"),
-                                       agno, rm_rec.rm_startblock);
-                       goto err_cur;
+                                       group,
+                                       rm_rec.rm_startblock);
+                       return error;
                }
 
                /*
@@ -1283,15 +1266,15 @@ _("Could not read reverse-mapping record for (%u/%u).\n"),
                        if (error) {
                                do_warn(
 _("Could not read reverse-mapping record for (%u/%u).\n"),
-                                               agno, rm_rec.rm_startblock);
-                               goto err_cur;
+                                               group, rm_rec.rm_startblock);
+                               return error;
                        }
                }
                if (!have) {
                        do_warn(
 _("Missing reverse-mapping record for (%u/%u) %slen %u owner %"PRId64" \
 %s%soff %"PRIu64"\n"),
-                               agno, rm_rec.rm_startblock,
+                               group, rm_rec.rm_startblock,
                                (rm_rec.rm_flags & XFS_RMAP_UNWRITTEN) ?
                                        _("unwritten ") : "",
                                rm_rec.rm_blockcount,
@@ -1304,12 +1287,12 @@ _("Missing reverse-mapping record for (%u/%u) %slen %u owner %"PRId64" \
                        continue;
                }
 
-               /* Compare each refcount observation against the btree's */
+               /* Compare each rmap observation against the btree's */
                if (!rmap_is_good(&rm_rec, &tmp)) {
                        do_warn(
 _("Incorrect reverse-mapping: saw (%u/%u) %slen %u owner %"PRId64" %s%soff \
 %"PRIu64"; should be (%u/%u) %slen %u owner %"PRId64" %s%soff %"PRIu64"\n"),
-                               agno, tmp.rm_startblock,
+                               group, tmp.rm_startblock,
                                (tmp.rm_flags & XFS_RMAP_UNWRITTEN) ?
                                        _("unwritten ") : "",
                                tmp.rm_blockcount,
@@ -1319,7 +1302,7 @@ _("Incorrect reverse-mapping: saw (%u/%u) %slen %u owner %"PRId64" %s%soff \
                                (tmp.rm_flags & XFS_RMAP_BMBT_BLOCK) ?
                                        _("bmbt ") : "",
                                tmp.rm_offset,
-                               agno, rm_rec.rm_startblock,
+                               group, rm_rec.rm_startblock,
                                (rm_rec.rm_flags & XFS_RMAP_UNWRITTEN) ?
                                        _("unwritten ") : "",
                                rm_rec.rm_blockcount,
@@ -1332,8 +1315,61 @@ _("Incorrect reverse-mapping: saw (%u/%u) %slen %u owner %"PRId64" %s%soff \
                }
        }
 
+       return error;
+}
+
+/*
+ * Compare the observed reverse mappings against what's in the ag btree.
+ */
+void
+rmaps_verify_btree(
+       struct xfs_mount        *mp,
+       xfs_agnumber_t          agno)
+{
+       struct xfs_btree_cur    *rm_cur;
+       struct xfs_btree_cur    *bt_cur = NULL;
+       struct xfs_buf          *agbp = NULL;
+       struct xfs_perag        *pag = NULL;
+       int                     error;
+
+       if (!xfs_has_rmapbt(mp) || add_rmapbt)
+               return;
+       if (rmapbt_suspect) {
+               if (no_modify && agno == 0)
+                       do_warn(_("would rebuild corrupt rmap btrees.\n"));
+               return;
+       }
+
+       /* Create cursors to rmap structures */
+       error = rmap_init_mem_cursor(mp, NULL, false, agno, &rm_cur);
+       if (error) {
+               do_warn(_("Not enough memory to check reverse mappings.\n"));
+               return;
+       }
+
+       pag = libxfs_perag_get(mp, agno);
+       error = -libxfs_alloc_read_agf(pag, NULL, 0, &agbp);
+       if (error) {
+               do_warn(_("Could not read AGF %u to check rmap btree.\n"),
+                               agno);
+               goto err_pag;
+       }
+
+       /* Leave the per-ag data "uninitialized" since we rewrite it later */
+       clear_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate);
+
+       bt_cur = libxfs_rmapbt_init_cursor(mp, NULL, agbp, pag);
+       if (!bt_cur) {
+               do_warn(_("Not enough memory to check reverse mappings.\n"));
+               goto err_agf;
+       }
+
+       error = rmap_compare_records(rm_cur, bt_cur, agno);
+       if (error)
+               goto err_cur;
+
 err_cur:
-       libxfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR);
+       libxfs_btree_del_cursor(bt_cur, error);
 err_agf:
        libxfs_buf_relse(agbp);
 err_pag:
@@ -1341,6 +1377,80 @@ err_pag:
        libxfs_btree_del_cursor(rm_cur, error);
 }
 
+/*
+ * Compare the observed reverse mappings against what's in the rtgroup btree.
+ */
+void
+rtrmaps_verify_btree(
+       struct xfs_mount        *mp,
+       xfs_rgnumber_t          rgno)
+{
+       struct xfs_btree_cur    *rm_cur;
+       struct xfs_btree_cur    *bt_cur = NULL;
+       struct xfs_rtgroup      *rtg = NULL;
+       struct xfs_inode        *ip = NULL;
+       int                     error;
+
+       if (!xfs_has_rmapbt(mp) || add_rmapbt)
+               return;
+       if (rmapbt_suspect) {
+               if (no_modify && rgno == 0)
+                       do_warn(_("would rebuild corrupt rmap btrees.\n"));
+               return;
+       }
+
+       /* Create cursors to rmap structures */
+       error = rmap_init_mem_cursor(mp, NULL, true, rgno, &rm_cur);
+       if (error) {
+               do_warn(_("Not enough memory to check reverse mappings.\n"));
+               return;
+       }
+
+       rtg = libxfs_rtgroup_get(mp, rgno);
+       if (!rtg) {
+               do_warn(_("Could not load rtgroup %u.\n"), rgno);
+               goto err_rcur;
+       }
+
+       ip = rtg->rtg_inodes[XFS_RTG_RMAP];
+       if (!ip) {
+               do_warn(_("Could not find rtgroup %u rmap inode.\n"), rgno);
+               goto err_rtg;
+       }
+
+       if (ip->i_df.if_format != XFS_DINODE_FMT_RMAP) {
+               do_warn(
+_("rtgroup %u rmap inode has wrong format 0x%x, expected 0x%x\n"),
+                               rgno, ip->i_df.if_format,
+                               XFS_DINODE_FMT_RMAP);
+               goto err_rtg;
+       }
+
+       if (xfs_inode_has_attr_fork(ip) &&
+           !(xfs_has_metadir(mp) && xfs_has_parent(mp))) {
+               do_warn(
+_("rtgroup %u rmap inode should not have extended attributes\n"), rgno);
+               goto err_rtg;
+       }
+
+       bt_cur = libxfs_rtrmapbt_init_cursor(mp, NULL, rtg, ip);
+       if (!bt_cur) {
+               do_warn(_("Not enough memory to check reverse mappings.\n"));
+               goto err_rtg;
+       }
+
+       error = rmap_compare_records(rm_cur, bt_cur, rgno);
+       if (error)
+               goto err_cur;
+
+err_cur:
+       libxfs_btree_del_cursor(bt_cur, error);
+err_rtg:
+       libxfs_rtgroup_put(rtg);
+err_rcur:
+       libxfs_btree_del_cursor(rm_cur, error);
+}
+
 /*
  * Compare the key fields of two rmap records -- positive if key1 > key2,
  * negative if key1 < key2, and zero if equal.
index b5c8b4f0bef7948e08fc2265439044de376aa061..ebda561e59bc8f9ac61325faed16ce0f443f7865 100644 (file)
@@ -21,6 +21,7 @@ void rmap_add_bmbt_rec(struct xfs_mount *mp, xfs_ino_t ino, int whichfork,
 bool rmaps_are_mergeable(struct xfs_rmap_irec *r1, struct xfs_rmap_irec *r2);
 
 void rmap_add_fixed_ag_rec(struct xfs_mount *mp, xfs_agnumber_t agno);
+void rmap_add_fixed_rtgroup_rec(struct xfs_mount *mp, xfs_rgnumber_t rgno);
 
 int rmap_add_agbtree_mapping(struct xfs_mount *mp, xfs_agnumber_t agno,
                xfs_agblock_t agbno, xfs_extlen_t len, uint64_t owner);
@@ -30,6 +31,7 @@ uint64_t rmap_record_count(struct xfs_mount *mp, bool isrt,
                xfs_agnumber_t agno);
 extern void rmap_avoid_check(struct xfs_mount *mp);
 void rmaps_verify_btree(struct xfs_mount *mp, xfs_agnumber_t agno);
+void rtrmaps_verify_btree(struct xfs_mount *mp, xfs_rgnumber_t rgno);
 
 extern int64_t rmap_diffkeys(struct xfs_rmap_irec *kp1,
                struct xfs_rmap_irec *kp2);