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