Check the rmapbt for obvious errors. We're leaving thorough checks
such as comparing the primary metadata against the rmapbt contents
for newer things like xfs_repair.
Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx>
---
db/check.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 84 insertions(+), 1 deletion(-)
diff --git a/db/check.c b/db/check.c
index 0871ed7..2964b5f 100644
--- a/db/check.c
+++ b/db/check.c
@@ -44,7 +44,7 @@ typedef enum {
DBM_FREE1, DBM_FREE2, DBM_FREELIST, DBM_INODE,
DBM_LOG, DBM_MISSING, DBM_QUOTA, DBM_RTBITMAP,
DBM_RTDATA, DBM_RTFREE, DBM_RTSUM, DBM_SB,
- DBM_SYMLINK, DBM_BTFINO,
+ DBM_SYMLINK, DBM_BTFINO, DBM_BTRMAP,
DBM_NDBM
} dbm_t;
@@ -171,6 +171,7 @@ static const char *typename[] = {
"sb",
"symlink",
"btfino",
+ "btrmap",
NULL
};
static int verbose;
@@ -349,6 +350,9 @@ static void scanfunc_ino(struct xfs_btree_block
*block, int level,
static void scanfunc_fino(struct xfs_btree_block *block, int level,
struct xfs_agf *agf, xfs_agblock_t bno,
int isroot);
+static void scanfunc_rmap(struct xfs_btree_block *block, int level,
+ struct xfs_agf *agf, xfs_agblock_t bno,
+ int isroot);
static void set_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno,
xfs_extlen_t len, dbm_t type,
xfs_agnumber_t c_agno, xfs_agblock_t c_agbno);
@@ -1050,6 +1054,7 @@ blocktrash_f(
(1 << DBM_RTSUM) |
(1 << DBM_SYMLINK) |
(1 << DBM_BTFINO) |
+ (1 << DBM_BTRMAP) |
(1 << DBM_SB);
while ((c = getopt(argc, argv, "0123n:o:s:t:x:y:z")) != EOF) {
switch (c) {
@@ -3899,6 +3904,12 @@ scan_ag(
be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]),
be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
1, scanfunc_cnt, TYP_CNTBT);
+ if (agf->agf_roots[XFS_BTNUM_RMAP]) {
+ scan_sbtree(agf,
+ be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]),
+ be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]),
+ 1, scanfunc_rmap, TYP_RMAPBT);
+ }
scan_sbtree(agf,
be32_to_cpu(agi->agi_root),
be32_to_cpu(agi->agi_level),
@@ -4650,6 +4661,78 @@ scanfunc_fino(
}
static void
+scanfunc_rmap(
+ struct xfs_btree_block *block,
+ int level,
+ struct xfs_agf *agf,
+ xfs_agblock_t bno,
+ int isroot)
+{
+ xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
+ int i;
+ xfs_rmap_ptr_t *pp;
+ struct xfs_rmap_rec *rp;
+ xfs_agblock_t lastblock;
+
+ if (be32_to_cpu(block->bb_magic) != XFS_RMAP_CRC_MAGIC) {
+ dbprintf(_("bad magic # %#x in rmapbt block %u/%u\n"),
+ be32_to_cpu(block->bb_magic), seqno, bno);
+ serious_error++;
+ return;
+ }
+ if (be16_to_cpu(block->bb_level) != level) {
+ if (!sflag)
+ dbprintf(_("expected level %d got %d in rmapbt block "
+ "%u/%u\n"),
+ level, be16_to_cpu(block->bb_level), seqno,
bno);
+ error++;
+ }
+ if (!isroot) {
+ fdblocks++;
+ agfbtreeblks++;
+ }
+ set_dbmap(seqno, bno, 1, DBM_BTRMAP, seqno, bno);
+ if (level == 0) {
+ if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[0] ||
+ (isroot == 0 && be16_to_cpu(block->bb_numrecs) <
mp->m_rmap_mnr[0])) {
+ dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
+ "rmapbt block %u/%u\n"),
+ be16_to_cpu(block->bb_numrecs),
mp->m_rmap_mnr[0],
+ mp->m_rmap_mxr[0], seqno, bno);
+ serious_error++;
+ return;
+ }
+ rp = XFS_RMAP_REC_ADDR(block, 1);
+ lastblock = 0;
+ for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
+ if (be32_to_cpu(rp[i].rm_startblock) < lastblock) {
+ dbprintf(_(
+ "out-of-order rmap btree record %d (%u %u) block %u/%u\n"),
+ i, be32_to_cpu(rp[i].rm_startblock),
+ be32_to_cpu(rp[i].rm_startblock),
+ be32_to_cpu(agf->agf_seqno), bno);
+ } else {
+ lastblock = be32_to_cpu(rp[i].rm_startblock);
+ }
+ }
+ return;
+ }
+ if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[1] ||
+ (isroot == 0 && be16_to_cpu(block->bb_numrecs) <
mp->m_rmap_mnr[1])) {
+ dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in rmapbt "
+ "block %u/%u\n"),
+ be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[1],
+ mp->m_rmap_mxr[1], seqno, bno);
+ serious_error++;
+ return;
+ }
+ pp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]);
+ for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
+ scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_rmap,
+ TYP_RMAPBT);
+}
+
+static void
set_dbmap(
xfs_agnumber_t agno,
xfs_agblock_t agbno,
|