Commit 1002ff45 authored by Darrick J. Wong's avatar Darrick J. Wong Committed by Dave Chinner

xfs: xrep_findroot_block should reject root blocks with siblings

In xrep_findroot_block, if we find a candidate root block with sibling
pointers or sibling blocks on the same tree level, we should not return
that block as a tree root because root blocks cannot have siblings.
Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent dddde68b
...@@ -692,12 +692,13 @@ xrep_findroot_block( ...@@ -692,12 +692,13 @@ xrep_findroot_block(
struct xrep_find_ag_btree *fab, struct xrep_find_ag_btree *fab,
uint64_t owner, uint64_t owner,
xfs_agblock_t agbno, xfs_agblock_t agbno,
bool *found_it) bool *done_with_block)
{ {
struct xfs_mount *mp = ri->sc->mp; struct xfs_mount *mp = ri->sc->mp;
struct xfs_buf *bp; struct xfs_buf *bp;
struct xfs_btree_block *btblock; struct xfs_btree_block *btblock;
xfs_daddr_t daddr; xfs_daddr_t daddr;
int block_level;
int error; int error;
daddr = XFS_AGB_TO_DADDR(mp, ri->sc->sa.agno, agbno); daddr = XFS_AGB_TO_DADDR(mp, ri->sc->sa.agno, agbno);
...@@ -735,18 +736,52 @@ xrep_findroot_block( ...@@ -735,18 +736,52 @@ xrep_findroot_block(
goto out; goto out;
bp->b_ops = fab->buf_ops; 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. */ /* Make sure we pass the verifiers. */
bp->b_ops->verify_read(bp); bp->b_ops->verify_read(bp);
if (bp->b_error) if (bp->b_error)
goto out; 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, trace_xrep_findroot_block(mp, ri->sc->sa.agno, agbno,
be32_to_cpu(btblock->bb_magic), fab->height - 1); be32_to_cpu(btblock->bb_magic), fab->height - 1);
...@@ -768,7 +803,7 @@ xrep_findroot_rmap( ...@@ -768,7 +803,7 @@ xrep_findroot_rmap(
struct xrep_findroot *ri = priv; struct xrep_findroot *ri = priv;
struct xrep_find_ag_btree *fab; struct xrep_find_ag_btree *fab;
xfs_agblock_t b; xfs_agblock_t b;
bool found_it; bool done;
int error = 0; int error = 0;
/* Ignore anything that isn't AG metadata. */ /* Ignore anything that isn't AG metadata. */
...@@ -777,16 +812,16 @@ xrep_findroot_rmap( ...@@ -777,16 +812,16 @@ xrep_findroot_rmap(
/* Otherwise scan each block + btree type. */ /* Otherwise scan each block + btree type. */
for (b = 0; b < rec->rm_blockcount; b++) { for (b = 0; b < rec->rm_blockcount; b++) {
found_it = false; done = false;
for (fab = ri->btree_info; fab->buf_ops; fab++) { for (fab = ri->btree_info; fab->buf_ops; fab++) {
if (rec->rm_owner != fab->rmap_owner) if (rec->rm_owner != fab->rmap_owner)
continue; continue;
error = xrep_findroot_block(ri, fab, error = xrep_findroot_block(ri, fab,
rec->rm_owner, rec->rm_startblock + b, rec->rm_owner, rec->rm_startblock + b,
&found_it); &done);
if (error) if (error)
return error; return error;
if (found_it) if (done)
break; break;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment