xref: /OK3568_Linux_fs/kernel/fs/xfs/scrub/btree.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2017 Oracle.  All Rights Reserved.
4*4882a593Smuzhiyun  * Author: Darrick J. Wong <darrick.wong@oracle.com>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun #include "xfs.h"
7*4882a593Smuzhiyun #include "xfs_fs.h"
8*4882a593Smuzhiyun #include "xfs_shared.h"
9*4882a593Smuzhiyun #include "xfs_format.h"
10*4882a593Smuzhiyun #include "xfs_trans_resv.h"
11*4882a593Smuzhiyun #include "xfs_mount.h"
12*4882a593Smuzhiyun #include "xfs_btree.h"
13*4882a593Smuzhiyun #include "scrub/scrub.h"
14*4882a593Smuzhiyun #include "scrub/common.h"
15*4882a593Smuzhiyun #include "scrub/btree.h"
16*4882a593Smuzhiyun #include "scrub/trace.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun /* btree scrubbing */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /*
21*4882a593Smuzhiyun  * Check for btree operation errors.  See the section about handling
22*4882a593Smuzhiyun  * operational errors in common.c.
23*4882a593Smuzhiyun  */
24*4882a593Smuzhiyun static bool
__xchk_btree_process_error(struct xfs_scrub * sc,struct xfs_btree_cur * cur,int level,int * error,__u32 errflag,void * ret_ip)25*4882a593Smuzhiyun __xchk_btree_process_error(
26*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
27*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur,
28*4882a593Smuzhiyun 	int			level,
29*4882a593Smuzhiyun 	int			*error,
30*4882a593Smuzhiyun 	__u32			errflag,
31*4882a593Smuzhiyun 	void			*ret_ip)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	if (*error == 0)
34*4882a593Smuzhiyun 		return true;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	switch (*error) {
37*4882a593Smuzhiyun 	case -EDEADLOCK:
38*4882a593Smuzhiyun 		/* Used to restart an op with deadlock avoidance. */
39*4882a593Smuzhiyun 		trace_xchk_deadlock_retry(sc->ip, sc->sm, *error);
40*4882a593Smuzhiyun 		break;
41*4882a593Smuzhiyun 	case -EFSBADCRC:
42*4882a593Smuzhiyun 	case -EFSCORRUPTED:
43*4882a593Smuzhiyun 		/* Note the badness but don't abort. */
44*4882a593Smuzhiyun 		sc->sm->sm_flags |= errflag;
45*4882a593Smuzhiyun 		*error = 0;
46*4882a593Smuzhiyun 		/* fall through */
47*4882a593Smuzhiyun 	default:
48*4882a593Smuzhiyun 		if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
49*4882a593Smuzhiyun 			trace_xchk_ifork_btree_op_error(sc, cur, level,
50*4882a593Smuzhiyun 					*error, ret_ip);
51*4882a593Smuzhiyun 		else
52*4882a593Smuzhiyun 			trace_xchk_btree_op_error(sc, cur, level,
53*4882a593Smuzhiyun 					*error, ret_ip);
54*4882a593Smuzhiyun 		break;
55*4882a593Smuzhiyun 	}
56*4882a593Smuzhiyun 	return false;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun bool
xchk_btree_process_error(struct xfs_scrub * sc,struct xfs_btree_cur * cur,int level,int * error)60*4882a593Smuzhiyun xchk_btree_process_error(
61*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
62*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur,
63*4882a593Smuzhiyun 	int			level,
64*4882a593Smuzhiyun 	int			*error)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	return __xchk_btree_process_error(sc, cur, level, error,
67*4882a593Smuzhiyun 			XFS_SCRUB_OFLAG_CORRUPT, __return_address);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun bool
xchk_btree_xref_process_error(struct xfs_scrub * sc,struct xfs_btree_cur * cur,int level,int * error)71*4882a593Smuzhiyun xchk_btree_xref_process_error(
72*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
73*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur,
74*4882a593Smuzhiyun 	int			level,
75*4882a593Smuzhiyun 	int			*error)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	return __xchk_btree_process_error(sc, cur, level, error,
78*4882a593Smuzhiyun 			XFS_SCRUB_OFLAG_XFAIL, __return_address);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /* Record btree block corruption. */
82*4882a593Smuzhiyun static void
__xchk_btree_set_corrupt(struct xfs_scrub * sc,struct xfs_btree_cur * cur,int level,__u32 errflag,void * ret_ip)83*4882a593Smuzhiyun __xchk_btree_set_corrupt(
84*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
85*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur,
86*4882a593Smuzhiyun 	int			level,
87*4882a593Smuzhiyun 	__u32			errflag,
88*4882a593Smuzhiyun 	void			*ret_ip)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	sc->sm->sm_flags |= errflag;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
93*4882a593Smuzhiyun 		trace_xchk_ifork_btree_error(sc, cur, level,
94*4882a593Smuzhiyun 				ret_ip);
95*4882a593Smuzhiyun 	else
96*4882a593Smuzhiyun 		trace_xchk_btree_error(sc, cur, level,
97*4882a593Smuzhiyun 				ret_ip);
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun void
xchk_btree_set_corrupt(struct xfs_scrub * sc,struct xfs_btree_cur * cur,int level)101*4882a593Smuzhiyun xchk_btree_set_corrupt(
102*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
103*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur,
104*4882a593Smuzhiyun 	int			level)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	__xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_CORRUPT,
107*4882a593Smuzhiyun 			__return_address);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun void
xchk_btree_xref_set_corrupt(struct xfs_scrub * sc,struct xfs_btree_cur * cur,int level)111*4882a593Smuzhiyun xchk_btree_xref_set_corrupt(
112*4882a593Smuzhiyun 	struct xfs_scrub	*sc,
113*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur,
114*4882a593Smuzhiyun 	int			level)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	__xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_XCORRUPT,
117*4882a593Smuzhiyun 			__return_address);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun /*
121*4882a593Smuzhiyun  * Make sure this record is in order and doesn't stray outside of the parent
122*4882a593Smuzhiyun  * keys.
123*4882a593Smuzhiyun  */
124*4882a593Smuzhiyun STATIC void
xchk_btree_rec(struct xchk_btree * bs)125*4882a593Smuzhiyun xchk_btree_rec(
126*4882a593Smuzhiyun 	struct xchk_btree	*bs)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur = bs->cur;
129*4882a593Smuzhiyun 	union xfs_btree_rec	*rec;
130*4882a593Smuzhiyun 	union xfs_btree_key	key;
131*4882a593Smuzhiyun 	union xfs_btree_key	hkey;
132*4882a593Smuzhiyun 	union xfs_btree_key	*keyp;
133*4882a593Smuzhiyun 	struct xfs_btree_block	*block;
134*4882a593Smuzhiyun 	struct xfs_btree_block	*keyblock;
135*4882a593Smuzhiyun 	struct xfs_buf		*bp;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	block = xfs_btree_get_block(cur, 0, &bp);
138*4882a593Smuzhiyun 	rec = xfs_btree_rec_addr(cur, cur->bc_ptrs[0], block);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	trace_xchk_btree_rec(bs->sc, cur, 0);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	/* If this isn't the first record, are they in order? */
143*4882a593Smuzhiyun 	if (!bs->firstrec && !cur->bc_ops->recs_inorder(cur, &bs->lastrec, rec))
144*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, cur, 0);
145*4882a593Smuzhiyun 	bs->firstrec = false;
146*4882a593Smuzhiyun 	memcpy(&bs->lastrec, rec, cur->bc_ops->rec_len);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (cur->bc_nlevels == 1)
149*4882a593Smuzhiyun 		return;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	/* Is this at least as large as the parent low key? */
152*4882a593Smuzhiyun 	cur->bc_ops->init_key_from_rec(&key, rec);
153*4882a593Smuzhiyun 	keyblock = xfs_btree_get_block(cur, 1, &bp);
154*4882a593Smuzhiyun 	keyp = xfs_btree_key_addr(cur, cur->bc_ptrs[1], keyblock);
155*4882a593Smuzhiyun 	if (cur->bc_ops->diff_two_keys(cur, &key, keyp) < 0)
156*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, cur, 1);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
159*4882a593Smuzhiyun 		return;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	/* Is this no larger than the parent high key? */
162*4882a593Smuzhiyun 	cur->bc_ops->init_high_key_from_rec(&hkey, rec);
163*4882a593Smuzhiyun 	keyp = xfs_btree_high_key_addr(cur, cur->bc_ptrs[1], keyblock);
164*4882a593Smuzhiyun 	if (cur->bc_ops->diff_two_keys(cur, keyp, &hkey) < 0)
165*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, cur, 1);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun /*
169*4882a593Smuzhiyun  * Make sure this key is in order and doesn't stray outside of the parent
170*4882a593Smuzhiyun  * keys.
171*4882a593Smuzhiyun  */
172*4882a593Smuzhiyun STATIC void
xchk_btree_key(struct xchk_btree * bs,int level)173*4882a593Smuzhiyun xchk_btree_key(
174*4882a593Smuzhiyun 	struct xchk_btree	*bs,
175*4882a593Smuzhiyun 	int			level)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur = bs->cur;
178*4882a593Smuzhiyun 	union xfs_btree_key	*key;
179*4882a593Smuzhiyun 	union xfs_btree_key	*keyp;
180*4882a593Smuzhiyun 	struct xfs_btree_block	*block;
181*4882a593Smuzhiyun 	struct xfs_btree_block	*keyblock;
182*4882a593Smuzhiyun 	struct xfs_buf		*bp;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	block = xfs_btree_get_block(cur, level, &bp);
185*4882a593Smuzhiyun 	key = xfs_btree_key_addr(cur, cur->bc_ptrs[level], block);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	trace_xchk_btree_key(bs->sc, cur, level);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	/* If this isn't the first key, are they in order? */
190*4882a593Smuzhiyun 	if (!bs->firstkey[level] &&
191*4882a593Smuzhiyun 	    !cur->bc_ops->keys_inorder(cur, &bs->lastkey[level], key))
192*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, cur, level);
193*4882a593Smuzhiyun 	bs->firstkey[level] = false;
194*4882a593Smuzhiyun 	memcpy(&bs->lastkey[level], key, cur->bc_ops->key_len);
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (level + 1 >= cur->bc_nlevels)
197*4882a593Smuzhiyun 		return;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	/* Is this at least as large as the parent low key? */
200*4882a593Smuzhiyun 	keyblock = xfs_btree_get_block(cur, level + 1, &bp);
201*4882a593Smuzhiyun 	keyp = xfs_btree_key_addr(cur, cur->bc_ptrs[level + 1], keyblock);
202*4882a593Smuzhiyun 	if (cur->bc_ops->diff_two_keys(cur, key, keyp) < 0)
203*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, cur, level);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
206*4882a593Smuzhiyun 		return;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	/* Is this no larger than the parent high key? */
209*4882a593Smuzhiyun 	key = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level], block);
210*4882a593Smuzhiyun 	keyp = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level + 1], keyblock);
211*4882a593Smuzhiyun 	if (cur->bc_ops->diff_two_keys(cur, keyp, key) < 0)
212*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, cur, level);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun /*
216*4882a593Smuzhiyun  * Check a btree pointer.  Returns true if it's ok to use this pointer.
217*4882a593Smuzhiyun  * Callers do not need to set the corrupt flag.
218*4882a593Smuzhiyun  */
219*4882a593Smuzhiyun static bool
xchk_btree_ptr_ok(struct xchk_btree * bs,int level,union xfs_btree_ptr * ptr)220*4882a593Smuzhiyun xchk_btree_ptr_ok(
221*4882a593Smuzhiyun 	struct xchk_btree	*bs,
222*4882a593Smuzhiyun 	int			level,
223*4882a593Smuzhiyun 	union xfs_btree_ptr	*ptr)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	bool			res;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	/* A btree rooted in an inode has no block pointer to the root. */
228*4882a593Smuzhiyun 	if ((bs->cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
229*4882a593Smuzhiyun 	    level == bs->cur->bc_nlevels)
230*4882a593Smuzhiyun 		return true;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	/* Otherwise, check the pointers. */
233*4882a593Smuzhiyun 	if (bs->cur->bc_flags & XFS_BTREE_LONG_PTRS)
234*4882a593Smuzhiyun 		res = xfs_btree_check_lptr(bs->cur, be64_to_cpu(ptr->l), level);
235*4882a593Smuzhiyun 	else
236*4882a593Smuzhiyun 		res = xfs_btree_check_sptr(bs->cur, be32_to_cpu(ptr->s), level);
237*4882a593Smuzhiyun 	if (!res)
238*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, bs->cur, level);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	return res;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun /* Check that a btree block's sibling matches what we expect it. */
244*4882a593Smuzhiyun STATIC int
xchk_btree_block_check_sibling(struct xchk_btree * bs,int level,int direction,union xfs_btree_ptr * sibling)245*4882a593Smuzhiyun xchk_btree_block_check_sibling(
246*4882a593Smuzhiyun 	struct xchk_btree	*bs,
247*4882a593Smuzhiyun 	int			level,
248*4882a593Smuzhiyun 	int			direction,
249*4882a593Smuzhiyun 	union xfs_btree_ptr	*sibling)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur = bs->cur;
252*4882a593Smuzhiyun 	struct xfs_btree_block	*pblock;
253*4882a593Smuzhiyun 	struct xfs_buf		*pbp;
254*4882a593Smuzhiyun 	struct xfs_btree_cur	*ncur = NULL;
255*4882a593Smuzhiyun 	union xfs_btree_ptr	*pp;
256*4882a593Smuzhiyun 	int			success;
257*4882a593Smuzhiyun 	int			error;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	error = xfs_btree_dup_cursor(cur, &ncur);
260*4882a593Smuzhiyun 	if (!xchk_btree_process_error(bs->sc, cur, level + 1, &error) ||
261*4882a593Smuzhiyun 	    !ncur)
262*4882a593Smuzhiyun 		return error;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	/*
265*4882a593Smuzhiyun 	 * If the pointer is null, we shouldn't be able to move the upper
266*4882a593Smuzhiyun 	 * level pointer anywhere.
267*4882a593Smuzhiyun 	 */
268*4882a593Smuzhiyun 	if (xfs_btree_ptr_is_null(cur, sibling)) {
269*4882a593Smuzhiyun 		if (direction > 0)
270*4882a593Smuzhiyun 			error = xfs_btree_increment(ncur, level + 1, &success);
271*4882a593Smuzhiyun 		else
272*4882a593Smuzhiyun 			error = xfs_btree_decrement(ncur, level + 1, &success);
273*4882a593Smuzhiyun 		if (error == 0 && success)
274*4882a593Smuzhiyun 			xchk_btree_set_corrupt(bs->sc, cur, level);
275*4882a593Smuzhiyun 		error = 0;
276*4882a593Smuzhiyun 		goto out;
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	/* Increment upper level pointer. */
280*4882a593Smuzhiyun 	if (direction > 0)
281*4882a593Smuzhiyun 		error = xfs_btree_increment(ncur, level + 1, &success);
282*4882a593Smuzhiyun 	else
283*4882a593Smuzhiyun 		error = xfs_btree_decrement(ncur, level + 1, &success);
284*4882a593Smuzhiyun 	if (!xchk_btree_process_error(bs->sc, cur, level + 1, &error))
285*4882a593Smuzhiyun 		goto out;
286*4882a593Smuzhiyun 	if (!success) {
287*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, cur, level + 1);
288*4882a593Smuzhiyun 		goto out;
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/* Compare upper level pointer to sibling pointer. */
292*4882a593Smuzhiyun 	pblock = xfs_btree_get_block(ncur, level + 1, &pbp);
293*4882a593Smuzhiyun 	pp = xfs_btree_ptr_addr(ncur, ncur->bc_ptrs[level + 1], pblock);
294*4882a593Smuzhiyun 	if (!xchk_btree_ptr_ok(bs, level + 1, pp))
295*4882a593Smuzhiyun 		goto out;
296*4882a593Smuzhiyun 	if (pbp)
297*4882a593Smuzhiyun 		xchk_buffer_recheck(bs->sc, pbp);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	if (xfs_btree_diff_two_ptrs(cur, pp, sibling))
300*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, cur, level);
301*4882a593Smuzhiyun out:
302*4882a593Smuzhiyun 	xfs_btree_del_cursor(ncur, XFS_BTREE_ERROR);
303*4882a593Smuzhiyun 	return error;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun /* Check the siblings of a btree block. */
307*4882a593Smuzhiyun STATIC int
xchk_btree_block_check_siblings(struct xchk_btree * bs,struct xfs_btree_block * block)308*4882a593Smuzhiyun xchk_btree_block_check_siblings(
309*4882a593Smuzhiyun 	struct xchk_btree	*bs,
310*4882a593Smuzhiyun 	struct xfs_btree_block	*block)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur = bs->cur;
313*4882a593Smuzhiyun 	union xfs_btree_ptr	leftsib;
314*4882a593Smuzhiyun 	union xfs_btree_ptr	rightsib;
315*4882a593Smuzhiyun 	int			level;
316*4882a593Smuzhiyun 	int			error = 0;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	xfs_btree_get_sibling(cur, block, &leftsib, XFS_BB_LEFTSIB);
319*4882a593Smuzhiyun 	xfs_btree_get_sibling(cur, block, &rightsib, XFS_BB_RIGHTSIB);
320*4882a593Smuzhiyun 	level = xfs_btree_get_level(block);
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	/* Root block should never have siblings. */
323*4882a593Smuzhiyun 	if (level == cur->bc_nlevels - 1) {
324*4882a593Smuzhiyun 		if (!xfs_btree_ptr_is_null(cur, &leftsib) ||
325*4882a593Smuzhiyun 		    !xfs_btree_ptr_is_null(cur, &rightsib))
326*4882a593Smuzhiyun 			xchk_btree_set_corrupt(bs->sc, cur, level);
327*4882a593Smuzhiyun 		goto out;
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	/*
331*4882a593Smuzhiyun 	 * Does the left & right sibling pointers match the adjacent
332*4882a593Smuzhiyun 	 * parent level pointers?
333*4882a593Smuzhiyun 	 * (These function absorbs error codes for us.)
334*4882a593Smuzhiyun 	 */
335*4882a593Smuzhiyun 	error = xchk_btree_block_check_sibling(bs, level, -1, &leftsib);
336*4882a593Smuzhiyun 	if (error)
337*4882a593Smuzhiyun 		return error;
338*4882a593Smuzhiyun 	error = xchk_btree_block_check_sibling(bs, level, 1, &rightsib);
339*4882a593Smuzhiyun 	if (error)
340*4882a593Smuzhiyun 		return error;
341*4882a593Smuzhiyun out:
342*4882a593Smuzhiyun 	return error;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun struct check_owner {
346*4882a593Smuzhiyun 	struct list_head	list;
347*4882a593Smuzhiyun 	xfs_daddr_t		daddr;
348*4882a593Smuzhiyun 	int			level;
349*4882a593Smuzhiyun };
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun /*
352*4882a593Smuzhiyun  * Make sure this btree block isn't in the free list and that there's
353*4882a593Smuzhiyun  * an rmap record for it.
354*4882a593Smuzhiyun  */
355*4882a593Smuzhiyun STATIC int
xchk_btree_check_block_owner(struct xchk_btree * bs,int level,xfs_daddr_t daddr)356*4882a593Smuzhiyun xchk_btree_check_block_owner(
357*4882a593Smuzhiyun 	struct xchk_btree	*bs,
358*4882a593Smuzhiyun 	int			level,
359*4882a593Smuzhiyun 	xfs_daddr_t		daddr)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	xfs_agnumber_t		agno;
362*4882a593Smuzhiyun 	xfs_agblock_t		agbno;
363*4882a593Smuzhiyun 	xfs_btnum_t		btnum;
364*4882a593Smuzhiyun 	bool			init_sa;
365*4882a593Smuzhiyun 	int			error = 0;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	if (!bs->cur)
368*4882a593Smuzhiyun 		return 0;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	btnum = bs->cur->bc_btnum;
371*4882a593Smuzhiyun 	agno = xfs_daddr_to_agno(bs->cur->bc_mp, daddr);
372*4882a593Smuzhiyun 	agbno = xfs_daddr_to_agbno(bs->cur->bc_mp, daddr);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	init_sa = bs->cur->bc_flags & XFS_BTREE_LONG_PTRS;
375*4882a593Smuzhiyun 	if (init_sa) {
376*4882a593Smuzhiyun 		error = xchk_ag_init(bs->sc, agno, &bs->sc->sa);
377*4882a593Smuzhiyun 		if (!xchk_btree_xref_process_error(bs->sc, bs->cur,
378*4882a593Smuzhiyun 				level, &error))
379*4882a593Smuzhiyun 			return error;
380*4882a593Smuzhiyun 	}
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	xchk_xref_is_used_space(bs->sc, agbno, 1);
383*4882a593Smuzhiyun 	/*
384*4882a593Smuzhiyun 	 * The bnobt scrubber aliases bs->cur to bs->sc->sa.bno_cur, so we
385*4882a593Smuzhiyun 	 * have to nullify it (to shut down further block owner checks) if
386*4882a593Smuzhiyun 	 * self-xref encounters problems.
387*4882a593Smuzhiyun 	 */
388*4882a593Smuzhiyun 	if (!bs->sc->sa.bno_cur && btnum == XFS_BTNUM_BNO)
389*4882a593Smuzhiyun 		bs->cur = NULL;
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	xchk_xref_is_owned_by(bs->sc, agbno, 1, bs->oinfo);
392*4882a593Smuzhiyun 	if (!bs->sc->sa.rmap_cur && btnum == XFS_BTNUM_RMAP)
393*4882a593Smuzhiyun 		bs->cur = NULL;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	if (init_sa)
396*4882a593Smuzhiyun 		xchk_ag_free(bs->sc, &bs->sc->sa);
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	return error;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun /* Check the owner of a btree block. */
402*4882a593Smuzhiyun STATIC int
xchk_btree_check_owner(struct xchk_btree * bs,int level,struct xfs_buf * bp)403*4882a593Smuzhiyun xchk_btree_check_owner(
404*4882a593Smuzhiyun 	struct xchk_btree	*bs,
405*4882a593Smuzhiyun 	int			level,
406*4882a593Smuzhiyun 	struct xfs_buf		*bp)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur = bs->cur;
409*4882a593Smuzhiyun 	struct check_owner	*co;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	/*
412*4882a593Smuzhiyun 	 * In theory, xfs_btree_get_block should only give us a null buffer
413*4882a593Smuzhiyun 	 * pointer for the root of a root-in-inode btree type, but we need
414*4882a593Smuzhiyun 	 * to check defensively here in case the cursor state is also screwed
415*4882a593Smuzhiyun 	 * up.
416*4882a593Smuzhiyun 	 */
417*4882a593Smuzhiyun 	if (bp == NULL) {
418*4882a593Smuzhiyun 		if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE))
419*4882a593Smuzhiyun 			xchk_btree_set_corrupt(bs->sc, bs->cur, level);
420*4882a593Smuzhiyun 		return 0;
421*4882a593Smuzhiyun 	}
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	/*
424*4882a593Smuzhiyun 	 * We want to cross-reference each btree block with the bnobt
425*4882a593Smuzhiyun 	 * and the rmapbt.  We cannot cross-reference the bnobt or
426*4882a593Smuzhiyun 	 * rmapbt while scanning the bnobt or rmapbt, respectively,
427*4882a593Smuzhiyun 	 * because we cannot alter the cursor and we'd prefer not to
428*4882a593Smuzhiyun 	 * duplicate cursors.  Therefore, save the buffer daddr for
429*4882a593Smuzhiyun 	 * later scanning.
430*4882a593Smuzhiyun 	 */
431*4882a593Smuzhiyun 	if (cur->bc_btnum == XFS_BTNUM_BNO || cur->bc_btnum == XFS_BTNUM_RMAP) {
432*4882a593Smuzhiyun 		co = kmem_alloc(sizeof(struct check_owner),
433*4882a593Smuzhiyun 				KM_MAYFAIL);
434*4882a593Smuzhiyun 		if (!co)
435*4882a593Smuzhiyun 			return -ENOMEM;
436*4882a593Smuzhiyun 		co->level = level;
437*4882a593Smuzhiyun 		co->daddr = XFS_BUF_ADDR(bp);
438*4882a593Smuzhiyun 		list_add_tail(&co->list, &bs->to_check);
439*4882a593Smuzhiyun 		return 0;
440*4882a593Smuzhiyun 	}
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	return xchk_btree_check_block_owner(bs, level, XFS_BUF_ADDR(bp));
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun /*
446*4882a593Smuzhiyun  * Check that this btree block has at least minrecs records or is one of the
447*4882a593Smuzhiyun  * special blocks that don't require that.
448*4882a593Smuzhiyun  */
449*4882a593Smuzhiyun STATIC void
xchk_btree_check_minrecs(struct xchk_btree * bs,int level,struct xfs_btree_block * block)450*4882a593Smuzhiyun xchk_btree_check_minrecs(
451*4882a593Smuzhiyun 	struct xchk_btree	*bs,
452*4882a593Smuzhiyun 	int			level,
453*4882a593Smuzhiyun 	struct xfs_btree_block	*block)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur = bs->cur;
456*4882a593Smuzhiyun 	unsigned int		root_level = cur->bc_nlevels - 1;
457*4882a593Smuzhiyun 	unsigned int		numrecs = be16_to_cpu(block->bb_numrecs);
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	/* More records than minrecs means the block is ok. */
460*4882a593Smuzhiyun 	if (numrecs >= cur->bc_ops->get_minrecs(cur, level))
461*4882a593Smuzhiyun 		return;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	/*
464*4882a593Smuzhiyun 	 * For btrees rooted in the inode, it's possible that the root block
465*4882a593Smuzhiyun 	 * contents spilled into a regular ondisk block because there wasn't
466*4882a593Smuzhiyun 	 * enough space in the inode root.  The number of records in that
467*4882a593Smuzhiyun 	 * child block might be less than the standard minrecs, but that's ok
468*4882a593Smuzhiyun 	 * provided that there's only one direct child of the root.
469*4882a593Smuzhiyun 	 */
470*4882a593Smuzhiyun 	if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
471*4882a593Smuzhiyun 	    level == cur->bc_nlevels - 2) {
472*4882a593Smuzhiyun 		struct xfs_btree_block	*root_block;
473*4882a593Smuzhiyun 		struct xfs_buf		*root_bp;
474*4882a593Smuzhiyun 		int			root_maxrecs;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 		root_block = xfs_btree_get_block(cur, root_level, &root_bp);
477*4882a593Smuzhiyun 		root_maxrecs = cur->bc_ops->get_dmaxrecs(cur, root_level);
478*4882a593Smuzhiyun 		if (be16_to_cpu(root_block->bb_numrecs) != 1 ||
479*4882a593Smuzhiyun 		    numrecs <= root_maxrecs)
480*4882a593Smuzhiyun 			xchk_btree_set_corrupt(bs->sc, cur, level);
481*4882a593Smuzhiyun 		return;
482*4882a593Smuzhiyun 	}
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	/*
485*4882a593Smuzhiyun 	 * Otherwise, only the root level is allowed to have fewer than minrecs
486*4882a593Smuzhiyun 	 * records or keyptrs.
487*4882a593Smuzhiyun 	 */
488*4882a593Smuzhiyun 	if (level < root_level)
489*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, cur, level);
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun /*
493*4882a593Smuzhiyun  * Grab and scrub a btree block given a btree pointer.  Returns block
494*4882a593Smuzhiyun  * and buffer pointers (if applicable) if they're ok to use.
495*4882a593Smuzhiyun  */
496*4882a593Smuzhiyun STATIC int
xchk_btree_get_block(struct xchk_btree * bs,int level,union xfs_btree_ptr * pp,struct xfs_btree_block ** pblock,struct xfs_buf ** pbp)497*4882a593Smuzhiyun xchk_btree_get_block(
498*4882a593Smuzhiyun 	struct xchk_btree	*bs,
499*4882a593Smuzhiyun 	int			level,
500*4882a593Smuzhiyun 	union xfs_btree_ptr	*pp,
501*4882a593Smuzhiyun 	struct xfs_btree_block	**pblock,
502*4882a593Smuzhiyun 	struct xfs_buf		**pbp)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun 	xfs_failaddr_t		failed_at;
505*4882a593Smuzhiyun 	int			error;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	*pblock = NULL;
508*4882a593Smuzhiyun 	*pbp = NULL;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	error = xfs_btree_lookup_get_block(bs->cur, level, pp, pblock);
511*4882a593Smuzhiyun 	if (!xchk_btree_process_error(bs->sc, bs->cur, level, &error) ||
512*4882a593Smuzhiyun 	    !*pblock)
513*4882a593Smuzhiyun 		return error;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	xfs_btree_get_block(bs->cur, level, pbp);
516*4882a593Smuzhiyun 	if (bs->cur->bc_flags & XFS_BTREE_LONG_PTRS)
517*4882a593Smuzhiyun 		failed_at = __xfs_btree_check_lblock(bs->cur, *pblock,
518*4882a593Smuzhiyun 				level, *pbp);
519*4882a593Smuzhiyun 	else
520*4882a593Smuzhiyun 		failed_at = __xfs_btree_check_sblock(bs->cur, *pblock,
521*4882a593Smuzhiyun 				 level, *pbp);
522*4882a593Smuzhiyun 	if (failed_at) {
523*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, bs->cur, level);
524*4882a593Smuzhiyun 		return 0;
525*4882a593Smuzhiyun 	}
526*4882a593Smuzhiyun 	if (*pbp)
527*4882a593Smuzhiyun 		xchk_buffer_recheck(bs->sc, *pbp);
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	xchk_btree_check_minrecs(bs, level, *pblock);
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	/*
532*4882a593Smuzhiyun 	 * Check the block's owner; this function absorbs error codes
533*4882a593Smuzhiyun 	 * for us.
534*4882a593Smuzhiyun 	 */
535*4882a593Smuzhiyun 	error = xchk_btree_check_owner(bs, level, *pbp);
536*4882a593Smuzhiyun 	if (error)
537*4882a593Smuzhiyun 		return error;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	/*
540*4882a593Smuzhiyun 	 * Check the block's siblings; this function absorbs error codes
541*4882a593Smuzhiyun 	 * for us.
542*4882a593Smuzhiyun 	 */
543*4882a593Smuzhiyun 	return xchk_btree_block_check_siblings(bs, *pblock);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun /*
547*4882a593Smuzhiyun  * Check that the low and high keys of this block match the keys stored
548*4882a593Smuzhiyun  * in the parent block.
549*4882a593Smuzhiyun  */
550*4882a593Smuzhiyun STATIC void
xchk_btree_block_keys(struct xchk_btree * bs,int level,struct xfs_btree_block * block)551*4882a593Smuzhiyun xchk_btree_block_keys(
552*4882a593Smuzhiyun 	struct xchk_btree	*bs,
553*4882a593Smuzhiyun 	int			level,
554*4882a593Smuzhiyun 	struct xfs_btree_block	*block)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun 	union xfs_btree_key	block_keys;
557*4882a593Smuzhiyun 	struct xfs_btree_cur	*cur = bs->cur;
558*4882a593Smuzhiyun 	union xfs_btree_key	*high_bk;
559*4882a593Smuzhiyun 	union xfs_btree_key	*parent_keys;
560*4882a593Smuzhiyun 	union xfs_btree_key	*high_pk;
561*4882a593Smuzhiyun 	struct xfs_btree_block	*parent_block;
562*4882a593Smuzhiyun 	struct xfs_buf		*bp;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	if (level >= cur->bc_nlevels - 1)
565*4882a593Smuzhiyun 		return;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* Calculate the keys for this block. */
568*4882a593Smuzhiyun 	xfs_btree_get_keys(cur, block, &block_keys);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	/* Obtain the parent's copy of the keys for this block. */
571*4882a593Smuzhiyun 	parent_block = xfs_btree_get_block(cur, level + 1, &bp);
572*4882a593Smuzhiyun 	parent_keys = xfs_btree_key_addr(cur, cur->bc_ptrs[level + 1],
573*4882a593Smuzhiyun 			parent_block);
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	if (cur->bc_ops->diff_two_keys(cur, &block_keys, parent_keys) != 0)
576*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, cur, 1);
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
579*4882a593Smuzhiyun 		return;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	/* Get high keys */
582*4882a593Smuzhiyun 	high_bk = xfs_btree_high_key_from_key(cur, &block_keys);
583*4882a593Smuzhiyun 	high_pk = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level + 1],
584*4882a593Smuzhiyun 			parent_block);
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	if (cur->bc_ops->diff_two_keys(cur, high_bk, high_pk) != 0)
587*4882a593Smuzhiyun 		xchk_btree_set_corrupt(bs->sc, cur, 1);
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun /*
591*4882a593Smuzhiyun  * Visit all nodes and leaves of a btree.  Check that all pointers and
592*4882a593Smuzhiyun  * records are in order, that the keys reflect the records, and use a callback
593*4882a593Smuzhiyun  * so that the caller can verify individual records.
594*4882a593Smuzhiyun  */
595*4882a593Smuzhiyun int
xchk_btree(struct xfs_scrub * sc,struct xfs_btree_cur * cur,xchk_btree_rec_fn scrub_fn,const struct xfs_owner_info * oinfo,void * private)596*4882a593Smuzhiyun xchk_btree(
597*4882a593Smuzhiyun 	struct xfs_scrub		*sc,
598*4882a593Smuzhiyun 	struct xfs_btree_cur		*cur,
599*4882a593Smuzhiyun 	xchk_btree_rec_fn		scrub_fn,
600*4882a593Smuzhiyun 	const struct xfs_owner_info	*oinfo,
601*4882a593Smuzhiyun 	void				*private)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun 	struct xchk_btree		bs = {
604*4882a593Smuzhiyun 		.cur			= cur,
605*4882a593Smuzhiyun 		.scrub_rec		= scrub_fn,
606*4882a593Smuzhiyun 		.oinfo			= oinfo,
607*4882a593Smuzhiyun 		.firstrec		= true,
608*4882a593Smuzhiyun 		.private		= private,
609*4882a593Smuzhiyun 		.sc			= sc,
610*4882a593Smuzhiyun 	};
611*4882a593Smuzhiyun 	union xfs_btree_ptr		ptr;
612*4882a593Smuzhiyun 	union xfs_btree_ptr		*pp;
613*4882a593Smuzhiyun 	union xfs_btree_rec		*recp;
614*4882a593Smuzhiyun 	struct xfs_btree_block		*block;
615*4882a593Smuzhiyun 	int				level;
616*4882a593Smuzhiyun 	struct xfs_buf			*bp;
617*4882a593Smuzhiyun 	struct check_owner		*co;
618*4882a593Smuzhiyun 	struct check_owner		*n;
619*4882a593Smuzhiyun 	int				i;
620*4882a593Smuzhiyun 	int				error = 0;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	/* Initialize scrub state */
623*4882a593Smuzhiyun 	for (i = 0; i < XFS_BTREE_MAXLEVELS; i++)
624*4882a593Smuzhiyun 		bs.firstkey[i] = true;
625*4882a593Smuzhiyun 	INIT_LIST_HEAD(&bs.to_check);
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	/* Don't try to check a tree with a height we can't handle. */
628*4882a593Smuzhiyun 	if (cur->bc_nlevels > XFS_BTREE_MAXLEVELS) {
629*4882a593Smuzhiyun 		xchk_btree_set_corrupt(sc, cur, 0);
630*4882a593Smuzhiyun 		goto out;
631*4882a593Smuzhiyun 	}
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	/*
634*4882a593Smuzhiyun 	 * Load the root of the btree.  The helper function absorbs
635*4882a593Smuzhiyun 	 * error codes for us.
636*4882a593Smuzhiyun 	 */
637*4882a593Smuzhiyun 	level = cur->bc_nlevels - 1;
638*4882a593Smuzhiyun 	cur->bc_ops->init_ptr_from_cur(cur, &ptr);
639*4882a593Smuzhiyun 	if (!xchk_btree_ptr_ok(&bs, cur->bc_nlevels, &ptr))
640*4882a593Smuzhiyun 		goto out;
641*4882a593Smuzhiyun 	error = xchk_btree_get_block(&bs, level, &ptr, &block, &bp);
642*4882a593Smuzhiyun 	if (error || !block)
643*4882a593Smuzhiyun 		goto out;
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	cur->bc_ptrs[level] = 1;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	while (level < cur->bc_nlevels) {
648*4882a593Smuzhiyun 		block = xfs_btree_get_block(cur, level, &bp);
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 		if (level == 0) {
651*4882a593Smuzhiyun 			/* End of leaf, pop back towards the root. */
652*4882a593Smuzhiyun 			if (cur->bc_ptrs[level] >
653*4882a593Smuzhiyun 			    be16_to_cpu(block->bb_numrecs)) {
654*4882a593Smuzhiyun 				xchk_btree_block_keys(&bs, level, block);
655*4882a593Smuzhiyun 				if (level < cur->bc_nlevels - 1)
656*4882a593Smuzhiyun 					cur->bc_ptrs[level + 1]++;
657*4882a593Smuzhiyun 				level++;
658*4882a593Smuzhiyun 				continue;
659*4882a593Smuzhiyun 			}
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 			/* Records in order for scrub? */
662*4882a593Smuzhiyun 			xchk_btree_rec(&bs);
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 			/* Call out to the record checker. */
665*4882a593Smuzhiyun 			recp = xfs_btree_rec_addr(cur, cur->bc_ptrs[0], block);
666*4882a593Smuzhiyun 			error = bs.scrub_rec(&bs, recp);
667*4882a593Smuzhiyun 			if (error)
668*4882a593Smuzhiyun 				break;
669*4882a593Smuzhiyun 			if (xchk_should_terminate(sc, &error) ||
670*4882a593Smuzhiyun 			    (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
671*4882a593Smuzhiyun 				break;
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 			cur->bc_ptrs[level]++;
674*4882a593Smuzhiyun 			continue;
675*4882a593Smuzhiyun 		}
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 		/* End of node, pop back towards the root. */
678*4882a593Smuzhiyun 		if (cur->bc_ptrs[level] > be16_to_cpu(block->bb_numrecs)) {
679*4882a593Smuzhiyun 			xchk_btree_block_keys(&bs, level, block);
680*4882a593Smuzhiyun 			if (level < cur->bc_nlevels - 1)
681*4882a593Smuzhiyun 				cur->bc_ptrs[level + 1]++;
682*4882a593Smuzhiyun 			level++;
683*4882a593Smuzhiyun 			continue;
684*4882a593Smuzhiyun 		}
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 		/* Keys in order for scrub? */
687*4882a593Smuzhiyun 		xchk_btree_key(&bs, level);
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 		/* Drill another level deeper. */
690*4882a593Smuzhiyun 		pp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[level], block);
691*4882a593Smuzhiyun 		if (!xchk_btree_ptr_ok(&bs, level, pp)) {
692*4882a593Smuzhiyun 			cur->bc_ptrs[level]++;
693*4882a593Smuzhiyun 			continue;
694*4882a593Smuzhiyun 		}
695*4882a593Smuzhiyun 		level--;
696*4882a593Smuzhiyun 		error = xchk_btree_get_block(&bs, level, pp, &block, &bp);
697*4882a593Smuzhiyun 		if (error || !block)
698*4882a593Smuzhiyun 			goto out;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 		cur->bc_ptrs[level] = 1;
701*4882a593Smuzhiyun 	}
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun out:
704*4882a593Smuzhiyun 	/* Process deferred owner checks on btree blocks. */
705*4882a593Smuzhiyun 	list_for_each_entry_safe(co, n, &bs.to_check, list) {
706*4882a593Smuzhiyun 		if (!error && bs.cur)
707*4882a593Smuzhiyun 			error = xchk_btree_check_block_owner(&bs,
708*4882a593Smuzhiyun 					co->level, co->daddr);
709*4882a593Smuzhiyun 		list_del(&co->list);
710*4882a593Smuzhiyun 		kmem_free(co);
711*4882a593Smuzhiyun 	}
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	return error;
714*4882a593Smuzhiyun }
715