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: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
Родитель
dddde68b8f
Коммит
1002ff45ef
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче