/* *Checkforbtreeoperationerrors.Seethesectionabouthandling *operationalerrorsincommon.c.
*/ staticbool
__xchk_btree_process_error( struct xfs_scrub *sc, struct xfs_btree_cur *cur, int level, int *error,
__u32 errflag, void *ret_ip)
{ if (*error == 0) returntrue;
switch (*error) { case -EDEADLOCK: case -ECHRNG: /* Used to restart an op with deadlock avoidance. */
trace_xchk_deadlock_retry(sc->ip, sc->sm, *error); break; case -EFSBADCRC: case -EFSCORRUPTED: /* Note the badness but don't abort. */
sc->sm->sm_flags |= errflag;
*error = 0;
fallthrough; default: if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE)
trace_xchk_ifork_btree_op_error(sc, cur, level,
*error, ret_ip); else
trace_xchk_btree_op_error(sc, cur, level,
*error, ret_ip); break;
} returnfalse;
}
/* Are all records across all record blocks in order? */ if (bs->lastrec_valid &&
!cur->bc_ops->recs_inorder(cur, &bs->lastrec, rec))
xchk_btree_set_corrupt(bs->sc, cur, 0);
memcpy(&bs->lastrec, rec, cur->bc_ops->rec_len);
bs->lastrec_valid = true;
if (cur->bc_nlevels == 1) return;
/* Is low_key(rec) at least as large as the parent low key? */
cur->bc_ops->init_key_from_rec(&key, rec);
keyblock = xfs_btree_get_block(cur, 1, &bp);
keyp = xfs_btree_key_addr(cur, cur->bc_levels[1].ptr, keyblock); if (xfs_btree_keycmp_lt(cur, &key, keyp))
xchk_btree_set_corrupt(bs->sc, cur, 1);
if (!(cur->bc_ops->geom_flags & XFS_BTGEO_OVERLAPPING)) return;
/* Is high_key(rec) no larger than the parent high key? */
cur->bc_ops->init_high_key_from_rec(&hkey, rec);
keyp = xfs_btree_high_key_addr(cur, cur->bc_levels[1].ptr, keyblock); if (xfs_btree_keycmp_lt(cur, keyp, &hkey))
xchk_btree_set_corrupt(bs->sc, cur, 1);
}
/* Are all low keys across all node blocks in order? */ if (bs->lastkey[level - 1].valid &&
!cur->bc_ops->keys_inorder(cur, &bs->lastkey[level - 1].key, key))
xchk_btree_set_corrupt(bs->sc, cur, level);
memcpy(&bs->lastkey[level - 1].key, key, cur->bc_ops->key_len);
bs->lastkey[level - 1].valid = true;
if (level + 1 >= cur->bc_nlevels) return;
/* Is this block's low key at least as large as the parent low key? */
keyblock = xfs_btree_get_block(cur, level + 1, &bp);
keyp = xfs_btree_key_addr(cur, cur->bc_levels[level + 1].ptr, keyblock); if (xfs_btree_keycmp_lt(cur, key, keyp))
xchk_btree_set_corrupt(bs->sc, cur, level);
if (!(cur->bc_ops->geom_flags & XFS_BTGEO_OVERLAPPING)) return;
/* Is this block's high key no larger than the parent high key? */
key = xfs_btree_high_key_addr(cur, cur->bc_levels[level].ptr, block);
keyp = xfs_btree_high_key_addr(cur, cur->bc_levels[level + 1].ptr,
keyblock); if (xfs_btree_keycmp_lt(cur, keyp, key))
xchk_btree_set_corrupt(bs->sc, cur, level);
}
/* *Checkabtreepointer.Returnstrueifit'soktousethispointer. *Callersdonotneedtosetthecorruptflag.
*/ staticbool
xchk_btree_ptr_ok( struct xchk_btree *bs, int level, union xfs_btree_ptr *ptr)
{ /* A btree rooted in an inode has no block pointer to the root. */ if (bs->cur->bc_ops->type == XFS_BTREE_TYPE_INODE &&
level == bs->cur->bc_nlevels) returntrue;
/* Otherwise, check the pointers. */ if (__xfs_btree_check_ptr(bs->cur, ptr, 0, level)) {
xchk_btree_set_corrupt(bs->sc, bs->cur, level); returnfalse;
}
returntrue;
}
/* Check that a btree block's sibling matches what we expect it. */ STATICint
xchk_btree_block_check_sibling( struct xchk_btree *bs, int level, int direction, union xfs_btree_ptr *sibling)
{ struct xfs_btree_cur *cur = bs->cur; struct xfs_btree_block *pblock; struct xfs_buf *pbp; struct xfs_btree_cur *ncur = NULL; union xfs_btree_ptr *pp; int success; int error;
/* Check the siblings of a btree block. */ STATICint
xchk_btree_block_check_siblings( struct xchk_btree *bs, struct xfs_btree_block *block)
{ struct xfs_btree_cur *cur = bs->cur; union xfs_btree_ptr leftsib; union xfs_btree_ptr rightsib; int level; int error = 0;
/* *Ifthisbtreeblockhasaparent,makesurethattheparent'skeyscapture *thekeyspacecontainedinthisblock.
*/ STATICvoid
xchk_btree_block_check_keys( struct xchk_btree *bs, int level, struct xfs_btree_block *block)
{ union xfs_btree_key block_key; union xfs_btree_key *block_high_key; union xfs_btree_key *parent_low_key, *parent_high_key; struct xfs_btree_cur *cur = bs->cur; struct xfs_btree_block *parent_block; struct xfs_buf *bp;
if (level == cur->bc_nlevels - 1) return;
xfs_btree_get_keys(cur, block, &block_key);
/* Make sure the low key of this block matches the parent. */
parent_block = xfs_btree_get_block(cur, level + 1, &bp);
parent_low_key = xfs_btree_key_addr(cur, cur->bc_levels[level + 1].ptr,
parent_block); if (xfs_btree_keycmp_ne(cur, &block_key, parent_low_key)) {
xchk_btree_set_corrupt(bs->sc, bs->cur, level); return;
}
if (!(cur->bc_ops->geom_flags & XFS_BTGEO_OVERLAPPING)) return;
/* Make sure the high key of this block matches the parent. */
parent_high_key = xfs_btree_high_key_addr(cur,
cur->bc_levels[level + 1].ptr, parent_block);
block_high_key = xfs_btree_high_key_from_key(cur, &block_key); if (xfs_btree_keycmp_ne(cur, block_high_key, parent_high_key))
xchk_btree_set_corrupt(bs->sc, bs->cur, level);
}
/* *Grabandscrubabtreeblockgivenabtreepointer.Returnsblock *andbufferpointers(ifapplicable)ifthey'reoktouse.
*/ STATICint
xchk_btree_get_block( struct xchk_btree *bs, int level, union xfs_btree_ptr *pp, struct xfs_btree_block **pblock, struct xfs_buf **pbp)
{ int error;
while (level < cur->bc_nlevels) {
block = xfs_btree_get_block(cur, level, &bp);
if (level == 0) { /* End of leaf, pop back towards the root. */ if (cur->bc_levels[level].ptr >
be16_to_cpu(block->bb_numrecs)) {
xchk_btree_block_keys(bs, level, block); if (level < cur->bc_nlevels - 1)
cur->bc_levels[level + 1].ptr++;
level++; continue;
}
/* Records in order for scrub? */
xchk_btree_rec(bs);
/* Call out to the record checker. */
recp = xfs_btree_rec_addr(cur, cur->bc_levels[0].ptr,
block);
error = bs->scrub_rec(bs, recp); if (error) break; if (xchk_should_terminate(sc, &error) ||
(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) break;
cur->bc_levels[level].ptr++; continue;
}
/* End of node, pop back towards the root. */ if (cur->bc_levels[level].ptr >
be16_to_cpu(block->bb_numrecs)) {
xchk_btree_block_keys(bs, level, block); if (level < cur->bc_nlevels - 1)
cur->bc_levels[level + 1].ptr++;
level++; continue;
}
/* Keys in order for scrub? */
xchk_btree_key(bs, level);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.