18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Oracle.  All Rights Reserved.
48c2ecf20Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include "xfs.h"
78c2ecf20Sopenharmony_ci#include "xfs_fs.h"
88c2ecf20Sopenharmony_ci#include "xfs_shared.h"
98c2ecf20Sopenharmony_ci#include "xfs_format.h"
108c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h"
118c2ecf20Sopenharmony_ci#include "xfs_mount.h"
128c2ecf20Sopenharmony_ci#include "xfs_btree.h"
138c2ecf20Sopenharmony_ci#include "scrub/scrub.h"
148c2ecf20Sopenharmony_ci#include "scrub/common.h"
158c2ecf20Sopenharmony_ci#include "scrub/btree.h"
168c2ecf20Sopenharmony_ci#include "scrub/trace.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* btree scrubbing */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/*
218c2ecf20Sopenharmony_ci * Check for btree operation errors.  See the section about handling
228c2ecf20Sopenharmony_ci * operational errors in common.c.
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_cistatic bool
258c2ecf20Sopenharmony_ci__xchk_btree_process_error(
268c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
278c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
288c2ecf20Sopenharmony_ci	int			level,
298c2ecf20Sopenharmony_ci	int			*error,
308c2ecf20Sopenharmony_ci	__u32			errflag,
318c2ecf20Sopenharmony_ci	void			*ret_ip)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	if (*error == 0)
348c2ecf20Sopenharmony_ci		return true;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	switch (*error) {
378c2ecf20Sopenharmony_ci	case -EDEADLOCK:
388c2ecf20Sopenharmony_ci		/* Used to restart an op with deadlock avoidance. */
398c2ecf20Sopenharmony_ci		trace_xchk_deadlock_retry(sc->ip, sc->sm, *error);
408c2ecf20Sopenharmony_ci		break;
418c2ecf20Sopenharmony_ci	case -EFSBADCRC:
428c2ecf20Sopenharmony_ci	case -EFSCORRUPTED:
438c2ecf20Sopenharmony_ci		/* Note the badness but don't abort. */
448c2ecf20Sopenharmony_ci		sc->sm->sm_flags |= errflag;
458c2ecf20Sopenharmony_ci		*error = 0;
468c2ecf20Sopenharmony_ci		/* fall through */
478c2ecf20Sopenharmony_ci	default:
488c2ecf20Sopenharmony_ci		if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
498c2ecf20Sopenharmony_ci			trace_xchk_ifork_btree_op_error(sc, cur, level,
508c2ecf20Sopenharmony_ci					*error, ret_ip);
518c2ecf20Sopenharmony_ci		else
528c2ecf20Sopenharmony_ci			trace_xchk_btree_op_error(sc, cur, level,
538c2ecf20Sopenharmony_ci					*error, ret_ip);
548c2ecf20Sopenharmony_ci		break;
558c2ecf20Sopenharmony_ci	}
568c2ecf20Sopenharmony_ci	return false;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cibool
608c2ecf20Sopenharmony_cixchk_btree_process_error(
618c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
628c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
638c2ecf20Sopenharmony_ci	int			level,
648c2ecf20Sopenharmony_ci	int			*error)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	return __xchk_btree_process_error(sc, cur, level, error,
678c2ecf20Sopenharmony_ci			XFS_SCRUB_OFLAG_CORRUPT, __return_address);
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cibool
718c2ecf20Sopenharmony_cixchk_btree_xref_process_error(
728c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
738c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
748c2ecf20Sopenharmony_ci	int			level,
758c2ecf20Sopenharmony_ci	int			*error)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	return __xchk_btree_process_error(sc, cur, level, error,
788c2ecf20Sopenharmony_ci			XFS_SCRUB_OFLAG_XFAIL, __return_address);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/* Record btree block corruption. */
828c2ecf20Sopenharmony_cistatic void
838c2ecf20Sopenharmony_ci__xchk_btree_set_corrupt(
848c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
858c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
868c2ecf20Sopenharmony_ci	int			level,
878c2ecf20Sopenharmony_ci	__u32			errflag,
888c2ecf20Sopenharmony_ci	void			*ret_ip)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	sc->sm->sm_flags |= errflag;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
938c2ecf20Sopenharmony_ci		trace_xchk_ifork_btree_error(sc, cur, level,
948c2ecf20Sopenharmony_ci				ret_ip);
958c2ecf20Sopenharmony_ci	else
968c2ecf20Sopenharmony_ci		trace_xchk_btree_error(sc, cur, level,
978c2ecf20Sopenharmony_ci				ret_ip);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_civoid
1018c2ecf20Sopenharmony_cixchk_btree_set_corrupt(
1028c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
1038c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1048c2ecf20Sopenharmony_ci	int			level)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	__xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_CORRUPT,
1078c2ecf20Sopenharmony_ci			__return_address);
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_civoid
1118c2ecf20Sopenharmony_cixchk_btree_xref_set_corrupt(
1128c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
1138c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur,
1148c2ecf20Sopenharmony_ci	int			level)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	__xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_XCORRUPT,
1178c2ecf20Sopenharmony_ci			__return_address);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/*
1218c2ecf20Sopenharmony_ci * Make sure this record is in order and doesn't stray outside of the parent
1228c2ecf20Sopenharmony_ci * keys.
1238c2ecf20Sopenharmony_ci */
1248c2ecf20Sopenharmony_ciSTATIC void
1258c2ecf20Sopenharmony_cixchk_btree_rec(
1268c2ecf20Sopenharmony_ci	struct xchk_btree	*bs)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur = bs->cur;
1298c2ecf20Sopenharmony_ci	union xfs_btree_rec	*rec;
1308c2ecf20Sopenharmony_ci	union xfs_btree_key	key;
1318c2ecf20Sopenharmony_ci	union xfs_btree_key	hkey;
1328c2ecf20Sopenharmony_ci	union xfs_btree_key	*keyp;
1338c2ecf20Sopenharmony_ci	struct xfs_btree_block	*block;
1348c2ecf20Sopenharmony_ci	struct xfs_btree_block	*keyblock;
1358c2ecf20Sopenharmony_ci	struct xfs_buf		*bp;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	block = xfs_btree_get_block(cur, 0, &bp);
1388c2ecf20Sopenharmony_ci	rec = xfs_btree_rec_addr(cur, cur->bc_ptrs[0], block);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	trace_xchk_btree_rec(bs->sc, cur, 0);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/* If this isn't the first record, are they in order? */
1438c2ecf20Sopenharmony_ci	if (!bs->firstrec && !cur->bc_ops->recs_inorder(cur, &bs->lastrec, rec))
1448c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, cur, 0);
1458c2ecf20Sopenharmony_ci	bs->firstrec = false;
1468c2ecf20Sopenharmony_ci	memcpy(&bs->lastrec, rec, cur->bc_ops->rec_len);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (cur->bc_nlevels == 1)
1498c2ecf20Sopenharmony_ci		return;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/* Is this at least as large as the parent low key? */
1528c2ecf20Sopenharmony_ci	cur->bc_ops->init_key_from_rec(&key, rec);
1538c2ecf20Sopenharmony_ci	keyblock = xfs_btree_get_block(cur, 1, &bp);
1548c2ecf20Sopenharmony_ci	keyp = xfs_btree_key_addr(cur, cur->bc_ptrs[1], keyblock);
1558c2ecf20Sopenharmony_ci	if (cur->bc_ops->diff_two_keys(cur, &key, keyp) < 0)
1568c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, cur, 1);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
1598c2ecf20Sopenharmony_ci		return;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/* Is this no larger than the parent high key? */
1628c2ecf20Sopenharmony_ci	cur->bc_ops->init_high_key_from_rec(&hkey, rec);
1638c2ecf20Sopenharmony_ci	keyp = xfs_btree_high_key_addr(cur, cur->bc_ptrs[1], keyblock);
1648c2ecf20Sopenharmony_ci	if (cur->bc_ops->diff_two_keys(cur, keyp, &hkey) < 0)
1658c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, cur, 1);
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci/*
1698c2ecf20Sopenharmony_ci * Make sure this key is in order and doesn't stray outside of the parent
1708c2ecf20Sopenharmony_ci * keys.
1718c2ecf20Sopenharmony_ci */
1728c2ecf20Sopenharmony_ciSTATIC void
1738c2ecf20Sopenharmony_cixchk_btree_key(
1748c2ecf20Sopenharmony_ci	struct xchk_btree	*bs,
1758c2ecf20Sopenharmony_ci	int			level)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur = bs->cur;
1788c2ecf20Sopenharmony_ci	union xfs_btree_key	*key;
1798c2ecf20Sopenharmony_ci	union xfs_btree_key	*keyp;
1808c2ecf20Sopenharmony_ci	struct xfs_btree_block	*block;
1818c2ecf20Sopenharmony_ci	struct xfs_btree_block	*keyblock;
1828c2ecf20Sopenharmony_ci	struct xfs_buf		*bp;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	block = xfs_btree_get_block(cur, level, &bp);
1858c2ecf20Sopenharmony_ci	key = xfs_btree_key_addr(cur, cur->bc_ptrs[level], block);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	trace_xchk_btree_key(bs->sc, cur, level);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/* If this isn't the first key, are they in order? */
1908c2ecf20Sopenharmony_ci	if (!bs->firstkey[level] &&
1918c2ecf20Sopenharmony_ci	    !cur->bc_ops->keys_inorder(cur, &bs->lastkey[level], key))
1928c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, cur, level);
1938c2ecf20Sopenharmony_ci	bs->firstkey[level] = false;
1948c2ecf20Sopenharmony_ci	memcpy(&bs->lastkey[level], key, cur->bc_ops->key_len);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (level + 1 >= cur->bc_nlevels)
1978c2ecf20Sopenharmony_ci		return;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	/* Is this at least as large as the parent low key? */
2008c2ecf20Sopenharmony_ci	keyblock = xfs_btree_get_block(cur, level + 1, &bp);
2018c2ecf20Sopenharmony_ci	keyp = xfs_btree_key_addr(cur, cur->bc_ptrs[level + 1], keyblock);
2028c2ecf20Sopenharmony_ci	if (cur->bc_ops->diff_two_keys(cur, key, keyp) < 0)
2038c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, cur, level);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
2068c2ecf20Sopenharmony_ci		return;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* Is this no larger than the parent high key? */
2098c2ecf20Sopenharmony_ci	key = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level], block);
2108c2ecf20Sopenharmony_ci	keyp = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level + 1], keyblock);
2118c2ecf20Sopenharmony_ci	if (cur->bc_ops->diff_two_keys(cur, keyp, key) < 0)
2128c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, cur, level);
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/*
2168c2ecf20Sopenharmony_ci * Check a btree pointer.  Returns true if it's ok to use this pointer.
2178c2ecf20Sopenharmony_ci * Callers do not need to set the corrupt flag.
2188c2ecf20Sopenharmony_ci */
2198c2ecf20Sopenharmony_cistatic bool
2208c2ecf20Sopenharmony_cixchk_btree_ptr_ok(
2218c2ecf20Sopenharmony_ci	struct xchk_btree	*bs,
2228c2ecf20Sopenharmony_ci	int			level,
2238c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*ptr)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	bool			res;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	/* A btree rooted in an inode has no block pointer to the root. */
2288c2ecf20Sopenharmony_ci	if ((bs->cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
2298c2ecf20Sopenharmony_ci	    level == bs->cur->bc_nlevels)
2308c2ecf20Sopenharmony_ci		return true;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/* Otherwise, check the pointers. */
2338c2ecf20Sopenharmony_ci	if (bs->cur->bc_flags & XFS_BTREE_LONG_PTRS)
2348c2ecf20Sopenharmony_ci		res = xfs_btree_check_lptr(bs->cur, be64_to_cpu(ptr->l), level);
2358c2ecf20Sopenharmony_ci	else
2368c2ecf20Sopenharmony_ci		res = xfs_btree_check_sptr(bs->cur, be32_to_cpu(ptr->s), level);
2378c2ecf20Sopenharmony_ci	if (!res)
2388c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, bs->cur, level);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return res;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci/* Check that a btree block's sibling matches what we expect it. */
2448c2ecf20Sopenharmony_ciSTATIC int
2458c2ecf20Sopenharmony_cixchk_btree_block_check_sibling(
2468c2ecf20Sopenharmony_ci	struct xchk_btree	*bs,
2478c2ecf20Sopenharmony_ci	int			level,
2488c2ecf20Sopenharmony_ci	int			direction,
2498c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*sibling)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur = bs->cur;
2528c2ecf20Sopenharmony_ci	struct xfs_btree_block	*pblock;
2538c2ecf20Sopenharmony_ci	struct xfs_buf		*pbp;
2548c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*ncur = NULL;
2558c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*pp;
2568c2ecf20Sopenharmony_ci	int			success;
2578c2ecf20Sopenharmony_ci	int			error;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	error = xfs_btree_dup_cursor(cur, &ncur);
2608c2ecf20Sopenharmony_ci	if (!xchk_btree_process_error(bs->sc, cur, level + 1, &error) ||
2618c2ecf20Sopenharmony_ci	    !ncur)
2628c2ecf20Sopenharmony_ci		return error;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	/*
2658c2ecf20Sopenharmony_ci	 * If the pointer is null, we shouldn't be able to move the upper
2668c2ecf20Sopenharmony_ci	 * level pointer anywhere.
2678c2ecf20Sopenharmony_ci	 */
2688c2ecf20Sopenharmony_ci	if (xfs_btree_ptr_is_null(cur, sibling)) {
2698c2ecf20Sopenharmony_ci		if (direction > 0)
2708c2ecf20Sopenharmony_ci			error = xfs_btree_increment(ncur, level + 1, &success);
2718c2ecf20Sopenharmony_ci		else
2728c2ecf20Sopenharmony_ci			error = xfs_btree_decrement(ncur, level + 1, &success);
2738c2ecf20Sopenharmony_ci		if (error == 0 && success)
2748c2ecf20Sopenharmony_ci			xchk_btree_set_corrupt(bs->sc, cur, level);
2758c2ecf20Sopenharmony_ci		error = 0;
2768c2ecf20Sopenharmony_ci		goto out;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* Increment upper level pointer. */
2808c2ecf20Sopenharmony_ci	if (direction > 0)
2818c2ecf20Sopenharmony_ci		error = xfs_btree_increment(ncur, level + 1, &success);
2828c2ecf20Sopenharmony_ci	else
2838c2ecf20Sopenharmony_ci		error = xfs_btree_decrement(ncur, level + 1, &success);
2848c2ecf20Sopenharmony_ci	if (!xchk_btree_process_error(bs->sc, cur, level + 1, &error))
2858c2ecf20Sopenharmony_ci		goto out;
2868c2ecf20Sopenharmony_ci	if (!success) {
2878c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, cur, level + 1);
2888c2ecf20Sopenharmony_ci		goto out;
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/* Compare upper level pointer to sibling pointer. */
2928c2ecf20Sopenharmony_ci	pblock = xfs_btree_get_block(ncur, level + 1, &pbp);
2938c2ecf20Sopenharmony_ci	pp = xfs_btree_ptr_addr(ncur, ncur->bc_ptrs[level + 1], pblock);
2948c2ecf20Sopenharmony_ci	if (!xchk_btree_ptr_ok(bs, level + 1, pp))
2958c2ecf20Sopenharmony_ci		goto out;
2968c2ecf20Sopenharmony_ci	if (pbp)
2978c2ecf20Sopenharmony_ci		xchk_buffer_recheck(bs->sc, pbp);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if (xfs_btree_diff_two_ptrs(cur, pp, sibling))
3008c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, cur, level);
3018c2ecf20Sopenharmony_ciout:
3028c2ecf20Sopenharmony_ci	xfs_btree_del_cursor(ncur, XFS_BTREE_ERROR);
3038c2ecf20Sopenharmony_ci	return error;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci/* Check the siblings of a btree block. */
3078c2ecf20Sopenharmony_ciSTATIC int
3088c2ecf20Sopenharmony_cixchk_btree_block_check_siblings(
3098c2ecf20Sopenharmony_ci	struct xchk_btree	*bs,
3108c2ecf20Sopenharmony_ci	struct xfs_btree_block	*block)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur = bs->cur;
3138c2ecf20Sopenharmony_ci	union xfs_btree_ptr	leftsib;
3148c2ecf20Sopenharmony_ci	union xfs_btree_ptr	rightsib;
3158c2ecf20Sopenharmony_ci	int			level;
3168c2ecf20Sopenharmony_ci	int			error = 0;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	xfs_btree_get_sibling(cur, block, &leftsib, XFS_BB_LEFTSIB);
3198c2ecf20Sopenharmony_ci	xfs_btree_get_sibling(cur, block, &rightsib, XFS_BB_RIGHTSIB);
3208c2ecf20Sopenharmony_ci	level = xfs_btree_get_level(block);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* Root block should never have siblings. */
3238c2ecf20Sopenharmony_ci	if (level == cur->bc_nlevels - 1) {
3248c2ecf20Sopenharmony_ci		if (!xfs_btree_ptr_is_null(cur, &leftsib) ||
3258c2ecf20Sopenharmony_ci		    !xfs_btree_ptr_is_null(cur, &rightsib))
3268c2ecf20Sopenharmony_ci			xchk_btree_set_corrupt(bs->sc, cur, level);
3278c2ecf20Sopenharmony_ci		goto out;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/*
3318c2ecf20Sopenharmony_ci	 * Does the left & right sibling pointers match the adjacent
3328c2ecf20Sopenharmony_ci	 * parent level pointers?
3338c2ecf20Sopenharmony_ci	 * (These function absorbs error codes for us.)
3348c2ecf20Sopenharmony_ci	 */
3358c2ecf20Sopenharmony_ci	error = xchk_btree_block_check_sibling(bs, level, -1, &leftsib);
3368c2ecf20Sopenharmony_ci	if (error)
3378c2ecf20Sopenharmony_ci		return error;
3388c2ecf20Sopenharmony_ci	error = xchk_btree_block_check_sibling(bs, level, 1, &rightsib);
3398c2ecf20Sopenharmony_ci	if (error)
3408c2ecf20Sopenharmony_ci		return error;
3418c2ecf20Sopenharmony_ciout:
3428c2ecf20Sopenharmony_ci	return error;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistruct check_owner {
3468c2ecf20Sopenharmony_ci	struct list_head	list;
3478c2ecf20Sopenharmony_ci	xfs_daddr_t		daddr;
3488c2ecf20Sopenharmony_ci	int			level;
3498c2ecf20Sopenharmony_ci};
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci/*
3528c2ecf20Sopenharmony_ci * Make sure this btree block isn't in the free list and that there's
3538c2ecf20Sopenharmony_ci * an rmap record for it.
3548c2ecf20Sopenharmony_ci */
3558c2ecf20Sopenharmony_ciSTATIC int
3568c2ecf20Sopenharmony_cixchk_btree_check_block_owner(
3578c2ecf20Sopenharmony_ci	struct xchk_btree	*bs,
3588c2ecf20Sopenharmony_ci	int			level,
3598c2ecf20Sopenharmony_ci	xfs_daddr_t		daddr)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	xfs_agnumber_t		agno;
3628c2ecf20Sopenharmony_ci	xfs_agblock_t		agbno;
3638c2ecf20Sopenharmony_ci	xfs_btnum_t		btnum;
3648c2ecf20Sopenharmony_ci	bool			init_sa;
3658c2ecf20Sopenharmony_ci	int			error = 0;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (!bs->cur)
3688c2ecf20Sopenharmony_ci		return 0;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	btnum = bs->cur->bc_btnum;
3718c2ecf20Sopenharmony_ci	agno = xfs_daddr_to_agno(bs->cur->bc_mp, daddr);
3728c2ecf20Sopenharmony_ci	agbno = xfs_daddr_to_agbno(bs->cur->bc_mp, daddr);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	init_sa = bs->cur->bc_flags & XFS_BTREE_LONG_PTRS;
3758c2ecf20Sopenharmony_ci	if (init_sa) {
3768c2ecf20Sopenharmony_ci		error = xchk_ag_init(bs->sc, agno, &bs->sc->sa);
3778c2ecf20Sopenharmony_ci		if (!xchk_btree_xref_process_error(bs->sc, bs->cur,
3788c2ecf20Sopenharmony_ci				level, &error))
3798c2ecf20Sopenharmony_ci			return error;
3808c2ecf20Sopenharmony_ci	}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	xchk_xref_is_used_space(bs->sc, agbno, 1);
3838c2ecf20Sopenharmony_ci	/*
3848c2ecf20Sopenharmony_ci	 * The bnobt scrubber aliases bs->cur to bs->sc->sa.bno_cur, so we
3858c2ecf20Sopenharmony_ci	 * have to nullify it (to shut down further block owner checks) if
3868c2ecf20Sopenharmony_ci	 * self-xref encounters problems.
3878c2ecf20Sopenharmony_ci	 */
3888c2ecf20Sopenharmony_ci	if (!bs->sc->sa.bno_cur && btnum == XFS_BTNUM_BNO)
3898c2ecf20Sopenharmony_ci		bs->cur = NULL;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	xchk_xref_is_owned_by(bs->sc, agbno, 1, bs->oinfo);
3928c2ecf20Sopenharmony_ci	if (!bs->sc->sa.rmap_cur && btnum == XFS_BTNUM_RMAP)
3938c2ecf20Sopenharmony_ci		bs->cur = NULL;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (init_sa)
3968c2ecf20Sopenharmony_ci		xchk_ag_free(bs->sc, &bs->sc->sa);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	return error;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci/* Check the owner of a btree block. */
4028c2ecf20Sopenharmony_ciSTATIC int
4038c2ecf20Sopenharmony_cixchk_btree_check_owner(
4048c2ecf20Sopenharmony_ci	struct xchk_btree	*bs,
4058c2ecf20Sopenharmony_ci	int			level,
4068c2ecf20Sopenharmony_ci	struct xfs_buf		*bp)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur = bs->cur;
4098c2ecf20Sopenharmony_ci	struct check_owner	*co;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/*
4128c2ecf20Sopenharmony_ci	 * In theory, xfs_btree_get_block should only give us a null buffer
4138c2ecf20Sopenharmony_ci	 * pointer for the root of a root-in-inode btree type, but we need
4148c2ecf20Sopenharmony_ci	 * to check defensively here in case the cursor state is also screwed
4158c2ecf20Sopenharmony_ci	 * up.
4168c2ecf20Sopenharmony_ci	 */
4178c2ecf20Sopenharmony_ci	if (bp == NULL) {
4188c2ecf20Sopenharmony_ci		if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE))
4198c2ecf20Sopenharmony_ci			xchk_btree_set_corrupt(bs->sc, bs->cur, level);
4208c2ecf20Sopenharmony_ci		return 0;
4218c2ecf20Sopenharmony_ci	}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/*
4248c2ecf20Sopenharmony_ci	 * We want to cross-reference each btree block with the bnobt
4258c2ecf20Sopenharmony_ci	 * and the rmapbt.  We cannot cross-reference the bnobt or
4268c2ecf20Sopenharmony_ci	 * rmapbt while scanning the bnobt or rmapbt, respectively,
4278c2ecf20Sopenharmony_ci	 * because we cannot alter the cursor and we'd prefer not to
4288c2ecf20Sopenharmony_ci	 * duplicate cursors.  Therefore, save the buffer daddr for
4298c2ecf20Sopenharmony_ci	 * later scanning.
4308c2ecf20Sopenharmony_ci	 */
4318c2ecf20Sopenharmony_ci	if (cur->bc_btnum == XFS_BTNUM_BNO || cur->bc_btnum == XFS_BTNUM_RMAP) {
4328c2ecf20Sopenharmony_ci		co = kmem_alloc(sizeof(struct check_owner),
4338c2ecf20Sopenharmony_ci				KM_MAYFAIL);
4348c2ecf20Sopenharmony_ci		if (!co)
4358c2ecf20Sopenharmony_ci			return -ENOMEM;
4368c2ecf20Sopenharmony_ci		co->level = level;
4378c2ecf20Sopenharmony_ci		co->daddr = XFS_BUF_ADDR(bp);
4388c2ecf20Sopenharmony_ci		list_add_tail(&co->list, &bs->to_check);
4398c2ecf20Sopenharmony_ci		return 0;
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	return xchk_btree_check_block_owner(bs, level, XFS_BUF_ADDR(bp));
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci/*
4468c2ecf20Sopenharmony_ci * Check that this btree block has at least minrecs records or is one of the
4478c2ecf20Sopenharmony_ci * special blocks that don't require that.
4488c2ecf20Sopenharmony_ci */
4498c2ecf20Sopenharmony_ciSTATIC void
4508c2ecf20Sopenharmony_cixchk_btree_check_minrecs(
4518c2ecf20Sopenharmony_ci	struct xchk_btree	*bs,
4528c2ecf20Sopenharmony_ci	int			level,
4538c2ecf20Sopenharmony_ci	struct xfs_btree_block	*block)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur = bs->cur;
4568c2ecf20Sopenharmony_ci	unsigned int		root_level = cur->bc_nlevels - 1;
4578c2ecf20Sopenharmony_ci	unsigned int		numrecs = be16_to_cpu(block->bb_numrecs);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	/* More records than minrecs means the block is ok. */
4608c2ecf20Sopenharmony_ci	if (numrecs >= cur->bc_ops->get_minrecs(cur, level))
4618c2ecf20Sopenharmony_ci		return;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	/*
4648c2ecf20Sopenharmony_ci	 * For btrees rooted in the inode, it's possible that the root block
4658c2ecf20Sopenharmony_ci	 * contents spilled into a regular ondisk block because there wasn't
4668c2ecf20Sopenharmony_ci	 * enough space in the inode root.  The number of records in that
4678c2ecf20Sopenharmony_ci	 * child block might be less than the standard minrecs, but that's ok
4688c2ecf20Sopenharmony_ci	 * provided that there's only one direct child of the root.
4698c2ecf20Sopenharmony_ci	 */
4708c2ecf20Sopenharmony_ci	if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
4718c2ecf20Sopenharmony_ci	    level == cur->bc_nlevels - 2) {
4728c2ecf20Sopenharmony_ci		struct xfs_btree_block	*root_block;
4738c2ecf20Sopenharmony_ci		struct xfs_buf		*root_bp;
4748c2ecf20Sopenharmony_ci		int			root_maxrecs;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci		root_block = xfs_btree_get_block(cur, root_level, &root_bp);
4778c2ecf20Sopenharmony_ci		root_maxrecs = cur->bc_ops->get_dmaxrecs(cur, root_level);
4788c2ecf20Sopenharmony_ci		if (be16_to_cpu(root_block->bb_numrecs) != 1 ||
4798c2ecf20Sopenharmony_ci		    numrecs <= root_maxrecs)
4808c2ecf20Sopenharmony_ci			xchk_btree_set_corrupt(bs->sc, cur, level);
4818c2ecf20Sopenharmony_ci		return;
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	/*
4858c2ecf20Sopenharmony_ci	 * Otherwise, only the root level is allowed to have fewer than minrecs
4868c2ecf20Sopenharmony_ci	 * records or keyptrs.
4878c2ecf20Sopenharmony_ci	 */
4888c2ecf20Sopenharmony_ci	if (level < root_level)
4898c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, cur, level);
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci/*
4938c2ecf20Sopenharmony_ci * Grab and scrub a btree block given a btree pointer.  Returns block
4948c2ecf20Sopenharmony_ci * and buffer pointers (if applicable) if they're ok to use.
4958c2ecf20Sopenharmony_ci */
4968c2ecf20Sopenharmony_ciSTATIC int
4978c2ecf20Sopenharmony_cixchk_btree_get_block(
4988c2ecf20Sopenharmony_ci	struct xchk_btree	*bs,
4998c2ecf20Sopenharmony_ci	int			level,
5008c2ecf20Sopenharmony_ci	union xfs_btree_ptr	*pp,
5018c2ecf20Sopenharmony_ci	struct xfs_btree_block	**pblock,
5028c2ecf20Sopenharmony_ci	struct xfs_buf		**pbp)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	xfs_failaddr_t		failed_at;
5058c2ecf20Sopenharmony_ci	int			error;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	*pblock = NULL;
5088c2ecf20Sopenharmony_ci	*pbp = NULL;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	error = xfs_btree_lookup_get_block(bs->cur, level, pp, pblock);
5118c2ecf20Sopenharmony_ci	if (!xchk_btree_process_error(bs->sc, bs->cur, level, &error) ||
5128c2ecf20Sopenharmony_ci	    !*pblock)
5138c2ecf20Sopenharmony_ci		return error;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	xfs_btree_get_block(bs->cur, level, pbp);
5168c2ecf20Sopenharmony_ci	if (bs->cur->bc_flags & XFS_BTREE_LONG_PTRS)
5178c2ecf20Sopenharmony_ci		failed_at = __xfs_btree_check_lblock(bs->cur, *pblock,
5188c2ecf20Sopenharmony_ci				level, *pbp);
5198c2ecf20Sopenharmony_ci	else
5208c2ecf20Sopenharmony_ci		failed_at = __xfs_btree_check_sblock(bs->cur, *pblock,
5218c2ecf20Sopenharmony_ci				 level, *pbp);
5228c2ecf20Sopenharmony_ci	if (failed_at) {
5238c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, bs->cur, level);
5248c2ecf20Sopenharmony_ci		return 0;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci	if (*pbp)
5278c2ecf20Sopenharmony_ci		xchk_buffer_recheck(bs->sc, *pbp);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	xchk_btree_check_minrecs(bs, level, *pblock);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	/*
5328c2ecf20Sopenharmony_ci	 * Check the block's owner; this function absorbs error codes
5338c2ecf20Sopenharmony_ci	 * for us.
5348c2ecf20Sopenharmony_ci	 */
5358c2ecf20Sopenharmony_ci	error = xchk_btree_check_owner(bs, level, *pbp);
5368c2ecf20Sopenharmony_ci	if (error)
5378c2ecf20Sopenharmony_ci		return error;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	/*
5408c2ecf20Sopenharmony_ci	 * Check the block's siblings; this function absorbs error codes
5418c2ecf20Sopenharmony_ci	 * for us.
5428c2ecf20Sopenharmony_ci	 */
5438c2ecf20Sopenharmony_ci	return xchk_btree_block_check_siblings(bs, *pblock);
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci/*
5478c2ecf20Sopenharmony_ci * Check that the low and high keys of this block match the keys stored
5488c2ecf20Sopenharmony_ci * in the parent block.
5498c2ecf20Sopenharmony_ci */
5508c2ecf20Sopenharmony_ciSTATIC void
5518c2ecf20Sopenharmony_cixchk_btree_block_keys(
5528c2ecf20Sopenharmony_ci	struct xchk_btree	*bs,
5538c2ecf20Sopenharmony_ci	int			level,
5548c2ecf20Sopenharmony_ci	struct xfs_btree_block	*block)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	union xfs_btree_key	block_keys;
5578c2ecf20Sopenharmony_ci	struct xfs_btree_cur	*cur = bs->cur;
5588c2ecf20Sopenharmony_ci	union xfs_btree_key	*high_bk;
5598c2ecf20Sopenharmony_ci	union xfs_btree_key	*parent_keys;
5608c2ecf20Sopenharmony_ci	union xfs_btree_key	*high_pk;
5618c2ecf20Sopenharmony_ci	struct xfs_btree_block	*parent_block;
5628c2ecf20Sopenharmony_ci	struct xfs_buf		*bp;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	if (level >= cur->bc_nlevels - 1)
5658c2ecf20Sopenharmony_ci		return;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	/* Calculate the keys for this block. */
5688c2ecf20Sopenharmony_ci	xfs_btree_get_keys(cur, block, &block_keys);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	/* Obtain the parent's copy of the keys for this block. */
5718c2ecf20Sopenharmony_ci	parent_block = xfs_btree_get_block(cur, level + 1, &bp);
5728c2ecf20Sopenharmony_ci	parent_keys = xfs_btree_key_addr(cur, cur->bc_ptrs[level + 1],
5738c2ecf20Sopenharmony_ci			parent_block);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	if (cur->bc_ops->diff_two_keys(cur, &block_keys, parent_keys) != 0)
5768c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, cur, 1);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
5798c2ecf20Sopenharmony_ci		return;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	/* Get high keys */
5828c2ecf20Sopenharmony_ci	high_bk = xfs_btree_high_key_from_key(cur, &block_keys);
5838c2ecf20Sopenharmony_ci	high_pk = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level + 1],
5848c2ecf20Sopenharmony_ci			parent_block);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if (cur->bc_ops->diff_two_keys(cur, high_bk, high_pk) != 0)
5878c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(bs->sc, cur, 1);
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci/*
5918c2ecf20Sopenharmony_ci * Visit all nodes and leaves of a btree.  Check that all pointers and
5928c2ecf20Sopenharmony_ci * records are in order, that the keys reflect the records, and use a callback
5938c2ecf20Sopenharmony_ci * so that the caller can verify individual records.
5948c2ecf20Sopenharmony_ci */
5958c2ecf20Sopenharmony_ciint
5968c2ecf20Sopenharmony_cixchk_btree(
5978c2ecf20Sopenharmony_ci	struct xfs_scrub		*sc,
5988c2ecf20Sopenharmony_ci	struct xfs_btree_cur		*cur,
5998c2ecf20Sopenharmony_ci	xchk_btree_rec_fn		scrub_fn,
6008c2ecf20Sopenharmony_ci	const struct xfs_owner_info	*oinfo,
6018c2ecf20Sopenharmony_ci	void				*private)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	struct xchk_btree		bs = {
6048c2ecf20Sopenharmony_ci		.cur			= cur,
6058c2ecf20Sopenharmony_ci		.scrub_rec		= scrub_fn,
6068c2ecf20Sopenharmony_ci		.oinfo			= oinfo,
6078c2ecf20Sopenharmony_ci		.firstrec		= true,
6088c2ecf20Sopenharmony_ci		.private		= private,
6098c2ecf20Sopenharmony_ci		.sc			= sc,
6108c2ecf20Sopenharmony_ci	};
6118c2ecf20Sopenharmony_ci	union xfs_btree_ptr		ptr;
6128c2ecf20Sopenharmony_ci	union xfs_btree_ptr		*pp;
6138c2ecf20Sopenharmony_ci	union xfs_btree_rec		*recp;
6148c2ecf20Sopenharmony_ci	struct xfs_btree_block		*block;
6158c2ecf20Sopenharmony_ci	int				level;
6168c2ecf20Sopenharmony_ci	struct xfs_buf			*bp;
6178c2ecf20Sopenharmony_ci	struct check_owner		*co;
6188c2ecf20Sopenharmony_ci	struct check_owner		*n;
6198c2ecf20Sopenharmony_ci	int				i;
6208c2ecf20Sopenharmony_ci	int				error = 0;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	/* Initialize scrub state */
6238c2ecf20Sopenharmony_ci	for (i = 0; i < XFS_BTREE_MAXLEVELS; i++)
6248c2ecf20Sopenharmony_ci		bs.firstkey[i] = true;
6258c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&bs.to_check);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	/* Don't try to check a tree with a height we can't handle. */
6288c2ecf20Sopenharmony_ci	if (cur->bc_nlevels > XFS_BTREE_MAXLEVELS) {
6298c2ecf20Sopenharmony_ci		xchk_btree_set_corrupt(sc, cur, 0);
6308c2ecf20Sopenharmony_ci		goto out;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	/*
6348c2ecf20Sopenharmony_ci	 * Load the root of the btree.  The helper function absorbs
6358c2ecf20Sopenharmony_ci	 * error codes for us.
6368c2ecf20Sopenharmony_ci	 */
6378c2ecf20Sopenharmony_ci	level = cur->bc_nlevels - 1;
6388c2ecf20Sopenharmony_ci	cur->bc_ops->init_ptr_from_cur(cur, &ptr);
6398c2ecf20Sopenharmony_ci	if (!xchk_btree_ptr_ok(&bs, cur->bc_nlevels, &ptr))
6408c2ecf20Sopenharmony_ci		goto out;
6418c2ecf20Sopenharmony_ci	error = xchk_btree_get_block(&bs, level, &ptr, &block, &bp);
6428c2ecf20Sopenharmony_ci	if (error || !block)
6438c2ecf20Sopenharmony_ci		goto out;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	cur->bc_ptrs[level] = 1;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	while (level < cur->bc_nlevels) {
6488c2ecf20Sopenharmony_ci		block = xfs_btree_get_block(cur, level, &bp);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci		if (level == 0) {
6518c2ecf20Sopenharmony_ci			/* End of leaf, pop back towards the root. */
6528c2ecf20Sopenharmony_ci			if (cur->bc_ptrs[level] >
6538c2ecf20Sopenharmony_ci			    be16_to_cpu(block->bb_numrecs)) {
6548c2ecf20Sopenharmony_ci				xchk_btree_block_keys(&bs, level, block);
6558c2ecf20Sopenharmony_ci				if (level < cur->bc_nlevels - 1)
6568c2ecf20Sopenharmony_ci					cur->bc_ptrs[level + 1]++;
6578c2ecf20Sopenharmony_ci				level++;
6588c2ecf20Sopenharmony_ci				continue;
6598c2ecf20Sopenharmony_ci			}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci			/* Records in order for scrub? */
6628c2ecf20Sopenharmony_ci			xchk_btree_rec(&bs);
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci			/* Call out to the record checker. */
6658c2ecf20Sopenharmony_ci			recp = xfs_btree_rec_addr(cur, cur->bc_ptrs[0], block);
6668c2ecf20Sopenharmony_ci			error = bs.scrub_rec(&bs, recp);
6678c2ecf20Sopenharmony_ci			if (error)
6688c2ecf20Sopenharmony_ci				break;
6698c2ecf20Sopenharmony_ci			if (xchk_should_terminate(sc, &error) ||
6708c2ecf20Sopenharmony_ci			    (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
6718c2ecf20Sopenharmony_ci				break;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci			cur->bc_ptrs[level]++;
6748c2ecf20Sopenharmony_ci			continue;
6758c2ecf20Sopenharmony_ci		}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci		/* End of node, pop back towards the root. */
6788c2ecf20Sopenharmony_ci		if (cur->bc_ptrs[level] > be16_to_cpu(block->bb_numrecs)) {
6798c2ecf20Sopenharmony_ci			xchk_btree_block_keys(&bs, level, block);
6808c2ecf20Sopenharmony_ci			if (level < cur->bc_nlevels - 1)
6818c2ecf20Sopenharmony_ci				cur->bc_ptrs[level + 1]++;
6828c2ecf20Sopenharmony_ci			level++;
6838c2ecf20Sopenharmony_ci			continue;
6848c2ecf20Sopenharmony_ci		}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci		/* Keys in order for scrub? */
6878c2ecf20Sopenharmony_ci		xchk_btree_key(&bs, level);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci		/* Drill another level deeper. */
6908c2ecf20Sopenharmony_ci		pp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[level], block);
6918c2ecf20Sopenharmony_ci		if (!xchk_btree_ptr_ok(&bs, level, pp)) {
6928c2ecf20Sopenharmony_ci			cur->bc_ptrs[level]++;
6938c2ecf20Sopenharmony_ci			continue;
6948c2ecf20Sopenharmony_ci		}
6958c2ecf20Sopenharmony_ci		level--;
6968c2ecf20Sopenharmony_ci		error = xchk_btree_get_block(&bs, level, pp, &block, &bp);
6978c2ecf20Sopenharmony_ci		if (error || !block)
6988c2ecf20Sopenharmony_ci			goto out;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci		cur->bc_ptrs[level] = 1;
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ciout:
7048c2ecf20Sopenharmony_ci	/* Process deferred owner checks on btree blocks. */
7058c2ecf20Sopenharmony_ci	list_for_each_entry_safe(co, n, &bs.to_check, list) {
7068c2ecf20Sopenharmony_ci		if (!error && bs.cur)
7078c2ecf20Sopenharmony_ci			error = xchk_btree_check_block_owner(&bs,
7088c2ecf20Sopenharmony_ci					co->level, co->daddr);
7098c2ecf20Sopenharmony_ci		list_del(&co->list);
7108c2ecf20Sopenharmony_ci		kmem_free(co);
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	return error;
7148c2ecf20Sopenharmony_ci}
715