brintos

brintos / linux-shallow public Read only

0
0
Text · 20.7 KiB · fe678a0 Raw
803 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2017-2023 Oracle.  All Rights Reserved.4 * Author: Darrick J. Wong <djwong@kernel.org>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_inode.h"13#include "xfs_btree.h"14#include "scrub/scrub.h"15#include "scrub/common.h"16#include "scrub/btree.h"17#include "scrub/trace.h"18 19/* btree scrubbing */20 21/*22 * Check for btree operation errors.  See the section about handling23 * operational errors in common.c.24 */25static bool26__xchk_btree_process_error(27	struct xfs_scrub	*sc,28	struct xfs_btree_cur	*cur,29	int			level,30	int			*error,31	__u32			errflag,32	void			*ret_ip)33{34	if (*error == 0)35		return true;36 37	switch (*error) {38	case -EDEADLOCK:39	case -ECHRNG:40		/* Used to restart an op with deadlock avoidance. */41		trace_xchk_deadlock_retry(sc->ip, sc->sm, *error);42		break;43	case -EFSBADCRC:44	case -EFSCORRUPTED:45		/* Note the badness but don't abort. */46		sc->sm->sm_flags |= errflag;47		*error = 0;48		fallthrough;49	default:50		if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE)51			trace_xchk_ifork_btree_op_error(sc, cur, level,52					*error, ret_ip);53		else54			trace_xchk_btree_op_error(sc, cur, level,55					*error, ret_ip);56		break;57	}58	return false;59}60 61bool62xchk_btree_process_error(63	struct xfs_scrub	*sc,64	struct xfs_btree_cur	*cur,65	int			level,66	int			*error)67{68	return __xchk_btree_process_error(sc, cur, level, error,69			XFS_SCRUB_OFLAG_CORRUPT, __return_address);70}71 72bool73xchk_btree_xref_process_error(74	struct xfs_scrub	*sc,75	struct xfs_btree_cur	*cur,76	int			level,77	int			*error)78{79	return __xchk_btree_process_error(sc, cur, level, error,80			XFS_SCRUB_OFLAG_XFAIL, __return_address);81}82 83/* Record btree block corruption. */84static void85__xchk_btree_set_corrupt(86	struct xfs_scrub	*sc,87	struct xfs_btree_cur	*cur,88	int			level,89	__u32			errflag,90	void			*ret_ip)91{92	sc->sm->sm_flags |= errflag;93 94	if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE)95		trace_xchk_ifork_btree_error(sc, cur, level,96				ret_ip);97	else98		trace_xchk_btree_error(sc, cur, level,99				ret_ip);100}101 102void103xchk_btree_set_corrupt(104	struct xfs_scrub	*sc,105	struct xfs_btree_cur	*cur,106	int			level)107{108	__xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_CORRUPT,109			__return_address);110}111 112void113xchk_btree_xref_set_corrupt(114	struct xfs_scrub	*sc,115	struct xfs_btree_cur	*cur,116	int			level)117{118	__xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_XCORRUPT,119			__return_address);120}121 122void123xchk_btree_set_preen(124	struct xfs_scrub	*sc,125	struct xfs_btree_cur	*cur,126	int			level)127{128	__xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_PREEN,129			__return_address);130}131 132/*133 * Make sure this record is in order and doesn't stray outside of the parent134 * keys.135 */136STATIC void137xchk_btree_rec(138	struct xchk_btree	*bs)139{140	struct xfs_btree_cur	*cur = bs->cur;141	union xfs_btree_rec	*rec;142	union xfs_btree_key	key;143	union xfs_btree_key	hkey;144	union xfs_btree_key	*keyp;145	struct xfs_btree_block	*block;146	struct xfs_btree_block	*keyblock;147	struct xfs_buf		*bp;148 149	block = xfs_btree_get_block(cur, 0, &bp);150	rec = xfs_btree_rec_addr(cur, cur->bc_levels[0].ptr, block);151 152	trace_xchk_btree_rec(bs->sc, cur, 0);153 154	/* Are all records across all record blocks in order? */155	if (bs->lastrec_valid &&156	    !cur->bc_ops->recs_inorder(cur, &bs->lastrec, rec))157		xchk_btree_set_corrupt(bs->sc, cur, 0);158	memcpy(&bs->lastrec, rec, cur->bc_ops->rec_len);159	bs->lastrec_valid = true;160 161	if (cur->bc_nlevels == 1)162		return;163 164	/* Is low_key(rec) at least as large as the parent low key? */165	cur->bc_ops->init_key_from_rec(&key, rec);166	keyblock = xfs_btree_get_block(cur, 1, &bp);167	keyp = xfs_btree_key_addr(cur, cur->bc_levels[1].ptr, keyblock);168	if (xfs_btree_keycmp_lt(cur, &key, keyp))169		xchk_btree_set_corrupt(bs->sc, cur, 1);170 171	if (!(cur->bc_ops->geom_flags & XFS_BTGEO_OVERLAPPING))172		return;173 174	/* Is high_key(rec) no larger than the parent high key? */175	cur->bc_ops->init_high_key_from_rec(&hkey, rec);176	keyp = xfs_btree_high_key_addr(cur, cur->bc_levels[1].ptr, keyblock);177	if (xfs_btree_keycmp_lt(cur, keyp, &hkey))178		xchk_btree_set_corrupt(bs->sc, cur, 1);179}180 181/*182 * Make sure this key is in order and doesn't stray outside of the parent183 * keys.184 */185STATIC void186xchk_btree_key(187	struct xchk_btree	*bs,188	int			level)189{190	struct xfs_btree_cur	*cur = bs->cur;191	union xfs_btree_key	*key;192	union xfs_btree_key	*keyp;193	struct xfs_btree_block	*block;194	struct xfs_btree_block	*keyblock;195	struct xfs_buf		*bp;196 197	block = xfs_btree_get_block(cur, level, &bp);198	key = xfs_btree_key_addr(cur, cur->bc_levels[level].ptr, block);199 200	trace_xchk_btree_key(bs->sc, cur, level);201 202	/* Are all low keys across all node blocks in order? */203	if (bs->lastkey[level - 1].valid &&204	    !cur->bc_ops->keys_inorder(cur, &bs->lastkey[level - 1].key, key))205		xchk_btree_set_corrupt(bs->sc, cur, level);206	memcpy(&bs->lastkey[level - 1].key, key, cur->bc_ops->key_len);207	bs->lastkey[level - 1].valid = true;208 209	if (level + 1 >= cur->bc_nlevels)210		return;211 212	/* Is this block's low key at least as large as the parent low key? */213	keyblock = xfs_btree_get_block(cur, level + 1, &bp);214	keyp = xfs_btree_key_addr(cur, cur->bc_levels[level + 1].ptr, keyblock);215	if (xfs_btree_keycmp_lt(cur, key, keyp))216		xchk_btree_set_corrupt(bs->sc, cur, level);217 218	if (!(cur->bc_ops->geom_flags & XFS_BTGEO_OVERLAPPING))219		return;220 221	/* Is this block's high key no larger than the parent high key? */222	key = xfs_btree_high_key_addr(cur, cur->bc_levels[level].ptr, block);223	keyp = xfs_btree_high_key_addr(cur, cur->bc_levels[level + 1].ptr,224			keyblock);225	if (xfs_btree_keycmp_lt(cur, keyp, key))226		xchk_btree_set_corrupt(bs->sc, cur, level);227}228 229/*230 * Check a btree pointer.  Returns true if it's ok to use this pointer.231 * Callers do not need to set the corrupt flag.232 */233static bool234xchk_btree_ptr_ok(235	struct xchk_btree	*bs,236	int			level,237	union xfs_btree_ptr	*ptr)238{239	/* A btree rooted in an inode has no block pointer to the root. */240	if (bs->cur->bc_ops->type == XFS_BTREE_TYPE_INODE &&241	    level == bs->cur->bc_nlevels)242		return true;243 244	/* Otherwise, check the pointers. */245	if (__xfs_btree_check_ptr(bs->cur, ptr, 0, level)) {246		xchk_btree_set_corrupt(bs->sc, bs->cur, level);247		return false;248	}249 250	return true;251}252 253/* Check that a btree block's sibling matches what we expect it. */254STATIC int255xchk_btree_block_check_sibling(256	struct xchk_btree	*bs,257	int			level,258	int			direction,259	union xfs_btree_ptr	*sibling)260{261	struct xfs_btree_cur	*cur = bs->cur;262	struct xfs_btree_block	*pblock;263	struct xfs_buf		*pbp;264	struct xfs_btree_cur	*ncur = NULL;265	union xfs_btree_ptr	*pp;266	int			success;267	int			error;268 269	error = xfs_btree_dup_cursor(cur, &ncur);270	if (!xchk_btree_process_error(bs->sc, cur, level + 1, &error) ||271	    !ncur)272		return error;273 274	/*275	 * If the pointer is null, we shouldn't be able to move the upper276	 * level pointer anywhere.277	 */278	if (xfs_btree_ptr_is_null(cur, sibling)) {279		if (direction > 0)280			error = xfs_btree_increment(ncur, level + 1, &success);281		else282			error = xfs_btree_decrement(ncur, level + 1, &success);283		if (error == 0 && success)284			xchk_btree_set_corrupt(bs->sc, cur, level);285		error = 0;286		goto out;287	}288 289	/* Increment upper level pointer. */290	if (direction > 0)291		error = xfs_btree_increment(ncur, level + 1, &success);292	else293		error = xfs_btree_decrement(ncur, level + 1, &success);294	if (!xchk_btree_process_error(bs->sc, cur, level + 1, &error))295		goto out;296	if (!success) {297		xchk_btree_set_corrupt(bs->sc, cur, level + 1);298		goto out;299	}300 301	/* Compare upper level pointer to sibling pointer. */302	pblock = xfs_btree_get_block(ncur, level + 1, &pbp);303	pp = xfs_btree_ptr_addr(ncur, ncur->bc_levels[level + 1].ptr, pblock);304	if (!xchk_btree_ptr_ok(bs, level + 1, pp))305		goto out;306	if (pbp)307		xchk_buffer_recheck(bs->sc, pbp);308 309	if (xfs_btree_diff_two_ptrs(cur, pp, sibling))310		xchk_btree_set_corrupt(bs->sc, cur, level);311out:312	xfs_btree_del_cursor(ncur, XFS_BTREE_ERROR);313	return error;314}315 316/* Check the siblings of a btree block. */317STATIC int318xchk_btree_block_check_siblings(319	struct xchk_btree	*bs,320	struct xfs_btree_block	*block)321{322	struct xfs_btree_cur	*cur = bs->cur;323	union xfs_btree_ptr	leftsib;324	union xfs_btree_ptr	rightsib;325	int			level;326	int			error = 0;327 328	xfs_btree_get_sibling(cur, block, &leftsib, XFS_BB_LEFTSIB);329	xfs_btree_get_sibling(cur, block, &rightsib, XFS_BB_RIGHTSIB);330	level = xfs_btree_get_level(block);331 332	/* Root block should never have siblings. */333	if (level == cur->bc_nlevels - 1) {334		if (!xfs_btree_ptr_is_null(cur, &leftsib) ||335		    !xfs_btree_ptr_is_null(cur, &rightsib))336			xchk_btree_set_corrupt(bs->sc, cur, level);337		goto out;338	}339 340	/*341	 * Does the left & right sibling pointers match the adjacent342	 * parent level pointers?343	 * (These function absorbs error codes for us.)344	 */345	error = xchk_btree_block_check_sibling(bs, level, -1, &leftsib);346	if (error)347		return error;348	error = xchk_btree_block_check_sibling(bs, level, 1, &rightsib);349	if (error)350		return error;351out:352	return error;353}354 355struct check_owner {356	struct list_head	list;357	xfs_daddr_t		daddr;358	int			level;359};360 361/*362 * Make sure this btree block isn't in the free list and that there's363 * an rmap record for it.364 */365STATIC int366xchk_btree_check_block_owner(367	struct xchk_btree	*bs,368	int			level,369	xfs_daddr_t		daddr)370{371	xfs_agnumber_t		agno;372	xfs_agblock_t		agbno;373	bool			init_sa;374	int			error = 0;375 376	if (!bs->cur)377		return 0;378 379	agno = xfs_daddr_to_agno(bs->cur->bc_mp, daddr);380	agbno = xfs_daddr_to_agbno(bs->cur->bc_mp, daddr);381 382	/*383	 * If the btree being examined is not itself a per-AG btree, initialize384	 * sc->sa so that we can check for the presence of an ownership record385	 * in the rmap btree for the AG containing the block.386	 */387	init_sa = bs->cur->bc_ops->type != XFS_BTREE_TYPE_AG;388	if (init_sa) {389		error = xchk_ag_init_existing(bs->sc, agno, &bs->sc->sa);390		if (!xchk_btree_xref_process_error(bs->sc, bs->cur,391				level, &error))392			goto out_free;393	}394 395	xchk_xref_is_used_space(bs->sc, agbno, 1);396	/*397	 * The bnobt scrubber aliases bs->cur to bs->sc->sa.bno_cur, so we398	 * have to nullify it (to shut down further block owner checks) if399	 * self-xref encounters problems.400	 */401	if (!bs->sc->sa.bno_cur && xfs_btree_is_bno(bs->cur->bc_ops))402		bs->cur = NULL;403 404	xchk_xref_is_only_owned_by(bs->sc, agbno, 1, bs->oinfo);405	if (!bs->sc->sa.rmap_cur && xfs_btree_is_rmap(bs->cur->bc_ops))406		bs->cur = NULL;407 408out_free:409	if (init_sa)410		xchk_ag_free(bs->sc, &bs->sc->sa);411 412	return error;413}414 415/* Check the owner of a btree block. */416STATIC int417xchk_btree_check_owner(418	struct xchk_btree	*bs,419	int			level,420	struct xfs_buf		*bp)421{422	struct xfs_btree_cur	*cur = bs->cur;423 424	/*425	 * In theory, xfs_btree_get_block should only give us a null buffer426	 * pointer for the root of a root-in-inode btree type, but we need427	 * to check defensively here in case the cursor state is also screwed428	 * up.429	 */430	if (bp == NULL) {431		if (cur->bc_ops->type != XFS_BTREE_TYPE_INODE)432			xchk_btree_set_corrupt(bs->sc, bs->cur, level);433		return 0;434	}435 436	/*437	 * We want to cross-reference each btree block with the bnobt438	 * and the rmapbt.  We cannot cross-reference the bnobt or439	 * rmapbt while scanning the bnobt or rmapbt, respectively,440	 * because we cannot alter the cursor and we'd prefer not to441	 * duplicate cursors.  Therefore, save the buffer daddr for442	 * later scanning.443	 */444	if (xfs_btree_is_bno(cur->bc_ops) || xfs_btree_is_rmap(cur->bc_ops)) {445		struct check_owner	*co;446 447		co = kmalloc(sizeof(struct check_owner), XCHK_GFP_FLAGS);448		if (!co)449			return -ENOMEM;450 451		INIT_LIST_HEAD(&co->list);452		co->level = level;453		co->daddr = xfs_buf_daddr(bp);454		list_add_tail(&co->list, &bs->to_check);455		return 0;456	}457 458	return xchk_btree_check_block_owner(bs, level, xfs_buf_daddr(bp));459}460 461/* Decide if we want to check minrecs of a btree block in the inode root. */462static inline bool463xchk_btree_check_iroot_minrecs(464	struct xchk_btree	*bs)465{466	/*467	 * xfs_bmap_add_attrfork_btree had an implementation bug wherein it468	 * would miscalculate the space required for the data fork bmbt root469	 * when adding an attr fork, and promote the iroot contents to an470	 * external block unnecessarily.  This went unnoticed for many years471	 * until scrub found filesystems in this state.  Inode rooted btrees are472	 * not supposed to have immediate child blocks that are small enough473	 * that the contents could fit in the inode root, but we can't fail474	 * existing filesystems, so instead we disable the check for data fork475	 * bmap btrees when there's an attr fork.476	 */477	if (xfs_btree_is_bmap(bs->cur->bc_ops) &&478	    bs->cur->bc_ino.whichfork == XFS_DATA_FORK &&479	    xfs_inode_has_attr_fork(bs->sc->ip))480		return false;481 482	return true;483}484 485/*486 * Check that this btree block has at least minrecs records or is one of the487 * special blocks that don't require that.488 */489STATIC void490xchk_btree_check_minrecs(491	struct xchk_btree	*bs,492	int			level,493	struct xfs_btree_block	*block)494{495	struct xfs_btree_cur	*cur = bs->cur;496	unsigned int		root_level = cur->bc_nlevels - 1;497	unsigned int		numrecs = be16_to_cpu(block->bb_numrecs);498 499	/* More records than minrecs means the block is ok. */500	if (numrecs >= cur->bc_ops->get_minrecs(cur, level))501		return;502 503	/*504	 * For btrees rooted in the inode, it's possible that the root block505	 * contents spilled into a regular ondisk block because there wasn't506	 * enough space in the inode root.  The number of records in that507	 * child block might be less than the standard minrecs, but that's ok508	 * provided that there's only one direct child of the root.509	 */510	if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE &&511	    level == cur->bc_nlevels - 2) {512		struct xfs_btree_block	*root_block;513		struct xfs_buf		*root_bp;514		int			root_maxrecs;515 516		root_block = xfs_btree_get_block(cur, root_level, &root_bp);517		root_maxrecs = cur->bc_ops->get_dmaxrecs(cur, root_level);518		if (xchk_btree_check_iroot_minrecs(bs) &&519		    (be16_to_cpu(root_block->bb_numrecs) != 1 ||520		     numrecs <= root_maxrecs))521			xchk_btree_set_corrupt(bs->sc, cur, level);522		return;523	}524 525	/*526	 * Otherwise, only the root level is allowed to have fewer than minrecs527	 * records or keyptrs.528	 */529	if (level < root_level)530		xchk_btree_set_corrupt(bs->sc, cur, level);531}532 533/*534 * If this btree block has a parent, make sure that the parent's keys capture535 * the keyspace contained in this block.536 */537STATIC void538xchk_btree_block_check_keys(539	struct xchk_btree	*bs,540	int			level,541	struct xfs_btree_block	*block)542{543	union xfs_btree_key	block_key;544	union xfs_btree_key	*block_high_key;545	union xfs_btree_key	*parent_low_key, *parent_high_key;546	struct xfs_btree_cur	*cur = bs->cur;547	struct xfs_btree_block	*parent_block;548	struct xfs_buf		*bp;549 550	if (level == cur->bc_nlevels - 1)551		return;552 553	xfs_btree_get_keys(cur, block, &block_key);554 555	/* Make sure the low key of this block matches the parent. */556	parent_block = xfs_btree_get_block(cur, level + 1, &bp);557	parent_low_key = xfs_btree_key_addr(cur, cur->bc_levels[level + 1].ptr,558			parent_block);559	if (xfs_btree_keycmp_ne(cur, &block_key, parent_low_key)) {560		xchk_btree_set_corrupt(bs->sc, bs->cur, level);561		return;562	}563 564	if (!(cur->bc_ops->geom_flags & XFS_BTGEO_OVERLAPPING))565		return;566 567	/* Make sure the high key of this block matches the parent. */568	parent_high_key = xfs_btree_high_key_addr(cur,569			cur->bc_levels[level + 1].ptr, parent_block);570	block_high_key = xfs_btree_high_key_from_key(cur, &block_key);571	if (xfs_btree_keycmp_ne(cur, block_high_key, parent_high_key))572		xchk_btree_set_corrupt(bs->sc, bs->cur, level);573}574 575/*576 * Grab and scrub a btree block given a btree pointer.  Returns block577 * and buffer pointers (if applicable) if they're ok to use.578 */579STATIC int580xchk_btree_get_block(581	struct xchk_btree	*bs,582	int			level,583	union xfs_btree_ptr	*pp,584	struct xfs_btree_block	**pblock,585	struct xfs_buf		**pbp)586{587	int			error;588 589	*pblock = NULL;590	*pbp = NULL;591 592	error = xfs_btree_lookup_get_block(bs->cur, level, pp, pblock);593	if (!xchk_btree_process_error(bs->sc, bs->cur, level, &error) ||594	    !*pblock)595		return error;596 597	xfs_btree_get_block(bs->cur, level, pbp);598	if (__xfs_btree_check_block(bs->cur, *pblock, level, *pbp)) {599		xchk_btree_set_corrupt(bs->sc, bs->cur, level);600		return 0;601	}602	if (*pbp)603		xchk_buffer_recheck(bs->sc, *pbp);604 605	xchk_btree_check_minrecs(bs, level, *pblock);606 607	/*608	 * Check the block's owner; this function absorbs error codes609	 * for us.610	 */611	error = xchk_btree_check_owner(bs, level, *pbp);612	if (error)613		return error;614 615	/*616	 * Check the block's siblings; this function absorbs error codes617	 * for us.618	 */619	error = xchk_btree_block_check_siblings(bs, *pblock);620	if (error)621		return error;622 623	xchk_btree_block_check_keys(bs, level, *pblock);624	return 0;625}626 627/*628 * Check that the low and high keys of this block match the keys stored629 * in the parent block.630 */631STATIC void632xchk_btree_block_keys(633	struct xchk_btree	*bs,634	int			level,635	struct xfs_btree_block	*block)636{637	union xfs_btree_key	block_keys;638	struct xfs_btree_cur	*cur = bs->cur;639	union xfs_btree_key	*high_bk;640	union xfs_btree_key	*parent_keys;641	union xfs_btree_key	*high_pk;642	struct xfs_btree_block	*parent_block;643	struct xfs_buf		*bp;644 645	if (level >= cur->bc_nlevels - 1)646		return;647 648	/* Calculate the keys for this block. */649	xfs_btree_get_keys(cur, block, &block_keys);650 651	/* Obtain the parent's copy of the keys for this block. */652	parent_block = xfs_btree_get_block(cur, level + 1, &bp);653	parent_keys = xfs_btree_key_addr(cur, cur->bc_levels[level + 1].ptr,654			parent_block);655 656	if (xfs_btree_keycmp_ne(cur, &block_keys, parent_keys))657		xchk_btree_set_corrupt(bs->sc, cur, 1);658 659	if (!(cur->bc_ops->geom_flags & XFS_BTGEO_OVERLAPPING))660		return;661 662	/* Get high keys */663	high_bk = xfs_btree_high_key_from_key(cur, &block_keys);664	high_pk = xfs_btree_high_key_addr(cur, cur->bc_levels[level + 1].ptr,665			parent_block);666 667	if (xfs_btree_keycmp_ne(cur, high_bk, high_pk))668		xchk_btree_set_corrupt(bs->sc, cur, 1);669}670 671/*672 * Visit all nodes and leaves of a btree.  Check that all pointers and673 * records are in order, that the keys reflect the records, and use a callback674 * so that the caller can verify individual records.675 */676int677xchk_btree(678	struct xfs_scrub		*sc,679	struct xfs_btree_cur		*cur,680	xchk_btree_rec_fn		scrub_fn,681	const struct xfs_owner_info	*oinfo,682	void				*private)683{684	union xfs_btree_ptr		ptr;685	struct xchk_btree		*bs;686	union xfs_btree_ptr		*pp;687	union xfs_btree_rec		*recp;688	struct xfs_btree_block		*block;689	struct xfs_buf			*bp;690	struct check_owner		*co;691	struct check_owner		*n;692	size_t				cur_sz;693	int				level;694	int				error = 0;695 696	/*697	 * Allocate the btree scrub context from the heap, because this698	 * structure can get rather large.  Don't let a caller feed us a699	 * totally absurd size.700	 */701	cur_sz = xchk_btree_sizeof(cur->bc_nlevels);702	if (cur_sz > PAGE_SIZE) {703		xchk_btree_set_corrupt(sc, cur, 0);704		return 0;705	}706	bs = kzalloc(cur_sz, XCHK_GFP_FLAGS);707	if (!bs)708		return -ENOMEM;709	bs->cur = cur;710	bs->scrub_rec = scrub_fn;711	bs->oinfo = oinfo;712	bs->private = private;713	bs->sc = sc;714 715	/* Initialize scrub state */716	INIT_LIST_HEAD(&bs->to_check);717 718	/*719	 * Load the root of the btree.  The helper function absorbs720	 * error codes for us.721	 */722	level = cur->bc_nlevels - 1;723	xfs_btree_init_ptr_from_cur(cur, &ptr);724	if (!xchk_btree_ptr_ok(bs, cur->bc_nlevels, &ptr))725		goto out;726	error = xchk_btree_get_block(bs, level, &ptr, &block, &bp);727	if (error || !block)728		goto out;729 730	cur->bc_levels[level].ptr = 1;731 732	while (level < cur->bc_nlevels) {733		block = xfs_btree_get_block(cur, level, &bp);734 735		if (level == 0) {736			/* End of leaf, pop back towards the root. */737			if (cur->bc_levels[level].ptr >738			    be16_to_cpu(block->bb_numrecs)) {739				xchk_btree_block_keys(bs, level, block);740				if (level < cur->bc_nlevels - 1)741					cur->bc_levels[level + 1].ptr++;742				level++;743				continue;744			}745 746			/* Records in order for scrub? */747			xchk_btree_rec(bs);748 749			/* Call out to the record checker. */750			recp = xfs_btree_rec_addr(cur, cur->bc_levels[0].ptr,751					block);752			error = bs->scrub_rec(bs, recp);753			if (error)754				break;755			if (xchk_should_terminate(sc, &error) ||756			    (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))757				break;758 759			cur->bc_levels[level].ptr++;760			continue;761		}762 763		/* End of node, pop back towards the root. */764		if (cur->bc_levels[level].ptr >765					be16_to_cpu(block->bb_numrecs)) {766			xchk_btree_block_keys(bs, level, block);767			if (level < cur->bc_nlevels - 1)768				cur->bc_levels[level + 1].ptr++;769			level++;770			continue;771		}772 773		/* Keys in order for scrub? */774		xchk_btree_key(bs, level);775 776		/* Drill another level deeper. */777		pp = xfs_btree_ptr_addr(cur, cur->bc_levels[level].ptr, block);778		if (!xchk_btree_ptr_ok(bs, level, pp)) {779			cur->bc_levels[level].ptr++;780			continue;781		}782		level--;783		error = xchk_btree_get_block(bs, level, pp, &block, &bp);784		if (error || !block)785			goto out;786 787		cur->bc_levels[level].ptr = 1;788	}789 790out:791	/* Process deferred owner checks on btree blocks. */792	list_for_each_entry_safe(co, n, &bs->to_check, list) {793		if (!error && bs->cur)794			error = xchk_btree_check_block_owner(bs, co->level,795					co->daddr);796		list_del(&co->list);797		kfree(co);798	}799	kfree(bs);800 801	return error;802}803