LCOV - code coverage report
Current view: top level - fs/xfs/scrub - dabtree.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwa @ Mon Jul 31 20:08:17 PDT 2023 Lines: 220 299 73.6 %
Date: 2023-07-31 20:08:17 Functions: 9 12 75.0 %

          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     2553841 : xchk_da_process_error(
      31             :         struct xchk_da_btree    *ds,
      32             :         int                     level,
      33             :         int                     *error)
      34             : {
      35     2553841 :         struct xfs_scrub        *sc = ds->sc;
      36             : 
      37     2553841 :         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 :                 *error = 0;
      51           0 :                 fallthrough;
      52           0 :         default:
      53           0 :                 trace_xchk_file_op_error(sc, ds->dargs.whichfork,
      54           0 :                                 xfs_dir2_da_to_db(ds->dargs.geo,
      55           0 :                                         ds->state->path.blk[level].blkno),
      56             :                                 *error, __return_address);
      57           0 :                 break;
      58             :         }
      59             :         return false;
      60             : }
      61             : 
      62             : /*
      63             :  * Check for da btree corruption.  See the section about handling
      64             :  * operational errors in common.c.
      65             :  */
      66             : void
      67           0 : xchk_da_set_corrupt(
      68             :         struct xchk_da_btree    *ds,
      69             :         int                     level)
      70             : {
      71           0 :         struct xfs_scrub        *sc = ds->sc;
      72             : 
      73           0 :         sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
      74             : 
      75           0 :         trace_xchk_fblock_error(sc, ds->dargs.whichfork,
      76           0 :                         xfs_dir2_da_to_db(ds->dargs.geo,
      77           0 :                                 ds->state->path.blk[level].blkno),
      78             :                         __return_address);
      79           0 : }
      80             : 
      81             : static struct xfs_da_node_entry *
      82   135849667 : xchk_da_btree_node_entry(
      83             :         struct xchk_da_btree            *ds,
      84             :         int                             level)
      85             : {
      86   135849667 :         struct xfs_da_state_blk         *blk = &ds->state->path.blk[level];
      87   135851142 :         struct xfs_da3_icnode_hdr       hdr;
      88             : 
      89   135851142 :         ASSERT(blk->magic == XFS_DA_NODE_MAGIC);
      90             : 
      91   135851142 :         xfs_da3_node_hdr_from_disk(ds->sc->mp, &hdr, blk->bp->b_addr);
      92   135850898 :         return hdr.btree + blk->index;
      93             : }
      94             : 
      95             : /* Scrub a da btree hash (key). */
      96             : int
      97   150910694 : xchk_da_btree_hash(
      98             :         struct xchk_da_btree            *ds,
      99             :         int                             level,
     100             :         __be32                          *hashp)
     101             : {
     102   150910694 :         struct xfs_da_node_entry        *entry;
     103   150910694 :         xfs_dahash_t                    hash;
     104   150910694 :         xfs_dahash_t                    parent_hash;
     105             : 
     106             :         /* Is this hash in order? */
     107   150910694 :         hash = be32_to_cpu(*hashp);
     108   150910694 :         if (hash < ds->hashes[level])
     109           0 :                 xchk_da_set_corrupt(ds, level);
     110   150911582 :         ds->hashes[level] = hash;
     111             : 
     112   150911699 :         if (level == 0)
     113             :                 return 0;
     114             : 
     115             :         /* Is this hash no larger than the parent hash? */
     116   134909503 :         entry = xchk_da_btree_node_entry(ds, level - 1);
     117   134910206 :         parent_hash = be32_to_cpu(entry->hashval);
     118   134910206 :         if (parent_hash < hash)
     119           0 :                 xchk_da_set_corrupt(ds, level);
     120             : 
     121             :         return 0;
     122             : }
     123             : 
     124             : /*
     125             :  * Check a da btree pointer.  Returns true if it's ok to use this
     126             :  * pointer.
     127             :  */
     128             : STATIC bool
     129     1719370 : xchk_da_btree_ptr_ok(
     130             :         struct xchk_da_btree    *ds,
     131             :         int                     level,
     132             :         xfs_dablk_t             blkno)
     133             : {
     134     1719370 :         if (blkno < ds->lowest || (ds->highest != 0 && blkno >= ds->highest)) {
     135           0 :                 xchk_da_set_corrupt(ds, level);
     136           0 :                 return false;
     137             :         }
     138             : 
     139             :         return true;
     140             : }
     141             : 
     142             : /*
     143             :  * The da btree scrubber can handle leaf1 blocks as a degenerate
     144             :  * form of leafn blocks.  Since the regular da code doesn't handle
     145             :  * leaf1, we must multiplex the verifiers.
     146             :  */
     147             : static void
     148       35420 : xchk_da_btree_read_verify(
     149             :         struct xfs_buf          *bp)
     150             : {
     151       35420 :         struct xfs_da_blkinfo   *info = bp->b_addr;
     152             : 
     153       35420 :         switch (be16_to_cpu(info->magic)) {
     154          52 :         case XFS_DIR2_LEAF1_MAGIC:
     155             :         case XFS_DIR3_LEAF1_MAGIC:
     156          52 :                 bp->b_ops = &xfs_dir3_leaf1_buf_ops;
     157          52 :                 bp->b_ops->verify_read(bp);
     158          52 :                 return;
     159       35368 :         default:
     160             :                 /*
     161             :                  * xfs_da3_node_buf_ops already know how to handle
     162             :                  * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks.
     163             :                  */
     164       35368 :                 bp->b_ops = &xfs_da3_node_buf_ops;
     165       35368 :                 bp->b_ops->verify_read(bp);
     166       35368 :                 return;
     167             :         }
     168             : }
     169             : static void
     170           0 : xchk_da_btree_write_verify(
     171             :         struct xfs_buf          *bp)
     172             : {
     173           0 :         struct xfs_da_blkinfo   *info = bp->b_addr;
     174             : 
     175           0 :         switch (be16_to_cpu(info->magic)) {
     176           0 :         case XFS_DIR2_LEAF1_MAGIC:
     177             :         case XFS_DIR3_LEAF1_MAGIC:
     178           0 :                 bp->b_ops = &xfs_dir3_leaf1_buf_ops;
     179           0 :                 bp->b_ops->verify_write(bp);
     180           0 :                 return;
     181           0 :         default:
     182             :                 /*
     183             :                  * xfs_da3_node_buf_ops already know how to handle
     184             :                  * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks.
     185             :                  */
     186           0 :                 bp->b_ops = &xfs_da3_node_buf_ops;
     187           0 :                 bp->b_ops->verify_write(bp);
     188           0 :                 return;
     189             :         }
     190             : }
     191             : static void *
     192           0 : xchk_da_btree_verify(
     193             :         struct xfs_buf          *bp)
     194             : {
     195           0 :         struct xfs_da_blkinfo   *info = bp->b_addr;
     196             : 
     197           0 :         switch (be16_to_cpu(info->magic)) {
     198           0 :         case XFS_DIR2_LEAF1_MAGIC:
     199             :         case XFS_DIR3_LEAF1_MAGIC:
     200           0 :                 bp->b_ops = &xfs_dir3_leaf1_buf_ops;
     201           0 :                 return bp->b_ops->verify_struct(bp);
     202           0 :         default:
     203           0 :                 bp->b_ops = &xfs_da3_node_buf_ops;
     204           0 :                 return bp->b_ops->verify_struct(bp);
     205             :         }
     206             : }
     207             : 
     208             : static const struct xfs_buf_ops xchk_da_btree_buf_ops = {
     209             :         .name = "xchk_da_btree",
     210             :         .verify_read = xchk_da_btree_read_verify,
     211             :         .verify_write = xchk_da_btree_write_verify,
     212             :         .verify_struct = xchk_da_btree_verify,
     213             : };
     214             : 
     215             : /* Check a block's sibling. */
     216             : STATIC int
     217      941145 : xchk_da_btree_block_check_sibling(
     218             :         struct xchk_da_btree    *ds,
     219             :         int                     level,
     220             :         int                     direction,
     221             :         xfs_dablk_t             sibling)
     222             : {
     223      941145 :         struct xfs_da_state_path *path = &ds->state->path;
     224      941145 :         struct xfs_da_state_path *altpath = &ds->state->altpath;
     225      941145 :         int                     retval;
     226      941145 :         int                     plevel;
     227      941145 :         int                     error;
     228             : 
     229     1882290 :         memcpy(altpath, path, sizeof(ds->state->altpath));
     230             : 
     231             :         /*
     232             :          * If the pointer is null, we shouldn't be able to move the upper
     233             :          * level pointer anywhere.
     234             :          */
     235      941145 :         if (sibling == 0) {
     236      106684 :                 error = xfs_da3_path_shift(ds->state, altpath, direction,
     237             :                                 false, &retval);
     238      106684 :                 if (error == 0 && retval == 0)
     239           0 :                         xchk_da_set_corrupt(ds, level);
     240      106684 :                 error = 0;
     241      106684 :                 goto out;
     242             :         }
     243             : 
     244             :         /* Move the alternate cursor one block in the direction given. */
     245      834461 :         error = xfs_da3_path_shift(ds->state, altpath, direction, false,
     246             :                         &retval);
     247      834462 :         if (!xchk_da_process_error(ds, level, &error))
     248           0 :                 goto out;
     249      834462 :         if (retval) {
     250           0 :                 xchk_da_set_corrupt(ds, level);
     251           0 :                 goto out;
     252             :         }
     253      834462 :         if (altpath->blk[level].bp)
     254      834462 :                 xchk_buffer_recheck(ds->sc, altpath->blk[level].bp);
     255             : 
     256             :         /* Compare upper level pointer to sibling pointer. */
     257      834462 :         if (altpath->blk[level].blkno != sibling)
     258           0 :                 xchk_da_set_corrupt(ds, level);
     259             : 
     260      834461 : out:
     261             :         /* Free all buffers in the altpath that aren't referenced from path. */
     262     2848647 :         for (plevel = 0; plevel < altpath->active; plevel++) {
     263     1907501 :                 if (altpath->blk[plevel].bp == NULL ||
     264     1907500 :                     (plevel < path->active &&
     265     1907500 :                      altpath->blk[plevel].bp == path->blk[plevel].bp))
     266     1072976 :                         continue;
     267             : 
     268      834525 :                 xfs_trans_brelse(ds->dargs.trans, altpath->blk[plevel].bp);
     269      834526 :                 altpath->blk[plevel].bp = NULL;
     270             :         }
     271             : 
     272      941146 :         return error;
     273             : }
     274             : 
     275             : /* Check a block's sibling pointers. */
     276             : STATIC int
     277     1585001 : xchk_da_btree_block_check_siblings(
     278             :         struct xchk_da_btree    *ds,
     279             :         int                     level,
     280             :         struct xfs_da_blkinfo   *hdr)
     281             : {
     282     1585001 :         xfs_dablk_t             forw;
     283     1585001 :         xfs_dablk_t             back;
     284     1585001 :         int                     error = 0;
     285             : 
     286     1585001 :         forw = be32_to_cpu(hdr->forw);
     287     1585001 :         back = be32_to_cpu(hdr->back);
     288             : 
     289             :         /* Top level blocks should not have sibling pointers. */
     290     1585001 :         if (level == 0) {
     291     1114428 :                 if (forw != 0 || back != 0)
     292           0 :                         xchk_da_set_corrupt(ds, level);
     293     1114428 :                 return 0;
     294             :         }
     295             : 
     296             :         /*
     297             :          * Check back (left) and forw (right) pointers.  These functions
     298             :          * absorb error codes for us.
     299             :          */
     300      470573 :         error = xchk_da_btree_block_check_sibling(ds, level, 0, back);
     301      470573 :         if (error)
     302           0 :                 goto out;
     303      470573 :         error = xchk_da_btree_block_check_sibling(ds, level, 1, forw);
     304             : 
     305      470573 : out:
     306      470573 :         memset(&ds->state->altpath, 0, sizeof(ds->state->altpath));
     307      470573 :         return error;
     308             : }
     309             : 
     310             : /* Load a dir/attribute block from a btree. */
     311             : STATIC int
     312     1719383 : xchk_da_btree_block(
     313             :         struct xchk_da_btree            *ds,
     314             :         int                             level,
     315             :         xfs_dablk_t                     blkno)
     316             : {
     317     1719383 :         struct xfs_da_state_blk         *blk;
     318     1719383 :         struct xfs_da_intnode           *node;
     319     1719383 :         struct xfs_da_node_entry        *btree;
     320     1719383 :         struct xfs_da3_blkinfo          *hdr3;
     321     1719383 :         struct xfs_da_args              *dargs = &ds->dargs;
     322     1719383 :         struct xfs_inode                *ip = ds->dargs.dp;
     323     1719383 :         xfs_ino_t                       owner;
     324     1719383 :         int                             *pmaxrecs;
     325     1719383 :         struct xfs_da3_icnode_hdr       nodehdr;
     326     1719383 :         int                             error = 0;
     327             : 
     328     1719383 :         blk = &ds->state->path.blk[level];
     329     1719396 :         ds->state->path.active = level + 1;
     330             : 
     331             :         /* Release old block. */
     332     1719396 :         if (blk->bp) {
     333      417231 :                 xfs_trans_brelse(dargs->trans, blk->bp);
     334      417231 :                 blk->bp = NULL;
     335             :         }
     336             : 
     337             :         /* Check the pointer. */
     338     1719396 :         blk->blkno = blkno;
     339     1719396 :         if (!xchk_da_btree_ptr_ok(ds, level, blkno))
     340           0 :                 goto out_nobuf;
     341             : 
     342             :         /* Read the buffer. */
     343     1719374 :         error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno,
     344             :                         XFS_DABUF_MAP_HOLE_OK, &blk->bp, dargs->whichfork,
     345             :                         &xchk_da_btree_buf_ops);
     346     1719388 :         if (!xchk_da_process_error(ds, level, &error))
     347           0 :                 goto out_nobuf;
     348     1719391 :         if (blk->bp)
     349     1585012 :                 xchk_buffer_recheck(ds->sc, blk->bp);
     350             : 
     351             :         /*
     352             :          * We didn't find a dir btree root block, which means that
     353             :          * there's no LEAF1/LEAFN tree (at least not where it's supposed
     354             :          * to be), so jump out now.
     355             :          */
     356     1719375 :         if (ds->dargs.whichfork == XFS_DATA_FORK && level == 0 &&
     357      186144 :                         blk->bp == NULL)
     358      134379 :                 goto out_nobuf;
     359             : 
     360             :         /* It's /not/ ok for attr trees not to have a da btree. */
     361     1584996 :         if (blk->bp == NULL) {
     362           0 :                 xchk_da_set_corrupt(ds, level);
     363           0 :                 goto out_nobuf;
     364             :         }
     365             : 
     366     1584996 :         hdr3 = blk->bp->b_addr;
     367     1584996 :         blk->magic = be16_to_cpu(hdr3->hdr.magic);
     368     1584996 :         pmaxrecs = &ds->maxrecs[level];
     369             : 
     370             :         /* We only started zeroing the header on v5 filesystems. */
     371     1584997 :         if (xfs_has_crc(ds->sc->mp) && hdr3->hdr.pad)
     372           0 :                 xchk_da_set_corrupt(ds, level);
     373             : 
     374             :         /* Check the owner. */
     375     1584997 :         if (xfs_has_crc(ip->i_mount)) {
     376     1584998 :                 owner = be64_to_cpu(hdr3->owner);
     377     1584998 :                 if (owner != ip->i_ino)
     378           0 :                         xchk_da_set_corrupt(ds, level);
     379             :         }
     380             : 
     381             :         /* Check the siblings. */
     382     1584997 :         error = xchk_da_btree_block_check_siblings(ds, level, &hdr3->hdr);
     383     1585004 :         if (error)
     384           0 :                 goto out;
     385             : 
     386             :         /* Interpret the buffer. */
     387     1585004 :         switch (blk->magic) {
     388     1089045 :         case XFS_ATTR_LEAF_MAGIC:
     389             :         case XFS_ATTR3_LEAF_MAGIC:
     390     1089045 :                 xfs_trans_buf_set_type(dargs->trans, blk->bp,
     391             :                                 XFS_BLFT_ATTR_LEAF_BUF);
     392     1089044 :                 blk->magic = XFS_ATTR_LEAF_MAGIC;
     393     1089044 :                 blk->hashval = xfs_attr_leaf_lasthash(blk->bp, pmaxrecs);
     394     1089048 :                 if (ds->tree_level != 0)
     395           0 :                         xchk_da_set_corrupt(ds, level);
     396             :                 break;
     397      431269 :         case XFS_DIR2_LEAFN_MAGIC:
     398             :         case XFS_DIR3_LEAFN_MAGIC:
     399      431269 :                 xfs_trans_buf_set_type(dargs->trans, blk->bp,
     400             :                                 XFS_BLFT_DIR_LEAFN_BUF);
     401      431269 :                 blk->magic = XFS_DIR2_LEAFN_MAGIC;
     402      431269 :                 blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
     403      431269 :                 if (ds->tree_level != 0)
     404           0 :                         xchk_da_set_corrupt(ds, level);
     405             :                 break;
     406       11316 :         case XFS_DIR2_LEAF1_MAGIC:
     407             :         case XFS_DIR3_LEAF1_MAGIC:
     408       11316 :                 xfs_trans_buf_set_type(dargs->trans, blk->bp,
     409             :                                 XFS_BLFT_DIR_LEAF1_BUF);
     410       11316 :                 blk->magic = XFS_DIR2_LEAF1_MAGIC;
     411       11316 :                 blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
     412       11316 :                 if (ds->tree_level != 0)
     413           0 :                         xchk_da_set_corrupt(ds, level);
     414             :                 break;
     415       53374 :         case XFS_DA_NODE_MAGIC:
     416             :         case XFS_DA3_NODE_MAGIC:
     417       53374 :                 xfs_trans_buf_set_type(dargs->trans, blk->bp,
     418             :                                 XFS_BLFT_DA_NODE_BUF);
     419       53374 :                 blk->magic = XFS_DA_NODE_MAGIC;
     420       53374 :                 node = blk->bp->b_addr;
     421       53374 :                 xfs_da3_node_hdr_from_disk(ip->i_mount, &nodehdr, node);
     422       53374 :                 btree = nodehdr.btree;
     423       53374 :                 *pmaxrecs = nodehdr.count;
     424       53374 :                 blk->hashval = be32_to_cpu(btree[*pmaxrecs - 1].hashval);
     425       53374 :                 if (level == 0) {
     426       53337 :                         if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
     427           0 :                                 xchk_da_set_corrupt(ds, level);
     428           0 :                                 goto out_freebp;
     429             :                         }
     430       53337 :                         ds->tree_level = nodehdr.level;
     431             :                 } else {
     432          37 :                         if (ds->tree_level != nodehdr.level) {
     433           0 :                                 xchk_da_set_corrupt(ds, level);
     434           0 :                                 goto out_freebp;
     435             :                         }
     436             :                 }
     437             : 
     438             :                 /* XXX: Check hdr3.pad32 once we know how to fix it. */
     439             :                 break;
     440           0 :         default:
     441           0 :                 xchk_da_set_corrupt(ds, level);
     442           0 :                 goto out_freebp;
     443             :         }
     444             : 
     445             :         /*
     446             :          * If we've been handed a block that is below the dabtree root, does
     447             :          * its hashval match what the parent block expected to see?
     448             :          */
     449     1585007 :         if (level > 0) {
     450      470573 :                 struct xfs_da_node_entry        *key;
     451             : 
     452      470573 :                 key = xchk_da_btree_node_entry(ds, level - 1);
     453      941146 :                 if (be32_to_cpu(key->hashval) != blk->hashval) {
     454           0 :                         xchk_da_set_corrupt(ds, level);
     455           0 :                         goto out_freebp;
     456             :                 }
     457             :         }
     458             : 
     459     1585007 : out:
     460             :         return error;
     461           0 : out_freebp:
     462           0 :         xfs_trans_brelse(dargs->trans, blk->bp);
     463           0 :         blk->bp = NULL;
     464      134379 : out_nobuf:
     465      134379 :         blk->blkno = 0;
     466      134379 :         return error;
     467             : }
     468             : 
     469             : /* Visit all nodes and leaves of a da btree. */
     470             : int
     471    80767740 : xchk_da_btree(
     472             :         struct xfs_scrub                *sc,
     473             :         int                             whichfork,
     474             :         xchk_da_btree_rec_fn            scrub_fn,
     475             :         void                            *private)
     476             : {
     477    80767740 :         struct xchk_da_btree            *ds;
     478    80767740 :         struct xfs_mount                *mp = sc->mp;
     479    80767740 :         struct xfs_da_state_blk         *blks;
     480    80767740 :         struct xfs_da_node_entry        *key;
     481    80767740 :         xfs_dablk_t                     blkno;
     482    80767740 :         int                             level;
     483    80767740 :         int                             error;
     484             : 
     485             :         /* Skip short format data structures; no btree to scan. */
     486    80767740 :         if (!xfs_ifork_has_extents(xfs_ifork_ptr(sc->ip, whichfork)))
     487             :                 return 0;
     488             : 
     489             :         /* Set up initial da state. */
     490     1248822 :         ds = kzalloc(sizeof(struct xchk_da_btree), XCHK_GFP_FLAGS);
     491     1248824 :         if (!ds)
     492             :                 return -ENOMEM;
     493     1248824 :         ds->dargs.dp = sc->ip;
     494     1248824 :         ds->dargs.whichfork = whichfork;
     495     1248824 :         ds->dargs.trans = sc->tp;
     496     1248824 :         ds->dargs.op_flags = XFS_DA_OP_OKNOENT;
     497     1248824 :         ds->state = xfs_da_state_alloc(&ds->dargs);
     498     1248826 :         ds->sc = sc;
     499     1248826 :         ds->private = private;
     500     1248826 :         if (whichfork == XFS_ATTR_FORK) {
     501     1062682 :                 ds->dargs.geo = mp->m_attr_geo;
     502     1062682 :                 ds->lowest = 0;
     503     1062682 :                 ds->highest = 0;
     504             :         } else {
     505      186144 :                 ds->dargs.geo = mp->m_dir_geo;
     506      186144 :                 ds->lowest = ds->dargs.geo->leafblk;
     507      186144 :                 ds->highest = ds->dargs.geo->freeblk;
     508             :         }
     509     1248826 :         blkno = ds->lowest;
     510     1248826 :         level = 0;
     511             : 
     512             :         /* Find the root of the da tree, if present. */
     513     1248826 :         blks = ds->state->path.blk;
     514     1248826 :         error = xchk_da_btree_block(ds, level, blkno);
     515     1248822 :         if (error)
     516           0 :                 goto out_state;
     517             :         /*
     518             :          * We didn't find a block at ds->lowest, which means that there's
     519             :          * no LEAF1/LEAFN tree (at least not where it's supposed to be),
     520             :          * so jump out now.
     521             :          */
     522     1248822 :         if (blks[level].bp == NULL)
     523      134379 :                 goto out_state;
     524             : 
     525     1114443 :         blks[level].index = 0;
     526   153609675 :         while (level >= 0 && level < XFS_DA_NODE_MAXDEPTH) {
     527             :                 /* Handle leaf block. */
     528   152495254 :                 if (blks[level].magic != XFS_DA_NODE_MAGIC) {
     529             :                         /* End of leaf, pop back towards the root. */
     530   151971309 :                         if (blks[level].index >= ds->maxrecs[level]) {
     531     1531610 :                                 if (level > 0)
     532      470534 :                                         blks[level - 1].index++;
     533     1531610 :                                 ds->tree_level++;
     534     1531610 :                                 level--;
     535     1531610 :                                 continue;
     536             :                         }
     537             : 
     538             :                         /* Dispatch record scrubbing. */
     539   150437581 :                         error = scrub_fn(ds, level);
     540   150433951 :                         if (error)
     541             :                                 break;
     542   150433951 :                         if (xchk_should_terminate(sc, &error) ||
     543   150439675 :                             (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
     544             :                                 break;
     545             : 
     546   150439675 :                         blks[level].index++;
     547   150439675 :                         continue;
     548             :                 }
     549             : 
     550             : 
     551             :                 /* End of node, pop back towards the root. */
     552      523945 :                 if (blks[level].index >= ds->maxrecs[level]) {
     553       53374 :                         if (level > 0)
     554          37 :                                 blks[level - 1].index++;
     555       53374 :                         ds->tree_level++;
     556       53374 :                         level--;
     557       53374 :                         continue;
     558             :                 }
     559             : 
     560             :                 /* Hashes in order for scrub? */
     561      470573 :                 key = xchk_da_btree_node_entry(ds, level);
     562      470573 :                 error = xchk_da_btree_hash(ds, level, &key->hashval);
     563      470573 :                 if (error)
     564           0 :                         goto out;
     565             : 
     566             :                 /* Drill another level deeper. */
     567      470573 :                 blkno = be32_to_cpu(key->before);
     568      470573 :                 level++;
     569      470573 :                 if (level >= XFS_DA_NODE_MAXDEPTH) {
     570             :                         /* Too deep! */
     571           0 :                         xchk_da_set_corrupt(ds, level - 1);
     572           0 :                         break;
     573             :                 }
     574      470573 :                 ds->tree_level--;
     575      470573 :                 error = xchk_da_btree_block(ds, level, blkno);
     576      470573 :                 if (error)
     577           0 :                         goto out;
     578      470573 :                 if (blks[level].bp == NULL)
     579           0 :                         goto out;
     580             : 
     581      470573 :                 blks[level].index = 0;
     582             :         }
     583             : 
     584     1114421 : out:
     585             :         /* Release all the buffers we're tracking. */
     586     6686648 :         for (level = 0; level < XFS_DA_NODE_MAXDEPTH; level++) {
     587     5572201 :                 if (blks[level].bp == NULL)
     588     4404442 :                         continue;
     589     1167759 :                 xfs_trans_brelse(sc->tp, blks[level].bp);
     590     1167785 :                 blks[level].bp = NULL;
     591             :         }
     592             : 
     593     1114447 : out_state:
     594     1248826 :         xfs_da_state_free(ds->state);
     595     1248824 :         kfree(ds);
     596     1248826 :         return error;
     597             : }

Generated by: LCOV version 1.14