Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
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_log_format.h"
13 : #include "xfs_trans.h"
14 : #include "xfs_inode.h"
15 : #include "xfs_dir2.h"
16 : #include "xfs_dir2_priv.h"
17 : #include "xfs_attr_leaf.h"
18 : #include "scrub/scrub.h"
19 : #include "scrub/common.h"
20 : #include "scrub/trace.h"
21 : #include "scrub/dabtree.h"
22 :
23 : /* Directory/Attribute Btree */
24 :
25 : /*
26 : * Check for da btree operation errors. See the section about handling
27 : * operational errors in common.c.
28 : */
29 : bool
30 2260635 : xchk_da_process_error(
31 : struct xchk_da_btree *ds,
32 : int level,
33 : int *error)
34 : {
35 2260635 : struct xfs_scrub *sc = ds->sc;
36 :
37 2260635 : if (*error == 0)
38 : return true;
39 :
40 0 : switch (*error) {
41 0 : case -EDEADLOCK:
42 : case -ECHRNG:
43 : /* Used to restart an op with deadlock avoidance. */
44 0 : trace_xchk_deadlock_retry(sc->ip, sc->sm, *error);
45 0 : break;
46 0 : case -EFSBADCRC:
47 : case -EFSCORRUPTED:
48 : /* Note the badness but don't abort. */
49 0 : sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
50 0 : xchk_whine(sc->mp, "ino 0x%llx fork %d type %s dablk 0x%llx error %d ret_ip %pS",
51 0 : sc->ip->i_ino,
52 : ds->dargs.whichfork,
53 0 : xchk_type_string(sc->sm->sm_type),
54 : xfs_dir2_da_to_db(ds->dargs.geo,
55 0 : ds->state->path.blk[level].blkno),
56 : *error,
57 : __return_address);
58 0 : *error = 0;
59 0 : fallthrough;
60 0 : default:
61 0 : if (*error)
62 0 : xchk_whine(sc->mp, "ino 0x%llx fork %d type %s dablk 0x%llx error %d ret_ip %pS",
63 0 : sc->ip->i_ino,
64 : ds->dargs.whichfork,
65 0 : xchk_type_string(sc->sm->sm_type),
66 : xfs_dir2_da_to_db(ds->dargs.geo,
67 0 : ds->state->path.blk[level].blkno),
68 : *error,
69 : __return_address);
70 0 : trace_xchk_file_op_error(sc, ds->dargs.whichfork,
71 0 : xfs_dir2_da_to_db(ds->dargs.geo,
72 0 : ds->state->path.blk[level].blkno),
73 : *error, __return_address);
74 0 : break;
75 : }
76 : return false;
77 : }
78 :
79 : /*
80 : * Check for da btree corruption. See the section about handling
81 : * operational errors in common.c.
82 : */
83 : void
84 0 : xchk_da_set_corrupt(
85 : struct xchk_da_btree *ds,
86 : int level)
87 : {
88 0 : struct xfs_scrub *sc = ds->sc;
89 :
90 0 : sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
91 :
92 0 : xchk_whine(sc->mp, "ino 0x%llx fork %d type %s dablk 0x%llx ret_ip %pS",
93 0 : sc->ip->i_ino,
94 : ds->dargs.whichfork,
95 0 : xchk_type_string(sc->sm->sm_type),
96 : xfs_dir2_da_to_db(ds->dargs.geo,
97 0 : ds->state->path.blk[level].blkno),
98 : __return_address);
99 0 : trace_xchk_fblock_error(sc, ds->dargs.whichfork,
100 0 : xfs_dir2_da_to_db(ds->dargs.geo,
101 0 : ds->state->path.blk[level].blkno),
102 : __return_address);
103 0 : }
104 :
105 : /* Flag a da btree node in need of optimization. */
106 : void
107 1051994 : xchk_da_set_preen(
108 : struct xchk_da_btree *ds,
109 : int level)
110 : {
111 1051994 : struct xfs_scrub *sc = ds->sc;
112 :
113 1051994 : sc->sm->sm_flags |= XFS_SCRUB_OFLAG_PREEN;
114 1051995 : trace_xchk_fblock_preen(sc, ds->dargs.whichfork,
115 1051994 : xfs_dir2_da_to_db(ds->dargs.geo,
116 1051994 : ds->state->path.blk[level].blkno),
117 : __return_address);
118 1051999 : }
119 :
120 : /* Find an entry at a certain level in a da btree. */
121 : static struct xfs_da_node_entry *
122 61044151 : xchk_da_btree_node_entry(
123 : struct xchk_da_btree *ds,
124 : int level)
125 : {
126 61044151 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
127 61044151 : struct xfs_da3_icnode_hdr hdr;
128 :
129 61044151 : ASSERT(blk->magic == XFS_DA_NODE_MAGIC);
130 :
131 61044151 : xfs_da3_node_hdr_from_disk(ds->sc->mp, &hdr, blk->bp->b_addr);
132 61045221 : return hdr.btree + blk->index;
133 : }
134 :
135 : /* Scrub a da btree hash (key). */
136 : int
137 83926238 : xchk_da_btree_hash(
138 : struct xchk_da_btree *ds,
139 : int level,
140 : __be32 *hashp)
141 : {
142 83926238 : struct xfs_da_node_entry *entry;
143 83926238 : xfs_dahash_t hash;
144 83926238 : xfs_dahash_t parent_hash;
145 :
146 : /* Is this hash in order? */
147 83926238 : hash = be32_to_cpu(*hashp);
148 83926238 : if (hash < ds->hashes[level])
149 0 : xchk_da_set_corrupt(ds, level);
150 83926238 : ds->hashes[level] = hash;
151 :
152 83926238 : if (level == 0)
153 : return 0;
154 :
155 : /* Is this hash no larger than the parent hash? */
156 60529186 : entry = xchk_da_btree_node_entry(ds, level - 1);
157 60529668 : parent_hash = be32_to_cpu(entry->hashval);
158 60529668 : if (parent_hash < hash)
159 0 : xchk_da_set_corrupt(ds, level);
160 :
161 : return 0;
162 : }
163 :
164 : /*
165 : * Check a da btree pointer. Returns true if it's ok to use this
166 : * pointer.
167 : */
168 : STATIC bool
169 1822255 : xchk_da_btree_ptr_ok(
170 : struct xchk_da_btree *ds,
171 : int level,
172 : xfs_dablk_t blkno)
173 : {
174 1822255 : if (blkno < ds->lowest || (ds->highest != 0 && blkno >= ds->highest)) {
175 0 : xchk_da_set_corrupt(ds, level);
176 0 : return false;
177 : }
178 :
179 : return true;
180 : }
181 :
182 : /*
183 : * The da btree scrubber can handle leaf1 blocks as a degenerate
184 : * form of leafn blocks. Since the regular da code doesn't handle
185 : * leaf1, we must multiplex the verifiers.
186 : */
187 : static void
188 14031 : xchk_da_btree_read_verify(
189 : struct xfs_buf *bp)
190 : {
191 14031 : struct xfs_da_blkinfo *info = bp->b_addr;
192 :
193 14031 : switch (be16_to_cpu(info->magic)) {
194 52 : case XFS_DIR2_LEAF1_MAGIC:
195 : case XFS_DIR3_LEAF1_MAGIC:
196 52 : bp->b_ops = &xfs_dir3_leaf1_buf_ops;
197 52 : bp->b_ops->verify_read(bp);
198 52 : return;
199 13979 : default:
200 : /*
201 : * xfs_da3_node_buf_ops already know how to handle
202 : * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks.
203 : */
204 13979 : bp->b_ops = &xfs_da3_node_buf_ops;
205 13979 : bp->b_ops->verify_read(bp);
206 13979 : return;
207 : }
208 : }
209 : static void
210 0 : xchk_da_btree_write_verify(
211 : struct xfs_buf *bp)
212 : {
213 0 : struct xfs_da_blkinfo *info = bp->b_addr;
214 :
215 0 : switch (be16_to_cpu(info->magic)) {
216 0 : case XFS_DIR2_LEAF1_MAGIC:
217 : case XFS_DIR3_LEAF1_MAGIC:
218 0 : bp->b_ops = &xfs_dir3_leaf1_buf_ops;
219 0 : bp->b_ops->verify_write(bp);
220 0 : return;
221 0 : default:
222 : /*
223 : * xfs_da3_node_buf_ops already know how to handle
224 : * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks.
225 : */
226 0 : bp->b_ops = &xfs_da3_node_buf_ops;
227 0 : bp->b_ops->verify_write(bp);
228 0 : return;
229 : }
230 : }
231 : static void *
232 0 : xchk_da_btree_verify(
233 : struct xfs_buf *bp)
234 : {
235 0 : struct xfs_da_blkinfo *info = bp->b_addr;
236 :
237 0 : switch (be16_to_cpu(info->magic)) {
238 0 : case XFS_DIR2_LEAF1_MAGIC:
239 : case XFS_DIR3_LEAF1_MAGIC:
240 0 : bp->b_ops = &xfs_dir3_leaf1_buf_ops;
241 0 : return bp->b_ops->verify_struct(bp);
242 0 : default:
243 0 : bp->b_ops = &xfs_da3_node_buf_ops;
244 0 : return bp->b_ops->verify_struct(bp);
245 : }
246 : }
247 :
248 : static const struct xfs_buf_ops xchk_da_btree_buf_ops = {
249 : .name = "xchk_da_btree",
250 : .verify_read = xchk_da_btree_read_verify,
251 : .verify_write = xchk_da_btree_write_verify,
252 : .verify_struct = xchk_da_btree_verify,
253 : };
254 :
255 : /* Check a block's sibling. */
256 : STATIC int
257 515955 : xchk_da_btree_block_check_sibling(
258 : struct xchk_da_btree *ds,
259 : int level,
260 : int direction,
261 : xfs_dablk_t sibling)
262 : {
263 515955 : struct xfs_da_state_path *path = &ds->state->path;
264 515955 : struct xfs_da_state_path *altpath = &ds->state->altpath;
265 515955 : int retval;
266 515955 : int plevel;
267 515955 : int error;
268 :
269 1031910 : memcpy(altpath, path, sizeof(ds->state->altpath));
270 :
271 : /*
272 : * If the pointer is null, we shouldn't be able to move the upper
273 : * level pointer anywhere.
274 : */
275 515955 : if (sibling == 0) {
276 77577 : error = xfs_da3_path_shift(ds->state, altpath, direction,
277 : false, &retval);
278 77576 : if (error == 0 && retval == 0)
279 0 : xchk_da_set_corrupt(ds, level);
280 77576 : error = 0;
281 77576 : goto out;
282 : }
283 :
284 : /* Move the alternate cursor one block in the direction given. */
285 438378 : error = xfs_da3_path_shift(ds->state, altpath, direction, false,
286 : &retval);
287 438377 : if (!xchk_da_process_error(ds, level, &error))
288 0 : goto out;
289 438378 : if (retval) {
290 0 : xchk_da_set_corrupt(ds, level);
291 0 : goto out;
292 : }
293 438378 : if (altpath->blk[level].bp)
294 438378 : xchk_buffer_recheck(ds->sc, altpath->blk[level].bp);
295 :
296 : /* Compare upper level pointer to sibling pointer. */
297 438378 : if (altpath->blk[level].blkno != sibling)
298 0 : xchk_da_set_corrupt(ds, level);
299 :
300 438378 : out:
301 : /* Free all buffers in the altpath that aren't referenced from path. */
302 1572889 : for (plevel = 0; plevel < altpath->active; plevel++) {
303 1056934 : if (altpath->blk[plevel].bp == NULL ||
304 1056934 : (plevel < path->active &&
305 1056934 : altpath->blk[plevel].bp == path->blk[plevel].bp))
306 618492 : continue;
307 :
308 438442 : xfs_trans_brelse(ds->dargs.trans, altpath->blk[plevel].bp);
309 438443 : altpath->blk[plevel].bp = NULL;
310 : }
311 :
312 515955 : return error;
313 : }
314 :
315 : /* Check a block's sibling pointers. */
316 : STATIC int
317 1551465 : xchk_da_btree_block_check_siblings(
318 : struct xchk_da_btree *ds,
319 : int level,
320 : struct xfs_da_blkinfo *hdr)
321 : {
322 1551465 : xfs_dablk_t forw;
323 1551465 : xfs_dablk_t back;
324 1551465 : int error = 0;
325 :
326 1551465 : forw = be32_to_cpu(hdr->forw);
327 1551465 : back = be32_to_cpu(hdr->back);
328 :
329 : /* Top level blocks should not have sibling pointers. */
330 1551465 : if (level == 0) {
331 1293488 : if (forw != 0 || back != 0)
332 0 : xchk_da_set_corrupt(ds, level);
333 1293488 : return 0;
334 : }
335 :
336 : /*
337 : * Check back (left) and forw (right) pointers. These functions
338 : * absorb error codes for us.
339 : */
340 257977 : error = xchk_da_btree_block_check_sibling(ds, level, 0, back);
341 257978 : if (error)
342 0 : goto out;
343 257978 : error = xchk_da_btree_block_check_sibling(ds, level, 1, forw);
344 :
345 257978 : out:
346 257978 : memset(&ds->state->altpath, 0, sizeof(ds->state->altpath));
347 257978 : return error;
348 : }
349 :
350 : /* Load a dir/attribute block from a btree. */
351 : STATIC int
352 1822260 : xchk_da_btree_block(
353 : struct xchk_da_btree *ds,
354 : int level,
355 : xfs_dablk_t blkno)
356 : {
357 1822260 : struct xfs_da_state_blk *blk;
358 1822260 : struct xfs_da_intnode *node;
359 1822260 : struct xfs_da_node_entry *btree;
360 1822260 : struct xfs_da3_blkinfo *hdr3;
361 1822260 : struct xfs_da_args *dargs = &ds->dargs;
362 1822260 : struct xfs_inode *ip = ds->dargs.dp;
363 1822260 : xfs_failaddr_t fa;
364 1822260 : xfs_ino_t owner;
365 1822260 : int *pmaxrecs;
366 1822260 : struct xfs_da3_icnode_hdr nodehdr;
367 1822260 : int error = 0;
368 :
369 1822260 : blk = &ds->state->path.blk[level];
370 1822260 : ds->state->path.active = level + 1;
371 :
372 : /* Release old block. */
373 1822260 : if (blk->bp) {
374 219189 : xfs_trans_brelse(dargs->trans, blk->bp);
375 219189 : blk->bp = NULL;
376 : }
377 :
378 : /* Check the pointer. */
379 1822260 : blk->blkno = blkno;
380 1822260 : if (!xchk_da_btree_ptr_ok(ds, level, blkno))
381 0 : goto out_nobuf;
382 :
383 : /* Read the buffer. */
384 1822255 : error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno,
385 : XFS_DABUF_MAP_HOLE_OK, &blk->bp, dargs->whichfork,
386 : &xchk_da_btree_buf_ops);
387 1822265 : if (!xchk_da_process_error(ds, level, &error))
388 0 : goto out_nobuf;
389 1822268 : if (blk->bp)
390 1551515 : xchk_buffer_recheck(ds->sc, blk->bp);
391 :
392 : /*
393 : * We didn't find a dir btree root block, which means that
394 : * there's no LEAF1/LEAFN tree (at least not where it's supposed
395 : * to be), so jump out now.
396 : */
397 1822211 : if (ds->dargs.whichfork == XFS_DATA_FORK && level == 0 &&
398 293622 : blk->bp == NULL)
399 270753 : goto out_nobuf;
400 :
401 : /* It's /not/ ok for attr trees not to have a da btree. */
402 1551458 : if (blk->bp == NULL) {
403 0 : xchk_da_set_corrupt(ds, level);
404 0 : goto out_nobuf;
405 : }
406 :
407 1551458 : hdr3 = blk->bp->b_addr;
408 1551458 : blk->magic = be16_to_cpu(hdr3->hdr.magic);
409 1551458 : pmaxrecs = &ds->maxrecs[level];
410 :
411 : /* We only started zeroing the header on v5 filesystems. */
412 1551458 : if (xfs_has_crc(ds->sc->mp) && hdr3->hdr.pad)
413 0 : xchk_da_set_corrupt(ds, level);
414 :
415 : /* Check the owner. */
416 1551458 : if (xfs_has_crc(ip->i_mount)) {
417 1551467 : owner = be64_to_cpu(hdr3->owner);
418 1551467 : if (owner != ip->i_ino)
419 0 : xchk_da_set_corrupt(ds, level);
420 : }
421 :
422 : /* Check the siblings. */
423 1551458 : error = xchk_da_btree_block_check_siblings(ds, level, &hdr3->hdr);
424 1551455 : if (error)
425 0 : goto out;
426 :
427 : /* Interpret the buffer. */
428 1551455 : switch (blk->magic) {
429 1319932 : case XFS_ATTR_LEAF_MAGIC:
430 : case XFS_ATTR3_LEAF_MAGIC:
431 1319932 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
432 : XFS_BLFT_ATTR_LEAF_BUF);
433 1319948 : blk->magic = XFS_ATTR_LEAF_MAGIC;
434 1319948 : blk->hashval = xfs_attr_leaf_lasthash(blk->bp, pmaxrecs);
435 1319944 : if (ds->tree_level != 0)
436 0 : xchk_da_set_corrupt(ds, level);
437 : break;
438 186458 : case XFS_DIR2_LEAFN_MAGIC:
439 : case XFS_DIR3_LEAFN_MAGIC:
440 186458 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
441 : XFS_BLFT_DIR_LEAFN_BUF);
442 186458 : blk->magic = XFS_DIR2_LEAFN_MAGIC;
443 186458 : blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
444 186458 : if (ds->tree_level != 0)
445 0 : xchk_da_set_corrupt(ds, level);
446 : break;
447 6244 : case XFS_DIR2_LEAF1_MAGIC:
448 : case XFS_DIR3_LEAF1_MAGIC:
449 6244 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
450 : XFS_BLFT_DIR_LEAF1_BUF);
451 6244 : blk->magic = XFS_DIR2_LEAF1_MAGIC;
452 6244 : blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
453 6244 : if (ds->tree_level != 0)
454 0 : xchk_da_set_corrupt(ds, level);
455 : break;
456 38821 : case XFS_DA_NODE_MAGIC:
457 : case XFS_DA3_NODE_MAGIC:
458 38821 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
459 : XFS_BLFT_DA_NODE_BUF);
460 38821 : blk->magic = XFS_DA_NODE_MAGIC;
461 38821 : node = blk->bp->b_addr;
462 38821 : xfs_da3_node_hdr_from_disk(ip->i_mount, &nodehdr, node);
463 38821 : btree = nodehdr.btree;
464 38821 : *pmaxrecs = nodehdr.count;
465 38821 : blk->hashval = be32_to_cpu(btree[*pmaxrecs - 1].hashval);
466 38821 : if (level == 0) {
467 38784 : if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
468 0 : xchk_da_set_corrupt(ds, level);
469 0 : goto out_freebp;
470 : }
471 38784 : ds->tree_level = nodehdr.level;
472 : } else {
473 37 : if (ds->tree_level != nodehdr.level) {
474 0 : xchk_da_set_corrupt(ds, level);
475 0 : goto out_freebp;
476 : }
477 : }
478 :
479 : /* XXX: Check hdr3.pad32 once we know how to fix it. */
480 : break;
481 0 : default:
482 0 : xchk_da_set_corrupt(ds, level);
483 0 : goto out_freebp;
484 : }
485 :
486 1551467 : fa = xfs_da3_header_check(blk->bp, dargs->owner);
487 1551494 : if (fa) {
488 0 : xchk_da_set_corrupt(ds, level);
489 0 : goto out_freebp;
490 : }
491 :
492 : /*
493 : * If we've been handed a block that is below the dabtree root, does
494 : * its hashval match what the parent block expected to see?
495 : */
496 1551494 : if (level > 0) {
497 257978 : struct xfs_da_node_entry *key;
498 :
499 257978 : key = xchk_da_btree_node_entry(ds, level - 1);
500 515956 : if (be32_to_cpu(key->hashval) != blk->hashval) {
501 0 : xchk_da_set_corrupt(ds, level);
502 0 : goto out_freebp;
503 : }
504 : }
505 :
506 1551494 : out:
507 : return error;
508 0 : out_freebp:
509 0 : xfs_trans_brelse(dargs->trans, blk->bp);
510 0 : blk->bp = NULL;
511 270753 : out_nobuf:
512 270753 : blk->blkno = 0;
513 270753 : return error;
514 : }
515 :
516 : /* Visit all nodes and leaves of a da btree. */
517 : int
518 15574498 : xchk_da_btree(
519 : struct xfs_scrub *sc,
520 : int whichfork,
521 : xchk_da_btree_rec_fn scrub_fn,
522 : void *private)
523 : {
524 15574498 : struct xchk_da_btree *ds;
525 15574498 : struct xfs_mount *mp = sc->mp;
526 15574498 : struct xfs_da_state_blk *blks;
527 15574498 : struct xfs_da_node_entry *key;
528 15574498 : xfs_dablk_t blkno;
529 15574498 : int level;
530 15574498 : int error;
531 :
532 : /* Skip short format data structures; no btree to scan. */
533 15574498 : if (!xfs_ifork_has_extents(xfs_ifork_ptr(sc->ip, whichfork)))
534 : return 0;
535 :
536 : /* Set up initial da state. */
537 1564293 : ds = kzalloc(sizeof(struct xchk_da_btree), XCHK_GFP_FLAGS);
538 1564290 : if (!ds)
539 : return -ENOMEM;
540 1564290 : ds->dargs.dp = sc->ip;
541 1564290 : ds->dargs.whichfork = whichfork;
542 1564290 : ds->dargs.trans = sc->tp;
543 1564290 : ds->dargs.op_flags = XFS_DA_OP_OKNOENT;
544 1564290 : ds->dargs.owner = sc->ip->i_ino;
545 1564290 : ds->state = xfs_da_state_alloc(&ds->dargs);
546 1564290 : ds->sc = sc;
547 1564290 : ds->private = private;
548 1564290 : if (whichfork == XFS_ATTR_FORK) {
549 1270668 : ds->dargs.geo = mp->m_attr_geo;
550 1270668 : ds->lowest = 0;
551 1270668 : ds->highest = 0;
552 : } else {
553 293622 : ds->dargs.geo = mp->m_dir_geo;
554 293622 : ds->lowest = ds->dargs.geo->leafblk;
555 293622 : ds->highest = ds->dargs.geo->freeblk;
556 : }
557 1564290 : blkno = ds->lowest;
558 1564290 : level = 0;
559 :
560 : /* Find the root of the da tree, if present. */
561 1564290 : blks = ds->state->path.blk;
562 1564290 : error = xchk_da_btree_block(ds, level, blkno);
563 1564257 : if (error)
564 0 : goto out_state;
565 : /*
566 : * We didn't find a block at ds->lowest, which means that there's
567 : * no LEAF1/LEAFN tree (at least not where it's supposed to be),
568 : * so jump out now.
569 : */
570 1564257 : if (blks[level].bp == NULL)
571 270753 : goto out_state;
572 :
573 1293504 : blks[level].index = 0;
574 86771064 : while (level >= 0 && level < XFS_DA_NODE_MAXDEPTH) {
575 : /* Handle leaf block. */
576 85477564 : if (blks[level].magic != XFS_DA_NODE_MAGIC) {
577 : /* End of leaf, pop back towards the root. */
578 85180769 : if (blks[level].index >= ds->maxrecs[level]) {
579 1512652 : if (level > 0)
580 257940 : blks[level - 1].index++;
581 1512652 : ds->tree_level++;
582 1512652 : level--;
583 1512652 : continue;
584 : }
585 :
586 : /* Dispatch record scrubbing. */
587 83668117 : error = scrub_fn(ds, level);
588 83666175 : if (error)
589 : break;
590 83666175 : if (xchk_should_terminate(sc, &error) ||
591 83668110 : (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
592 : break;
593 :
594 83668110 : blks[level].index++;
595 83668110 : continue;
596 : }
597 :
598 :
599 : /* End of node, pop back towards the root. */
600 296795 : if (blks[level].index >= ds->maxrecs[level]) {
601 38820 : if (level > 0)
602 37 : blks[level - 1].index++;
603 38820 : ds->tree_level++;
604 38820 : level--;
605 38820 : continue;
606 : }
607 :
608 : /* Hashes in order for scrub? */
609 257975 : key = xchk_da_btree_node_entry(ds, level);
610 257977 : error = xchk_da_btree_hash(ds, level, &key->hashval);
611 257978 : if (error)
612 0 : goto out;
613 :
614 : /* Drill another level deeper. */
615 257978 : blkno = be32_to_cpu(key->before);
616 257978 : level++;
617 257978 : if (level >= XFS_DA_NODE_MAXDEPTH) {
618 : /* Too deep! */
619 0 : xchk_da_set_corrupt(ds, level - 1);
620 0 : break;
621 : }
622 257978 : ds->tree_level--;
623 257978 : error = xchk_da_btree_block(ds, level, blkno);
624 257978 : if (error)
625 0 : goto out;
626 257978 : if (blks[level].bp == NULL)
627 0 : goto out;
628 :
629 257978 : blks[level].index = 0;
630 : }
631 :
632 1293501 : out:
633 : /* Release all the buffers we're tracking. */
634 7761209 : for (level = 0; level < XFS_DA_NODE_MAXDEPTH; level++) {
635 6467666 : if (blks[level].bp == NULL)
636 5135375 : continue;
637 1332291 : xfs_trans_brelse(sc->tp, blks[level].bp);
638 1332333 : blks[level].bp = NULL;
639 : }
640 :
641 1293543 : out_state:
642 1564296 : xfs_da_state_free(ds->state);
643 1564296 : kfree(ds);
644 1564296 : return error;
645 : }
|