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