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 3238611 : xchk_da_process_error(
31 : struct xchk_da_btree *ds,
32 : int level,
33 : int *error)
34 : {
35 3238611 : struct xfs_scrub *sc = ds->sc;
36 :
37 3238611 : 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 1252417 : xchk_da_set_preen(
108 : struct xchk_da_btree *ds,
109 : int level)
110 : {
111 1252417 : struct xfs_scrub *sc = ds->sc;
112 :
113 1252417 : sc->sm->sm_flags |= XFS_SCRUB_OFLAG_PREEN;
114 2503994 : trace_xchk_fblock_preen(sc, ds->dargs.whichfork,
115 1251574 : xfs_dir2_da_to_db(ds->dargs.geo,
116 1251886 : ds->state->path.blk[level].blkno),
117 : __return_address);
118 1252458 : }
119 :
120 : /* Find an entry at a certain level in a da btree. */
121 : static struct xfs_da_node_entry *
122 98061644 : xchk_da_btree_node_entry(
123 : struct xchk_da_btree *ds,
124 : int level)
125 : {
126 98061644 : struct xfs_da_state_blk *blk = &ds->state->path.blk[level];
127 98049149 : struct xfs_da3_icnode_hdr hdr;
128 :
129 98049149 : ASSERT(blk->magic == XFS_DA_NODE_MAGIC);
130 :
131 98049149 : xfs_da3_node_hdr_from_disk(ds->sc->mp, &hdr, blk->bp->b_addr);
132 98042389 : return hdr.btree + blk->index;
133 : }
134 :
135 : /* Scrub a da btree hash (key). */
136 : int
137 125753173 : xchk_da_btree_hash(
138 : struct xchk_da_btree *ds,
139 : int level,
140 : __be32 *hashp)
141 : {
142 125753173 : struct xfs_da_node_entry *entry;
143 125753173 : xfs_dahash_t hash;
144 125753173 : xfs_dahash_t parent_hash;
145 :
146 : /* Is this hash in order? */
147 125753173 : hash = be32_to_cpu(*hashp);
148 125753173 : if (hash < ds->hashes[level])
149 0 : xchk_da_set_corrupt(ds, level);
150 125721716 : ds->hashes[level] = hash;
151 :
152 125725672 : if (level == 0)
153 : return 0;
154 :
155 : /* Is this hash no larger than the parent hash? */
156 97066296 : entry = xchk_da_btree_node_entry(ds, level - 1);
157 97065366 : parent_hash = be32_to_cpu(entry->hashval);
158 97065366 : 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 2365753 : xchk_da_btree_ptr_ok(
170 : struct xchk_da_btree *ds,
171 : int level,
172 : xfs_dablk_t blkno)
173 : {
174 2365753 : 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 15578 : xchk_da_btree_read_verify(
189 : struct xfs_buf *bp)
190 : {
191 15578 : struct xfs_da_blkinfo *info = bp->b_addr;
192 :
193 15578 : switch (be16_to_cpu(info->magic)) {
194 473 : case XFS_DIR2_LEAF1_MAGIC:
195 : case XFS_DIR3_LEAF1_MAGIC:
196 473 : bp->b_ops = &xfs_dir3_leaf1_buf_ops;
197 473 : bp->b_ops->verify_read(bp);
198 473 : return;
199 15105 : default:
200 : /*
201 : * xfs_da3_node_buf_ops already know how to handle
202 : * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks.
203 : */
204 15105 : bp->b_ops = &xfs_da3_node_buf_ops;
205 15105 : bp->b_ops->verify_read(bp);
206 15105 : 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 983986 : 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 983986 : struct xfs_da_state_path *path = &ds->state->path;
264 983986 : struct xfs_da_state_path *altpath = &ds->state->altpath;
265 983986 : int retval;
266 983986 : int plevel;
267 983986 : int error;
268 :
269 1967972 : 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 983986 : if (sibling == 0) {
276 112754 : error = xfs_da3_path_shift(ds->state, altpath, direction,
277 : false, &retval);
278 112750 : if (error == 0 && retval == 0)
279 0 : xchk_da_set_corrupt(ds, level);
280 112750 : error = 0;
281 112750 : goto out;
282 : }
283 :
284 : /* Move the alternate cursor one block in the direction given. */
285 871232 : error = xfs_da3_path_shift(ds->state, altpath, direction, false,
286 : &retval);
287 871227 : if (!xchk_da_process_error(ds, level, &error))
288 0 : goto out;
289 871228 : if (retval) {
290 0 : xchk_da_set_corrupt(ds, level);
291 0 : goto out;
292 : }
293 871228 : if (altpath->blk[level].bp)
294 871228 : xchk_buffer_recheck(ds->sc, altpath->blk[level].bp);
295 :
296 : /* Compare upper level pointer to sibling pointer. */
297 871243 : if (altpath->blk[level].blkno != sibling)
298 0 : xchk_da_set_corrupt(ds, level);
299 :
300 871243 : out:
301 : /* Free all buffers in the altpath that aren't referenced from path. */
302 3184414 : for (plevel = 0; plevel < altpath->active; plevel++) {
303 2200421 : if (altpath->blk[plevel].bp == NULL ||
304 2200424 : (plevel < path->active &&
305 2200424 : altpath->blk[plevel].bp == path->blk[plevel].bp))
306 1328425 : continue;
307 :
308 871995 : xfs_trans_brelse(ds->dargs.trans, altpath->blk[plevel].bp);
309 871996 : altpath->blk[plevel].bp = NULL;
310 : }
311 :
312 983993 : return error;
313 : }
314 :
315 : /* Check a block's sibling pointers. */
316 : STATIC int
317 2006710 : xchk_da_btree_block_check_siblings(
318 : struct xchk_da_btree *ds,
319 : int level,
320 : struct xfs_da_blkinfo *hdr)
321 : {
322 2006710 : xfs_dablk_t forw;
323 2006710 : xfs_dablk_t back;
324 2006710 : int error = 0;
325 :
326 2006710 : forw = be32_to_cpu(hdr->forw);
327 2006710 : back = be32_to_cpu(hdr->back);
328 :
329 : /* Top level blocks should not have sibling pointers. */
330 2006710 : if (level == 0) {
331 1514710 : if (forw != 0 || back != 0)
332 0 : xchk_da_set_corrupt(ds, level);
333 1514710 : return 0;
334 : }
335 :
336 : /*
337 : * Check back (left) and forw (right) pointers. These functions
338 : * absorb error codes for us.
339 : */
340 492000 : error = xchk_da_btree_block_check_sibling(ds, level, 0, back);
341 491989 : if (error)
342 0 : goto out;
343 491989 : error = xchk_da_btree_block_check_sibling(ds, level, 1, forw);
344 :
345 492001 : out:
346 492001 : memset(&ds->state->altpath, 0, sizeof(ds->state->altpath));
347 492001 : return error;
348 : }
349 :
350 : /* Load a dir/attribute block from a btree. */
351 : STATIC int
352 2366445 : xchk_da_btree_block(
353 : struct xchk_da_btree *ds,
354 : int level,
355 : xfs_dablk_t blkno)
356 : {
357 2366445 : struct xfs_da_state_blk *blk;
358 2366445 : struct xfs_da_intnode *node;
359 2366445 : struct xfs_da_node_entry *btree;
360 2366445 : struct xfs_da3_blkinfo *hdr3;
361 2366445 : struct xfs_da_args *dargs = &ds->dargs;
362 2366445 : struct xfs_inode *ip = ds->dargs.dp;
363 2366445 : xfs_failaddr_t fa;
364 2366445 : xfs_ino_t owner;
365 2366445 : int *pmaxrecs;
366 2366445 : struct xfs_da3_icnode_hdr nodehdr;
367 2366445 : int error = 0;
368 :
369 2366445 : blk = &ds->state->path.blk[level];
370 2362323 : ds->state->path.active = level + 1;
371 :
372 : /* Release old block. */
373 2362323 : if (blk->bp) {
374 435617 : xfs_trans_brelse(dargs->trans, blk->bp);
375 435624 : blk->bp = NULL;
376 : }
377 :
378 : /* Check the pointer. */
379 2362330 : blk->blkno = blkno;
380 2362330 : if (!xchk_da_btree_ptr_ok(ds, level, blkno))
381 0 : goto out_nobuf;
382 :
383 : /* Read the buffer. */
384 2360137 : 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 2369092 : if (!xchk_da_process_error(ds, level, &error))
388 0 : goto out_nobuf;
389 2363514 : if (blk->bp)
390 1999115 : 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 2371913 : if (ds->dargs.whichfork == XFS_DATA_FORK && level == 0 &&
398 417496 : blk->bp == NULL)
399 364394 : goto out_nobuf;
400 :
401 : /* It's /not/ ok for attr trees not to have a da btree. */
402 2007519 : if (blk->bp == NULL) {
403 0 : xchk_da_set_corrupt(ds, level);
404 0 : goto out_nobuf;
405 : }
406 :
407 2007519 : hdr3 = blk->bp->b_addr;
408 2007519 : blk->magic = be16_to_cpu(hdr3->hdr.magic);
409 2007519 : pmaxrecs = &ds->maxrecs[level];
410 :
411 : /* We only started zeroing the header on v5 filesystems. */
412 2007170 : if (xfs_has_crc(ds->sc->mp) && hdr3->hdr.pad)
413 0 : xchk_da_set_corrupt(ds, level);
414 :
415 : /* Check the owner. */
416 2007170 : if (xfs_has_crc(ip->i_mount)) {
417 2007152 : owner = be64_to_cpu(hdr3->owner);
418 2007152 : if (owner != ip->i_ino)
419 0 : xchk_da_set_corrupt(ds, level);
420 : }
421 :
422 : /* Check the siblings. */
423 2007170 : error = xchk_da_btree_block_check_siblings(ds, level, &hdr3->hdr);
424 2003550 : if (error)
425 0 : goto out;
426 :
427 : /* Interpret the buffer. */
428 2003550 : switch (blk->magic) {
429 1635849 : case XFS_ATTR_LEAF_MAGIC:
430 : case XFS_ATTR3_LEAF_MAGIC:
431 1635849 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
432 : XFS_BLFT_ATTR_LEAF_BUF);
433 1632333 : blk->magic = XFS_ATTR_LEAF_MAGIC;
434 1632333 : blk->hashval = xfs_attr_leaf_lasthash(blk->bp, pmaxrecs);
435 1635691 : if (ds->tree_level != 0)
436 0 : xchk_da_set_corrupt(ds, level);
437 : break;
438 290117 : case XFS_DIR2_LEAFN_MAGIC:
439 : case XFS_DIR3_LEAFN_MAGIC:
440 290117 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
441 : XFS_BLFT_DIR_LEAFN_BUF);
442 290118 : blk->magic = XFS_DIR2_LEAFN_MAGIC;
443 290118 : blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
444 290119 : if (ds->tree_level != 0)
445 0 : xchk_da_set_corrupt(ds, level);
446 : break;
447 20835 : case XFS_DIR2_LEAF1_MAGIC:
448 : case XFS_DIR3_LEAF1_MAGIC:
449 20835 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
450 : XFS_BLFT_DIR_LEAF1_BUF);
451 20835 : blk->magic = XFS_DIR2_LEAF1_MAGIC;
452 20835 : blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
453 20835 : if (ds->tree_level != 0)
454 0 : xchk_da_set_corrupt(ds, level);
455 : break;
456 56749 : case XFS_DA_NODE_MAGIC:
457 : case XFS_DA3_NODE_MAGIC:
458 56749 : xfs_trans_buf_set_type(dargs->trans, blk->bp,
459 : XFS_BLFT_DA_NODE_BUF);
460 56748 : blk->magic = XFS_DA_NODE_MAGIC;
461 56748 : node = blk->bp->b_addr;
462 56748 : xfs_da3_node_hdr_from_disk(ip->i_mount, &nodehdr, node);
463 56749 : btree = nodehdr.btree;
464 56749 : *pmaxrecs = nodehdr.count;
465 56749 : blk->hashval = be32_to_cpu(btree[*pmaxrecs - 1].hashval);
466 56749 : if (level == 0) {
467 56317 : if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
468 0 : xchk_da_set_corrupt(ds, level);
469 0 : goto out_freebp;
470 : }
471 56317 : ds->tree_level = nodehdr.level;
472 : } else {
473 432 : 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 2003394 : fa = xfs_da3_header_check(blk->bp, dargs->owner);
487 2001482 : 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 2001482 : if (level > 0) {
497 491994 : struct xfs_da_node_entry *key;
498 :
499 491994 : key = xchk_da_btree_node_entry(ds, level - 1);
500 491994 : 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 2001482 : out:
507 : return error;
508 0 : out_freebp:
509 0 : xfs_trans_brelse(dargs->trans, blk->bp);
510 0 : blk->bp = NULL;
511 364394 : out_nobuf:
512 364394 : blk->blkno = 0;
513 364394 : return error;
514 : }
515 :
516 : /* Visit all nodes and leaves of a da btree. */
517 : int
518 24550012 : xchk_da_btree(
519 : struct xfs_scrub *sc,
520 : int whichfork,
521 : xchk_da_btree_rec_fn scrub_fn,
522 : void *private)
523 : {
524 24550012 : struct xchk_da_btree *ds;
525 24550012 : struct xfs_mount *mp = sc->mp;
526 24550012 : struct xfs_da_state_blk *blks;
527 24550012 : struct xfs_da_node_entry *key;
528 24550012 : xfs_dablk_t blkno;
529 24550012 : int level;
530 24550012 : int error;
531 :
532 : /* Skip short format data structures; no btree to scan. */
533 24550012 : if (!xfs_ifork_has_extents(xfs_ifork_ptr(sc->ip, whichfork)))
534 : return 0;
535 :
536 : /* Set up initial da state. */
537 1870378 : ds = kzalloc(sizeof(struct xchk_da_btree), XCHK_GFP_FLAGS);
538 1874339 : if (!ds)
539 : return -ENOMEM;
540 1874339 : ds->dargs.dp = sc->ip;
541 1874339 : ds->dargs.whichfork = whichfork;
542 1874339 : ds->dargs.trans = sc->tp;
543 1874339 : ds->dargs.op_flags = XFS_DA_OP_OKNOENT;
544 1874339 : ds->dargs.owner = sc->ip->i_ino;
545 1874339 : ds->state = xfs_da_state_alloc(&ds->dargs);
546 1875165 : ds->sc = sc;
547 1875165 : ds->private = private;
548 1875165 : if (whichfork == XFS_ATTR_FORK) {
549 1457597 : ds->dargs.geo = mp->m_attr_geo;
550 1457597 : ds->lowest = 0;
551 1457597 : ds->highest = 0;
552 : } else {
553 417568 : ds->dargs.geo = mp->m_dir_geo;
554 417568 : ds->lowest = ds->dargs.geo->leafblk;
555 417568 : ds->highest = ds->dargs.geo->freeblk;
556 : }
557 1875165 : blkno = ds->lowest;
558 1875165 : level = 0;
559 :
560 : /* Find the root of the da tree, if present. */
561 1875165 : blks = ds->state->path.blk;
562 1875165 : error = xchk_da_btree_block(ds, level, blkno);
563 1875074 : 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 1875074 : if (blks[level].bp == NULL)
571 364395 : goto out_state;
572 :
573 1510679 : blks[level].index = 0;
574 129285442 : while (level >= 0 && level < XFS_DA_NODE_MAXDEPTH) {
575 : /* Handle leaf block. */
576 127768502 : if (blks[level].magic != XFS_DA_NODE_MAGIC) {
577 : /* End of leaf, pop back towards the root. */
578 127219752 : if (blks[level].index >= ds->maxrecs[level]) {
579 1952353 : if (level > 0)
580 491568 : blks[level - 1].index++;
581 1952353 : ds->tree_level++;
582 1952353 : level--;
583 1952353 : continue;
584 : }
585 :
586 : /* Dispatch record scrubbing. */
587 125273300 : error = scrub_fn(ds, level);
588 125269075 : if (error)
589 : break;
590 125269075 : if (xchk_should_terminate(sc, &error) ||
591 125273661 : (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
592 : break;
593 :
594 125273661 : blks[level].index++;
595 125273661 : continue;
596 : }
597 :
598 :
599 : /* End of node, pop back towards the root. */
600 548750 : if (blks[level].index >= ds->maxrecs[level]) {
601 56755 : if (level > 0)
602 432 : blks[level - 1].index++;
603 56755 : ds->tree_level++;
604 56755 : level--;
605 56755 : continue;
606 : }
607 :
608 : /* Hashes in order for scrub? */
609 491991 : key = xchk_da_btree_node_entry(ds, level);
610 491985 : error = xchk_da_btree_hash(ds, level, &key->hashval);
611 491986 : if (error)
612 0 : goto out;
613 :
614 : /* Drill another level deeper. */
615 491986 : blkno = be32_to_cpu(key->before);
616 491986 : level++;
617 491986 : if (level >= XFS_DA_NODE_MAXDEPTH) {
618 : /* Too deep! */
619 0 : xchk_da_set_corrupt(ds, level - 1);
620 0 : break;
621 : }
622 491986 : ds->tree_level--;
623 491986 : error = xchk_da_btree_block(ds, level, blkno);
624 491994 : if (error)
625 0 : goto out;
626 491994 : if (blks[level].bp == NULL)
627 0 : goto out;
628 :
629 491994 : blks[level].index = 0;
630 : }
631 :
632 1516941 : out:
633 : /* Release all the buffers we're tracking. */
634 9097033 : for (level = 0; level < XFS_DA_NODE_MAXDEPTH; level++) {
635 7580835 : if (blks[level].bp == NULL)
636 6007669 : continue;
637 1573166 : xfs_trans_brelse(sc->tp, blks[level].bp);
638 1572423 : blks[level].bp = NULL;
639 : }
640 :
641 1516198 : out_state:
642 1880593 : xfs_da_state_free(ds->state);
643 1879950 : kfree(ds);
644 1880203 : return error;
645 : }
|