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 3839635 : xchk_da_process_error(
31 : struct xchk_da_btree *ds,
32 : int level,
33 : int *error)
34 : {
35 3839635 : struct xfs_scrub *sc = ds->sc;
36 :
37 3839635 : 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 1961565 : xchk_da_set_preen(
108 : struct xchk_da_btree *ds,
109 : int level)
110 : {
111 1961565 : struct xfs_scrub *sc = ds->sc;
112 :
113 1961565 : sc->sm->sm_flags |= XFS_SCRUB_OFLAG_PREEN;
114 3923718 : trace_xchk_fblock_preen(sc, ds->dargs.whichfork,
115 1958458 : xfs_dir2_da_to_db(ds->dargs.geo,
116 1959513 : ds->state->path.blk[level].blkno),
117 : __return_address);
118 1963069 : }
119 :
120 : /* Find an entry at a certain level in a da btree. */
121 : static struct xfs_da_node_entry *
122 79202076 : xchk_da_btree_node_entry(
123 : struct xchk_da_btree *ds,
124 : int level)
125 : {
126 79202076 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
127 79172687 : struct xfs_da3_icnode_hdr hdr;
128 :
129 79172687 : ASSERT(blk->magic == XFS_DA_NODE_MAGIC);
130 :
131 79172687 : xfs_da3_node_hdr_from_disk(ds->sc->mp, &hdr, blk->bp->b_addr);
132 79183749 : return hdr.btree + blk->index;
133 : }
134 :
135 : /* Scrub a da btree hash (key). */
136 : int
137 121067577 : xchk_da_btree_hash(
138 : struct xchk_da_btree *ds,
139 : int level,
140 : __be32 *hashp)
141 : {
142 121067577 : struct xfs_da_node_entry *entry;
143 121067577 : xfs_dahash_t hash;
144 121067577 : xfs_dahash_t parent_hash;
145 :
146 : /* Is this hash in order? */
147 121067577 : hash = be32_to_cpu(*hashp);
148 121067577 : if (hash < ds->hashes[level])
149 0 : xchk_da_set_corrupt(ds, level);
150 120985616 : ds->hashes[level] = hash;
151 :
152 120989896 : if (level == 0)
153 : return 0;
154 :
155 : /* Is this hash no larger than the parent hash? */
156 78196431 : entry = xchk_da_btree_node_entry(ds, level - 1);
157 78251463 : parent_hash = be32_to_cpu(entry->hashval);
158 78251463 : 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 3025820 : xchk_da_btree_ptr_ok(
170 : struct xchk_da_btree *ds,
171 : int level,
172 : xfs_dablk_t blkno)
173 : {
174 3025820 : 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 14109 : xchk_da_btree_read_verify(
189 : struct xfs_buf *bp)
190 : {
191 14109 : struct xfs_da_blkinfo *info = bp->b_addr;
192 :
193 14109 : switch (be16_to_cpu(info->magic)) {
194 391 : case XFS_DIR2_LEAF1_MAGIC:
195 : case XFS_DIR3_LEAF1_MAGIC:
196 391 : bp->b_ops = &xfs_dir3_leaf1_buf_ops;
197 391 : bp->b_ops->verify_read(bp);
198 391 : return;
199 13718 : default:
200 : /*
201 : * xfs_da3_node_buf_ops already know how to handle
202 : * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks.
203 : */
204 13718 : bp->b_ops = &xfs_da3_node_buf_ops;
205 13718 : bp->b_ops->verify_read(bp);
206 13718 : 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 951122 : 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 951122 : struct xfs_da_state_path *path = &ds->state->path;
264 951122 : struct xfs_da_state_path *altpath = &ds->state->altpath;
265 951122 : int retval;
266 951122 : int plevel;
267 951122 : int error;
268 :
269 1902244 : 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 951122 : if (sibling == 0) {
276 132467 : error = xfs_da3_path_shift(ds->state, altpath, direction,
277 : false, &retval);
278 132465 : if (error == 0 && retval == 0)
279 0 : xchk_da_set_corrupt(ds, level);
280 132465 : error = 0;
281 132465 : goto out;
282 : }
283 :
284 : /* Move the alternate cursor one block in the direction given. */
285 818655 : error = xfs_da3_path_shift(ds->state, altpath, direction, false,
286 : &retval);
287 818654 : if (!xchk_da_process_error(ds, level, &error))
288 0 : goto out;
289 818650 : if (retval) {
290 0 : xchk_da_set_corrupt(ds, level);
291 0 : goto out;
292 : }
293 818650 : if (altpath->blk[level].bp)
294 818652 : xchk_buffer_recheck(ds->sc, altpath->blk[level].bp);
295 :
296 : /* Compare upper level pointer to sibling pointer. */
297 818664 : if (altpath->blk[level].blkno != sibling)
298 0 : xchk_da_set_corrupt(ds, level);
299 :
300 818664 : out:
301 : /* Free all buffers in the altpath that aren't referenced from path. */
302 3094247 : for (plevel = 0; plevel < altpath->active; plevel++) {
303 2143122 : if (altpath->blk[plevel].bp == NULL ||
304 2143104 : (plevel < path->active &&
305 2143104 : altpath->blk[plevel].bp == path->blk[plevel].bp))
306 1323668 : continue;
307 :
308 819436 : xfs_trans_brelse(ds->dargs.trans, altpath->blk[plevel].bp);
309 819450 : altpath->blk[plevel].bp = NULL;
310 : }
311 :
312 951125 : return error;
313 : }
314 :
315 : /* Check a block's sibling pointers. */
316 : STATIC int
317 2749643 : xchk_da_btree_block_check_siblings(
318 : struct xchk_da_btree *ds,
319 : int level,
320 : struct xfs_da_blkinfo *hdr)
321 : {
322 2749643 : xfs_dablk_t forw;
323 2749643 : xfs_dablk_t back;
324 2749643 : int error = 0;
325 :
326 2749643 : forw = be32_to_cpu(hdr->forw);
327 2749643 : back = be32_to_cpu(hdr->back);
328 :
329 : /* Top level blocks should not have sibling pointers. */
330 2749643 : if (level == 0) {
331 2274073 : if (forw != 0 || back != 0)
332 0 : xchk_da_set_corrupt(ds, level);
333 2274073 : return 0;
334 : }
335 :
336 : /*
337 : * Check back (left) and forw (right) pointers. These functions
338 : * absorb error codes for us.
339 : */
340 475570 : error = xchk_da_btree_block_check_sibling(ds, level, 0, back);
341 475554 : if (error)
342 0 : goto out;
343 475554 : error = xchk_da_btree_block_check_sibling(ds, level, 1, forw);
344 :
345 475570 : out:
346 475570 : memset(&ds->state->altpath, 0, sizeof(ds->state->altpath));
347 475570 : return error;
348 : }
349 :
350 : /* Load a dir/attribute block from a btree. */
351 : STATIC int
352 3030605 : xchk_da_btree_block(
353 : struct xchk_da_btree *ds,
354 : int level,
355 : xfs_dablk_t blkno)
356 : {
357 3030605 : struct xfs_da_state_blk *blk;
358 3030605 : struct xfs_da_intnode *node;
359 3030605 : struct xfs_da_node_entry *btree;
360 3030605 : struct xfs_da3_blkinfo *hdr3;
361 3030605 : struct xfs_da_args *dargs = &ds->dargs;
362 3030605 : struct xfs_inode *ip = ds->dargs.dp;
363 3030605 : xfs_failaddr_t fa;
364 3030605 : xfs_ino_t owner;
365 3030605 : int *pmaxrecs;
366 3030605 : struct xfs_da3_icnode_hdr nodehdr;
367 3030605 : int error = 0;
368 :
369 3030605 : blk = &ds->state->path.blk[level];
370 3022317 : ds->state->path.active = level + 1;
371 :
372 : /* Release old block. */
373 3022317 : if (blk->bp) {
374 409328 : xfs_trans_brelse(dargs->trans, blk->bp);
375 409333 : blk->bp = NULL;
376 : }
377 :
378 : /* Check the pointer. */
379 3022322 : blk->blkno = blkno;
380 3022322 : if (!xchk_da_btree_ptr_ok(ds, level, blkno))
381 0 : goto out_nobuf;
382 :
383 : /* Read the buffer. */
384 3018032 : 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 3025713 : if (!xchk_da_process_error(ds, level, &error))
388 0 : goto out_nobuf;
389 3019603 : if (blk->bp)
390 2737450 : 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 3033747 : if (ds->dargs.whichfork == XFS_DATA_FORK && level == 0 &&
398 327903 : blk->bp == NULL)
399 282156 : goto out_nobuf;
400 :
401 : /* It's /not/ ok for attr trees not to have a da btree. */
402 2751591 : if (blk->bp == NULL) {
403 0 : xchk_da_set_corrupt(ds, level);
404 0 : goto out_nobuf;
405 : }
406 :
407 2751591 : hdr3 = blk->bp->b_addr;
408 2751591 : blk->magic = be16_to_cpu(hdr3->hdr.magic);
409 2751591 : pmaxrecs = &ds->maxrecs[level];
410 :
411 : /* We only started zeroing the header on v5 filesystems. */
412 2751225 : if (xfs_has_crc(ds->sc->mp) && hdr3->hdr.pad)
413 0 : xchk_da_set_corrupt(ds, level);
414 :
415 : /* Check the owner. */
416 2751225 : if (xfs_has_crc(ip->i_mount)) {
417 2750289 : owner = be64_to_cpu(hdr3->owner);
418 2750289 : if (owner != ip->i_ino)
419 0 : xchk_da_set_corrupt(ds, level);
420 : }
421 :
422 : /* Check the siblings. */
423 2751225 : error = xchk_da_btree_block_check_siblings(ds, level, &hdr3->hdr);
424 2746547 : if (error)
425 0 : goto out;
426 :
427 : /* Interpret the buffer. */
428 2746547 : switch (blk->magic) {
429 2432273 : case XFS_ATTR_LEAF_MAGIC:
430 : case XFS_ATTR3_LEAF_MAGIC:
431 2432273 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
432 : XFS_BLFT_ATTR_LEAF_BUF);
433 2427471 : blk->magic = XFS_ATTR_LEAF_MAGIC;
434 2427471 : blk->hashval = xfs_attr_leaf_lasthash(blk->bp, pmaxrecs);
435 2430780 : if (ds->tree_level != 0)
436 0 : xchk_da_set_corrupt(ds, level);
437 : break;
438 227799 : case XFS_DIR2_LEAFN_MAGIC:
439 : case XFS_DIR3_LEAFN_MAGIC:
440 227799 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
441 : XFS_BLFT_DIR_LEAFN_BUF);
442 227797 : blk->magic = XFS_DIR2_LEAFN_MAGIC;
443 227797 : blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
444 227797 : if (ds->tree_level != 0)
445 0 : xchk_da_set_corrupt(ds, level);
446 : break;
447 19851 : case XFS_DIR2_LEAF1_MAGIC:
448 : case XFS_DIR3_LEAF1_MAGIC:
449 19851 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
450 : XFS_BLFT_DIR_LEAF1_BUF);
451 19851 : blk->magic = XFS_DIR2_LEAF1_MAGIC;
452 19851 : blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
453 19851 : if (ds->tree_level != 0)
454 0 : xchk_da_set_corrupt(ds, level);
455 : break;
456 66624 : case XFS_DA_NODE_MAGIC:
457 : case XFS_DA3_NODE_MAGIC:
458 66624 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
459 : XFS_BLFT_DA_NODE_BUF);
460 66619 : blk->magic = XFS_DA_NODE_MAGIC;
461 66619 : node = blk->bp->b_addr;
462 66619 : xfs_da3_node_hdr_from_disk(ip->i_mount, &nodehdr, node);
463 66622 : btree = nodehdr.btree;
464 66622 : *pmaxrecs = nodehdr.count;
465 66622 : blk->hashval = be32_to_cpu(btree[*pmaxrecs - 1].hashval);
466 66622 : if (level == 0) {
467 66173 : if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
468 0 : xchk_da_set_corrupt(ds, level);
469 0 : goto out_freebp;
470 : }
471 66173 : ds->tree_level = nodehdr.level;
472 : } else {
473 449 : 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 2745050 : fa = xfs_da3_header_check(blk->bp, dargs->owner);
487 2739776 : 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 2739776 : if (level > 0) {
497 475557 : struct xfs_da_node_entry *key;
498 :
499 475557 : key = xchk_da_btree_node_entry(ds, level - 1);
500 475551 : 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 2739770 : out:
507 : return error;
508 0 : out_freebp:
509 0 : xfs_trans_brelse(dargs->trans, blk->bp);
510 0 : blk->bp = NULL;
511 282156 : out_nobuf:
512 282156 : blk->blkno = 0;
513 282156 : return error;
514 : }
515 :
516 : /* Visit all nodes and leaves of a da btree. */
517 : int
518 21554659 : xchk_da_btree(
519 : struct xfs_scrub *sc,
520 : int whichfork,
521 : xchk_da_btree_rec_fn scrub_fn,
522 : void *private)
523 : {
524 21554659 : struct xchk_da_btree *ds;
525 21554659 : struct xfs_mount *mp = sc->mp;
526 21554659 : struct xfs_da_state_blk *blks;
527 21554659 : struct xfs_da_node_entry *key;
528 21554659 : xfs_dablk_t blkno;
529 21554659 : int level;
530 21554659 : int error;
531 :
532 : /* Skip short format data structures; no btree to scan. */
533 21554659 : if (!xfs_ifork_has_extents(xfs_ifork_ptr(sc->ip, whichfork)))
534 : return 0;
535 :
536 : /* Set up initial da state. */
537 2546274 : ds = kzalloc(sizeof(struct xchk_da_btree), XCHK_GFP_FLAGS);
538 2551842 : if (!ds)
539 : return -ENOMEM;
540 2551842 : ds->dargs.dp = sc->ip;
541 2551842 : ds->dargs.whichfork = whichfork;
542 2551842 : ds->dargs.trans = sc->tp;
543 2551842 : ds->dargs.op_flags = XFS_DA_OP_OKNOENT;
544 2551842 : ds->dargs.owner = sc->ip->i_ino;
545 2551842 : ds->state = xfs_da_state_alloc(&ds->dargs);
546 2551958 : ds->sc = sc;
547 2551958 : ds->private = private;
548 2551958 : if (whichfork == XFS_ATTR_FORK) {
549 2224028 : ds->dargs.geo = mp->m_attr_geo;
550 2224028 : ds->lowest = 0;
551 2224028 : ds->highest = 0;
552 : } else {
553 327930 : ds->dargs.geo = mp->m_dir_geo;
554 327930 : ds->lowest = ds->dargs.geo->leafblk;
555 327930 : ds->highest = ds->dargs.geo->freeblk;
556 : }
557 2551958 : blkno = ds->lowest;
558 2551958 : level = 0;
559 :
560 : /* Find the root of the da tree, if present. */
561 2551958 : blks = ds->state->path.blk;
562 2551958 : error = xchk_da_btree_block(ds, level, blkno);
563 2547679 : 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 2547679 : if (blks[level].bp == NULL)
571 282155 : goto out_state;
572 :
573 2265524 : blks[level].index = 0;
574 126115569 : while (level >= 0 && level < XFS_DA_NODE_MAXDEPTH) {
575 : /* Handle leaf block. */
576 123838160 : if (blks[level].magic != XFS_DA_NODE_MAGIC) {
577 : /* End of leaf, pop back towards the root. */
578 123295974 : if (blks[level].index >= ds->maxrecs[level]) {
579 2686729 : if (level > 0)
580 475119 : blks[level - 1].index++;
581 2686729 : ds->tree_level++;
582 2686729 : level--;
583 2686729 : continue;
584 : }
585 :
586 : /* Dispatch record scrubbing. */
587 120641175 : error = scrub_fn(ds, level);
588 120646694 : if (error)
589 : break;
590 120646694 : if (xchk_should_terminate(sc, &error) ||
591 120621138 : (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
592 : break;
593 :
594 120621138 : blks[level].index++;
595 120621138 : continue;
596 : }
597 :
598 :
599 : /* End of node, pop back towards the root. */
600 542186 : if (blks[level].index >= ds->maxrecs[level]) {
601 66626 : if (level > 0)
602 449 : blks[level - 1].index++;
603 66626 : ds->tree_level++;
604 66626 : level--;
605 66626 : continue;
606 : }
607 :
608 : /* Hashes in order for scrub? */
609 475559 : key = xchk_da_btree_node_entry(ds, level);
610 475552 : error = xchk_da_btree_hash(ds, level, &key->hashval);
611 475555 : if (error)
612 0 : goto out;
613 :
614 : /* Drill another level deeper. */
615 475555 : blkno = be32_to_cpu(key->before);
616 475555 : level++;
617 475555 : if (level >= XFS_DA_NODE_MAXDEPTH) {
618 : /* Too deep! */
619 0 : xchk_da_set_corrupt(ds, level - 1);
620 0 : break;
621 : }
622 475555 : ds->tree_level--;
623 475555 : error = xchk_da_btree_block(ds, level, blkno);
624 475552 : if (error)
625 0 : goto out;
626 475552 : if (blks[level].bp == NULL)
627 0 : goto out;
628 :
629 475552 : blks[level].index = 0;
630 : }
631 :
632 2277416 : out:
633 : /* Release all the buffers we're tracking. */
634 13645924 : for (level = 0; level < XFS_DA_NODE_MAXDEPTH; level++) {
635 11371853 : if (blks[level].bp == NULL)
636 9028270 : continue;
637 2343583 : xfs_trans_brelse(sc->tp, blks[level].bp);
638 2340238 : blks[level].bp = NULL;
639 : }
640 :
641 2274071 : out_state:
642 2556226 : xfs_da_state_free(ds->state);
643 2552839 : kfree(ds);
644 2555873 : return error;
645 : }
|