Commit c99f99fa authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: check btree keys reflect the child block



When scrub is checking a non-root btree block, it should make sure that
the keys in the parent btree block accurately capture the keyspace that
the child block stores.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
parent 38384569
Loading
Loading
Loading
Loading
+48 −1
Original line number Diff line number Diff line
@@ -529,6 +529,48 @@ xchk_btree_check_minrecs(
		xchk_btree_set_corrupt(bs->sc, cur, level);
}

/*
 * If this btree block has a parent, make sure that the parent's keys capture
 * the keyspace contained in this block.
 */
STATIC void
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 (cur->bc_ops->diff_two_keys(cur, &block_key, parent_low_key)) {
		xchk_btree_set_corrupt(bs->sc, bs->cur, level);
		return;
	}

	if (!(cur->bc_flags & XFS_BTREE_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 (cur->bc_ops->diff_two_keys(cur, block_high_key, parent_high_key))
		xchk_btree_set_corrupt(bs->sc, bs->cur, level);
}

/*
 * Grab and scrub a btree block given a btree pointer.  Returns block
 * and buffer pointers (if applicable) if they're ok to use.
@@ -580,7 +622,12 @@ xchk_btree_get_block(
	 * Check the block's siblings; this function absorbs error codes
	 * for us.
	 */
	return xchk_btree_block_check_siblings(bs, *pblock);
	error = xchk_btree_block_check_siblings(bs, *pblock);
	if (error)
		return error;

	xchk_btree_block_check_keys(bs, level, *pblock);
	return 0;
}

/*