|
@@ -692,12 +692,13 @@ xrep_findroot_block(
|
|
|
struct xrep_find_ag_btree *fab,
|
|
|
uint64_t owner,
|
|
|
xfs_agblock_t agbno,
|
|
|
- bool *found_it)
|
|
|
+ bool *done_with_block)
|
|
|
{
|
|
|
struct xfs_mount *mp = ri->sc->mp;
|
|
|
struct xfs_buf *bp;
|
|
|
struct xfs_btree_block *btblock;
|
|
|
xfs_daddr_t daddr;
|
|
|
+ int block_level;
|
|
|
int error;
|
|
|
|
|
|
daddr = XFS_AGB_TO_DADDR(mp, ri->sc->sa.agno, agbno);
|
|
@@ -735,18 +736,52 @@ xrep_findroot_block(
|
|
|
goto out;
|
|
|
bp->b_ops = fab->buf_ops;
|
|
|
|
|
|
- /* Ignore this block if it's lower in the tree than we've seen. */
|
|
|
- if (fab->root != NULLAGBLOCK &&
|
|
|
- xfs_btree_get_level(btblock) < fab->height)
|
|
|
- goto out;
|
|
|
-
|
|
|
/* Make sure we pass the verifiers. */
|
|
|
bp->b_ops->verify_read(bp);
|
|
|
if (bp->b_error)
|
|
|
goto out;
|
|
|
- fab->root = agbno;
|
|
|
- fab->height = xfs_btree_get_level(btblock) + 1;
|
|
|
- *found_it = true;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This block passes the magic/uuid and verifier tests for this btree
|
|
|
+ * type. We don't need the caller to try the other tree types.
|
|
|
+ */
|
|
|
+ *done_with_block = true;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Compare this btree block's level to the height of the current
|
|
|
+ * candidate root block.
|
|
|
+ *
|
|
|
+ * If the level matches the root we found previously, throw away both
|
|
|
+ * blocks because there can't be two candidate roots.
|
|
|
+ *
|
|
|
+ * If level is lower in the tree than the root we found previously,
|
|
|
+ * ignore this block.
|
|
|
+ */
|
|
|
+ block_level = xfs_btree_get_level(btblock);
|
|
|
+ if (block_level + 1 == fab->height) {
|
|
|
+ fab->root = NULLAGBLOCK;
|
|
|
+ goto out;
|
|
|
+ } else if (block_level < fab->height) {
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This is the highest block in the tree that we've found so far.
|
|
|
+ * Update the btree height to reflect what we've learned from this
|
|
|
+ * block.
|
|
|
+ */
|
|
|
+ fab->height = block_level + 1;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If this block doesn't have sibling pointers, then it's the new root
|
|
|
+ * block candidate. Otherwise, the root will be found farther up the
|
|
|
+ * tree.
|
|
|
+ */
|
|
|
+ if (btblock->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) &&
|
|
|
+ btblock->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK))
|
|
|
+ fab->root = agbno;
|
|
|
+ else
|
|
|
+ fab->root = NULLAGBLOCK;
|
|
|
|
|
|
trace_xrep_findroot_block(mp, ri->sc->sa.agno, agbno,
|
|
|
be32_to_cpu(btblock->bb_magic), fab->height - 1);
|
|
@@ -768,7 +803,7 @@ xrep_findroot_rmap(
|
|
|
struct xrep_findroot *ri = priv;
|
|
|
struct xrep_find_ag_btree *fab;
|
|
|
xfs_agblock_t b;
|
|
|
- bool found_it;
|
|
|
+ bool done;
|
|
|
int error = 0;
|
|
|
|
|
|
/* Ignore anything that isn't AG metadata. */
|
|
@@ -777,16 +812,16 @@ xrep_findroot_rmap(
|
|
|
|
|
|
/* Otherwise scan each block + btree type. */
|
|
|
for (b = 0; b < rec->rm_blockcount; b++) {
|
|
|
- found_it = false;
|
|
|
+ done = false;
|
|
|
for (fab = ri->btree_info; fab->buf_ops; fab++) {
|
|
|
if (rec->rm_owner != fab->rmap_owner)
|
|
|
continue;
|
|
|
error = xrep_findroot_block(ri, fab,
|
|
|
rec->rm_owner, rec->rm_startblock + b,
|
|
|
- &found_it);
|
|
|
+ &done);
|
|
|
if (error)
|
|
|
return error;
|
|
|
- if (found_it)
|
|
|
+ if (done)
|
|
|
break;
|
|
|
}
|
|
|
}
|