xfs
[Top] [All Lists]

[PATCH 33/51] xfs_repair: check existing rmapbt entries against observed

To: david@xxxxxxxxxxxxx, darrick.wong@xxxxxxxxxx
Subject: [PATCH 33/51] xfs_repair: check existing rmapbt entries against observed rmaps
From: "Darrick J. Wong" <darrick.wong@xxxxxxxxxx>
Date: Tue, 06 Oct 2015 22:08:48 -0700
Cc: xfs@xxxxxxxxxxx
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <20151007050513.1504.28089.stgit@xxxxxxxxxxxxxxxx>
References: <20151007050513.1504.28089.stgit@xxxxxxxxxxxxxxxx>
User-agent: StGit/0.17.1-dirty
If we're running in -n mode, check the rmaps that we observe against
what's in the rmap btree and complain if there's a mismatch.

Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
---
 include/libxfs.h |    1 
 repair/phase4.c  |    6 ++
 repair/rmap.c    |  173 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 repair/rmap.h    |    5 ++
 repair/scan.c    |   19 ++++--
 5 files changed, 198 insertions(+), 6 deletions(-)


diff --git a/include/libxfs.h b/include/libxfs.h
index 662dc30..9c85a49 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -77,6 +77,7 @@ extern uint32_t crc32c_le(uint32_t crc, unsigned char const 
*p, size_t len);
 #include "xfs_bmap.h"
 #include "xfs_trace.h"
 #include "xfs_trans.h"
+#include "xfs_rmap_btree.h"
 
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
diff --git a/repair/phase4.c b/repair/phase4.c
index cbdb92e..98aab35 100644
--- a/repair/phase4.c
+++ b/repair/phase4.c
@@ -174,6 +174,12 @@ _("unable to add AG %u metadata reverse-mapping data.\n"), 
agno);
        if (error)
                do_error(
 _("unable to merge AG %u metadata reverse-mapping data.\n"), agno);
+
+       error = check_rmaps(wq->mp, agno);
+       if (error)
+               do_error(
+_("%s while checking reverse-mappings"),
+                        strerror(-error));
 }
 
 static void
diff --git a/repair/rmap.c b/repair/rmap.c
index a5ea685..7b65d52 100644
--- a/repair/rmap.c
+++ b/repair/rmap.c
@@ -41,6 +41,7 @@ struct xfs_ag_rmap {
 };
 
 static struct xfs_ag_rmap *ag_rmaps;
+static bool rmapbt_suspect;
 
 /*
  * Compare rmap observations for array sorting.
@@ -413,3 +414,175 @@ dump_rmap(
 #else
 # define dump_rmap(m, a, r)
 #endif
+
+/**
+ * rmap_record_count() -- Return the number of rmap objects for an AG.
+ *
+ * @mp: XFS mount object
+ * @agno: AG number
+ */
+size_t
+rmap_record_count(
+       struct xfs_mount                *mp,
+       xfs_agnumber_t          agno)
+{
+       return slab_count(ag_rmaps[agno].ar_rmaps);
+}
+
+/**
+ * init_rmap_cursor() -- Return a slab cursor that will return rmap
+ *                       objects in order.
+ * @agno: AG number.
+ * @cur: The new cursor.
+ */
+int
+init_rmap_cursor(
+       xfs_agnumber_t          agno,
+       struct xfs_slab_cursor  **cur)
+{
+       return init_slab_cursor(ag_rmaps[agno].ar_rmaps, rmap_compare, cur);
+}
+
+/**
+ * rmap_avoid_check() -- Disable the refcount btree check.
+ */
+void
+rmap_avoid_check(void)
+{
+       rmapbt_suspect = true;
+}
+
+/**
+ * check_rmaps() -- Compare the observed reverse mappings against
+ *                 what's in the ag btree.
+ * @mp: XFS mount object
+ * @agno: AG number
+ */
+int
+check_rmaps(
+       struct xfs_mount        *mp,
+       xfs_agnumber_t          agno)
+{
+       struct xfs_slab_cursor  *rm_cur;
+       struct xfs_btree_cur    *bt_cur = NULL;
+       int                     error;
+       int                     have;
+       int                     i;
+       struct xfs_buf          *agbp = NULL;
+       struct xfs_rmap_irec    *rm_rec;
+       struct xfs_rmap_irec    tmp;
+       struct xfs_perag        *pag;           /* per allocation group data */
+
+       if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
+               return 0;
+       if (rmapbt_suspect) {
+               if (no_modify && agno == 0)
+                       do_warn(_("would rebuild corrupt rmap btrees.\n"));
+               return 0;
+       }
+
+       /* Create cursors to refcount structures */
+       error = init_rmap_cursor(agno, &rm_cur);
+       if (error)
+               return error;
+
+       error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
+       if (error)
+               goto err;
+
+       /* Leave the per-ag data "uninitialized" since we rewrite it later */
+       pag = xfs_perag_get(mp, agno);
+       pag->pagf_init = 0;
+       xfs_perag_put(pag);
+
+       bt_cur = xfs_rmapbt_init_cursor(mp, NULL, agbp, agno);
+       if (!bt_cur) {
+               error = -ENOMEM;
+               goto err;
+       }
+
+       rm_rec = pop_slab_cursor(rm_cur);
+       while (rm_rec) {
+               /* Look for a rmap record in the btree */
+               error = xfs_rmap_lookup_eq(bt_cur, rm_rec->rm_startblock,
+                               rm_rec->rm_blockcount, rm_rec->rm_owner,
+                               rm_rec->rm_offset, &have);
+               if (error)
+                       goto err;
+               if (!have) {
+                       do_warn(
+_("Missing reverse-mapping record for (%u/%u) %slen %u owner %"PRIx64" \
+%s%soff %"PRIx64"\n"),
+                               agno, rm_rec->rm_startblock,
+                               XFS_RMAP_IS_UNWRITTEN(rm_rec->rm_blockcount) ?
+                                       _("unwritten ") : "",
+                               XFS_RMAP_LEN(rm_rec->rm_blockcount),
+                               rm_rec->rm_owner,
+                               XFS_RMAP_IS_ATTR_FORK(rm_rec->rm_offset) ?
+                                       _("attr ") : "",
+                               XFS_RMAP_IS_BMBT(rm_rec->rm_offset) ?
+                                       _("bmbt ") : "",
+                               XFS_RMAP_OFF(rm_rec->rm_offset));
+                       goto next_loop;
+               }
+
+               error = xfs_rmap_get_rec(bt_cur, &tmp, &i);
+               if (error)
+                       goto err;
+               if (!i) {
+                       do_warn(
+_("Unretrievable reverse-mapping record for (%u/%u) %slen %u owner %"PRIx64" \
+%s%soff %"PRIx64"\n"),
+                               agno, rm_rec->rm_startblock,
+                               XFS_RMAP_IS_UNWRITTEN(rm_rec->rm_blockcount) ?
+                                       _("unwritten ") : "",
+                               XFS_RMAP_LEN(rm_rec->rm_blockcount),
+                               rm_rec->rm_owner,
+                               XFS_RMAP_IS_ATTR_FORK(rm_rec->rm_offset) ?
+                                       _("attr ") : "",
+                               XFS_RMAP_IS_BMBT(rm_rec->rm_offset) ?
+                                       _("bmbt ") : "",
+                               XFS_RMAP_OFF(rm_rec->rm_offset));
+                       goto next_loop;
+               }
+
+               /* Compare each refcount observation against the btree's */
+               if (tmp.rm_startblock != rm_rec->rm_startblock ||
+                   tmp.rm_blockcount != rm_rec->rm_blockcount ||
+                   tmp.rm_owner != rm_rec->rm_owner ||
+                   tmp.rm_offset != rm_rec->rm_offset)
+                       do_warn(
+_("Incorrect reverse-mapping: saw (%u/%u) %slen %u owner %"PRIx64" %s%soff \
+%"PRIx64"; should be (%u/%u) %slen %u owner %"PRIx64" %s%soff %"PRIx64"\n"),
+                               agno, tmp.rm_startblock,
+                               XFS_RMAP_IS_UNWRITTEN(tmp.rm_blockcount) ?
+                                       _("unwritten ") : "",
+                               XFS_RMAP_LEN(tmp.rm_blockcount),
+                               tmp.rm_owner,
+                               XFS_RMAP_IS_ATTR_FORK(tmp.rm_offset) ?
+                                       _("attr ") : "",
+                               XFS_RMAP_IS_BMBT(tmp.rm_offset) ?
+                                       _("bmbt ") : "",
+                               XFS_RMAP_OFF(tmp.rm_offset),
+                               agno, rm_rec->rm_startblock,
+                               XFS_RMAP_IS_UNWRITTEN(rm_rec->rm_blockcount) ?
+                                       _("unwritten ") : "",
+                               XFS_RMAP_LEN(rm_rec->rm_blockcount),
+                               rm_rec->rm_owner,
+                               XFS_RMAP_IS_ATTR_FORK(rm_rec->rm_offset) ?
+                                       _("attr ") : "",
+                               XFS_RMAP_IS_BMBT(rm_rec->rm_offset) ?
+                                       _("bmbt ") : "",
+                               XFS_RMAP_OFF(rm_rec->rm_offset));
+next_loop:
+               rm_rec = pop_slab_cursor(rm_cur);
+       }
+
+err:
+       if (bt_cur)
+               xfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR);
+       if (agbp)
+               libxfs_putbuf(agbp);
+       free_slab_cursor(&rm_cur);
+       return 0;
+}
diff --git a/repair/rmap.h b/repair/rmap.h
index 7bab450..f3f3331 100644
--- a/repair/rmap.h
+++ b/repair/rmap.h
@@ -33,4 +33,9 @@ extern int fold_raw_rmaps(struct xfs_mount *mp, 
xfs_agnumber_t agno);
 
 extern int add_fixed_ag_rmap_data(struct xfs_mount *, xfs_agnumber_t);
 
+extern size_t rmap_record_count(struct xfs_mount *, xfs_agnumber_t);
+extern int init_rmap_cursor(xfs_agnumber_t, struct xfs_slab_cursor **);
+extern void rmap_avoid_check(void);
+extern int check_rmaps(struct xfs_mount *, xfs_agnumber_t);
+
 #endif /* RMAP_H_ */
diff --git a/repair/scan.c b/repair/scan.c
index db9e131..823401b 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -29,6 +29,7 @@
 #include "bmap.h"
 #include "progress.h"
 #include "threads.h"
+#include "slab.h"
 #include "rmap.h"
 
 static xfs_mount_t     *mp = NULL;
@@ -808,7 +809,9 @@ scan_rmapbt(
 
        if (magic != XFS_RMAP_CRC_MAGIC) {
                name = "(unknown)";
-               assert(0);
+               hdr_errors++;
+               suspect++;
+               goto out;
        }
 
        if (be32_to_cpu(block->bb_magic) != magic) {
@@ -816,7 +819,7 @@ scan_rmapbt(
                        be32_to_cpu(block->bb_magic), name, agno, bno);
                hdr_errors++;
                if (suspect)
-                       return;
+                       goto out;
        }
 
        /*
@@ -834,7 +837,7 @@ scan_rmapbt(
                        level, be16_to_cpu(block->bb_level), name, agno, bno);
                hdr_errors++;
                if (suspect)
-                       return;
+                       goto out;
        }
 
        /* check for btree blocks multiply claimed */
@@ -844,7 +847,7 @@ scan_rmapbt(
                do_warn(
 _("%s rmap btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
                                name, state, agno, bno, suspect);
-               return;
+               goto out;
        }
        set_bmap(agno, bno, XR_E_FS_MAP);
 
@@ -992,7 +995,7 @@ _("unknown block (%d,%d-%d) mismatch on %s tree, state - 
%d,%" PRIx64 "\n"),
                                }
                        }
                }
-               return;
+               goto out;
        }
 
        /*
@@ -1020,7 +1023,7 @@ _("unknown block (%d,%d-%d) mismatch on %s tree, state - 
%d,%" PRIx64 "\n"),
                        mp->m_rmap_mnr[1], mp->m_rmap_mxr[1],
                        name, agno, bno);
                if (suspect)
-                       return;
+                       goto out;
                suspect++;
        } else if (suspect) {
                suspect = 0;
@@ -1043,6 +1046,10 @@ _("unknown block (%d,%d-%d) mismatch on %s tree, state - 
%d,%" PRIx64 "\n"),
                                    magic, priv, &xfs_rmapbt_buf_ops);
                }
        }
+
+out:
+       if (suspect)
+               rmap_avoid_check();
 }
 
 /*

<Prev in Thread] Current Thread [Next in Thread>