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-djwx @ Mon Jul 31 20:08:22 PDT 2023 Lines: 220 299 73.6 %
Date: 2023-07-31 20:08:22 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     3102334 : xchk_da_process_error(
      31             :         struct xchk_da_btree    *ds,
      32             :         int                     level,
      33             :         int                     *error)
      34             : {
      35     3102334 :         struct xfs_scrub        *sc = ds->sc;
      36             : 
      37     3102334 :         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   131485763 : xchk_da_btree_node_entry(
      83             :         struct xchk_da_btree            *ds,
      84             :         int                             level)
      85             : {
      86   131485763 :         struct xfs_da_state_blk         *blk = &ds->state->path.blk[level];
      87   131302334 :         struct xfs_da3_icnode_hdr       hdr;
      88             : 
      89   131302334 :         ASSERT(blk->magic == XFS_DA_NODE_MAGIC);
      90             : 
      91   131302334 :         xfs_da3_node_hdr_from_disk(ds->sc->mp, &hdr, blk->bp->b_addr);
      92   131295804 :         return hdr.btree + blk->index;
      93             : }
      94             : 
      95             : /* Scrub a da btree hash (key). */
      96             : int
      97   152671218 : xchk_da_btree_hash(
      98             :         struct xchk_da_btree            *ds,
      99             :         int                             level,
     100             :         __be32                          *hashp)
     101             : {
     102   152671218 :         struct xfs_da_node_entry        *entry;
     103   152671218 :         xfs_dahash_t                    hash;
     104   152671218 :         xfs_dahash_t                    parent_hash;
     105             : 
     106             :         /* Is this hash in order? */
     107   152671218 :         hash = be32_to_cpu(*hashp);
     108   152671218 :         if (hash < ds->hashes[level])
     109           0 :                 xchk_da_set_corrupt(ds, level);
     110   152550609 :         ds->hashes[level] = hash;
     111             : 
     112   152543229 :         if (level == 0)
     113             :                 return 0;
     114             : 
     115             :         /* Is this hash no larger than the parent hash? */
     116   130189402 :         entry = xchk_da_btree_node_entry(ds, level - 1);
     117   130268112 :         parent_hash = be32_to_cpu(entry->hashval);
     118   130268112 :         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     2190505 : xchk_da_btree_ptr_ok(
     130             :         struct xchk_da_btree    *ds,
     131             :         int                     level,
     132             :         xfs_dablk_t             blkno)
     133             : {
     134     2190505 :         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       38805 : xchk_da_btree_read_verify(
     149             :         struct xfs_buf          *bp)
     150             : {
     151       38805 :         struct xfs_da_blkinfo   *info = bp->b_addr;
     152             : 
     153       38805 :         switch (be16_to_cpu(info->magic)) {
     154         526 :         case XFS_DIR2_LEAF1_MAGIC:
     155             :         case XFS_DIR3_LEAF1_MAGIC:
     156         526 :                 bp->b_ops = &xfs_dir3_leaf1_buf_ops;
     157         526 :                 bp->b_ops->verify_read(bp);
     158         526 :                 return;
     159       38279 :         default:
     160             :                 /*
     161             :                  * xfs_da3_node_buf_ops already know how to handle
     162             :                  * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks.
     163             :                  */
     164       38279 :                 bp->b_ops = &xfs_da3_node_buf_ops;
     165       38279 :                 bp->b_ops->verify_read(bp);
     166       38279 :                 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     1041200 : 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     1041200 :         struct xfs_da_state_path *path = &ds->state->path;
     224     1041200 :         struct xfs_da_state_path *altpath = &ds->state->altpath;
     225     1041200 :         int                     retval;
     226     1041200 :         int                     plevel;
     227     1041200 :         int                     error;
     228             : 
     229     2082400 :         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     1041200 :         if (sibling == 0) {
     236      131695 :                 error = xfs_da3_path_shift(ds->state, altpath, direction,
     237             :                                 false, &retval);
     238      131691 :                 if (error == 0 && retval == 0)
     239           0 :                         xchk_da_set_corrupt(ds, level);
     240      131691 :                 error = 0;
     241      131691 :                 goto out;
     242             :         }
     243             : 
     244             :         /* Move the alternate cursor one block in the direction given. */
     245      909505 :         error = xfs_da3_path_shift(ds->state, altpath, direction, false,
     246             :                         &retval);
     247      909486 :         if (!xchk_da_process_error(ds, level, &error))
     248           0 :                 goto out;
     249      909483 :         if (retval) {
     250           0 :                 xchk_da_set_corrupt(ds, level);
     251           0 :                 goto out;
     252             :         }
     253      909483 :         if (altpath->blk[level].bp)
     254      909484 :                 xchk_buffer_recheck(ds->sc, altpath->blk[level].bp);
     255             : 
     256             :         /* Compare upper level pointer to sibling pointer. */
     257      909505 :         if (altpath->blk[level].blkno != sibling)
     258           0 :                 xchk_da_set_corrupt(ds, level);
     259             : 
     260      909505 : out:
     261             :         /* Free all buffers in the altpath that aren't referenced from path. */
     262     3343724 :         for (plevel = 0; plevel < altpath->active; plevel++) {
     263     2302521 :                 if (altpath->blk[plevel].bp == NULL ||
     264     2302511 :                     (plevel < path->active &&
     265     2302511 :                      altpath->blk[plevel].bp == path->blk[plevel].bp))
     266     1392289 :                         continue;
     267             : 
     268      910221 :                 xfs_trans_brelse(ds->dargs.trans, altpath->blk[plevel].bp);
     269      910239 :                 altpath->blk[plevel].bp = NULL;
     270             :         }
     271             : 
     272     1041203 :         return error;
     273             : }
     274             : 
     275             : /* Check a block's sibling pointers. */
     276             : STATIC int
     277     2002412 : xchk_da_btree_block_check_siblings(
     278             :         struct xchk_da_btree    *ds,
     279             :         int                     level,
     280             :         struct xfs_da_blkinfo   *hdr)
     281             : {
     282     2002412 :         xfs_dablk_t             forw;
     283     2002412 :         xfs_dablk_t             back;
     284     2002412 :         int                     error = 0;
     285             : 
     286     2002412 :         forw = be32_to_cpu(hdr->forw);
     287     2002412 :         back = be32_to_cpu(hdr->back);
     288             : 
     289             :         /* Top level blocks should not have sibling pointers. */
     290     2002412 :         if (level == 0) {
     291     1481810 :                 if (forw != 0 || back != 0)
     292           0 :                         xchk_da_set_corrupt(ds, level);
     293     1481810 :                 return 0;
     294             :         }
     295             : 
     296             :         /*
     297             :          * Check back (left) and forw (right) pointers.  These functions
     298             :          * absorb error codes for us.
     299             :          */
     300      520602 :         error = xchk_da_btree_block_check_sibling(ds, level, 0, back);
     301      520601 :         if (error)
     302           0 :                 goto out;
     303      520601 :         error = xchk_da_btree_block_check_sibling(ds, level, 1, forw);
     304             : 
     305      520605 : out:
     306      520605 :         memset(&ds->state->altpath, 0, sizeof(ds->state->altpath));
     307      520605 :         return error;
     308             : }
     309             : 
     310             : /* Load a dir/attribute block from a btree. */
     311             : STATIC int
     312     2194102 : xchk_da_btree_block(
     313             :         struct xchk_da_btree            *ds,
     314             :         int                             level,
     315             :         xfs_dablk_t                     blkno)
     316             : {
     317     2194102 :         struct xfs_da_state_blk         *blk;
     318     2194102 :         struct xfs_da_intnode           *node;
     319     2194102 :         struct xfs_da_node_entry        *btree;
     320     2194102 :         struct xfs_da3_blkinfo          *hdr3;
     321     2194102 :         struct xfs_da_args              *dargs = &ds->dargs;
     322     2194102 :         struct xfs_inode                *ip = ds->dargs.dp;
     323     2194102 :         xfs_ino_t                       owner;
     324     2194102 :         int                             *pmaxrecs;
     325     2194102 :         struct xfs_da3_icnode_hdr       nodehdr;
     326     2194102 :         int                             error = 0;
     327             : 
     328     2194102 :         blk = &ds->state->path.blk[level];
     329     2192781 :         ds->state->path.active = level + 1;
     330             : 
     331             :         /* Release old block. */
     332     2192781 :         if (blk->bp) {
     333      454747 :                 xfs_trans_brelse(dargs->trans, blk->bp);
     334      454754 :                 blk->bp = NULL;
     335             :         }
     336             : 
     337             :         /* Check the pointer. */
     338     2192788 :         blk->blkno = blkno;
     339     2192788 :         if (!xchk_da_btree_ptr_ok(ds, level, blkno))
     340           0 :                 goto out_nobuf;
     341             : 
     342             :         /* Read the buffer. */
     343     2190516 :         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     2194271 :         if (!xchk_da_process_error(ds, level, &error))
     347           0 :                 goto out_nobuf;
     348     2191450 :         if (blk->bp)
     349     1999006 :                 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     2195125 :         if (ds->dargs.whichfork == XFS_DATA_FORK && level == 0 &&
     357      273836 :                         blk->bp == NULL)
     358      192444 :                 goto out_nobuf;
     359             : 
     360             :         /* It's /not/ ok for attr trees not to have a da btree. */
     361     2002681 :         if (blk->bp == NULL) {
     362           0 :                 xchk_da_set_corrupt(ds, level);
     363           0 :                 goto out_nobuf;
     364             :         }
     365             : 
     366     2002681 :         hdr3 = blk->bp->b_addr;
     367     2002681 :         blk->magic = be16_to_cpu(hdr3->hdr.magic);
     368     2002681 :         pmaxrecs = &ds->maxrecs[level];
     369             : 
     370             :         /* We only started zeroing the header on v5 filesystems. */
     371     2002682 :         if (xfs_has_crc(ds->sc->mp) && hdr3->hdr.pad)
     372           0 :                 xchk_da_set_corrupt(ds, level);
     373             : 
     374             :         /* Check the owner. */
     375     2002682 :         if (xfs_has_crc(ip->i_mount)) {
     376     2002972 :                 owner = be64_to_cpu(hdr3->owner);
     377     2002972 :                 if (owner != ip->i_ino)
     378           0 :                         xchk_da_set_corrupt(ds, level);
     379             :         }
     380             : 
     381             :         /* Check the siblings. */
     382     2002682 :         error = xchk_da_btree_block_check_siblings(ds, level, &hdr3->hdr);
     383     2001760 :         if (error)
     384           0 :                 goto out;
     385             : 
     386             :         /* Interpret the buffer. */
     387     2001760 :         switch (blk->magic) {
     388     1507905 :         case XFS_ATTR_LEAF_MAGIC:
     389             :         case XFS_ATTR3_LEAF_MAGIC:
     390     1507905 :                 xfs_trans_buf_set_type(dargs->trans, blk->bp,
     391             :                                 XFS_BLFT_ATTR_LEAF_BUF);
     392     1506929 :                 blk->magic = XFS_ATTR_LEAF_MAGIC;
     393     1506929 :                 blk->hashval = xfs_attr_leaf_lasthash(blk->bp, pmaxrecs);
     394     1506407 :                 if (ds->tree_level != 0)
     395           0 :                         xchk_da_set_corrupt(ds, level);
     396             :                 break;
     397      397895 :         case XFS_DIR2_LEAFN_MAGIC:
     398             :         case XFS_DIR3_LEAFN_MAGIC:
     399      397895 :                 xfs_trans_buf_set_type(dargs->trans, blk->bp,
     400             :                                 XFS_BLFT_DIR_LEAFN_BUF);
     401      397884 :                 blk->magic = XFS_DIR2_LEAFN_MAGIC;
     402      397884 :                 blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
     403      397892 :                 if (ds->tree_level != 0)
     404           0 :                         xchk_da_set_corrupt(ds, level);
     405             :                 break;
     406       29750 :         case XFS_DIR2_LEAF1_MAGIC:
     407             :         case XFS_DIR3_LEAF1_MAGIC:
     408       29750 :                 xfs_trans_buf_set_type(dargs->trans, blk->bp,
     409             :                                 XFS_BLFT_DIR_LEAF1_BUF);
     410       29749 :                 blk->magic = XFS_DIR2_LEAF1_MAGIC;
     411       29749 :                 blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
     412       29748 :                 if (ds->tree_level != 0)
     413           0 :                         xchk_da_set_corrupt(ds, level);
     414             :                 break;
     415       66210 :         case XFS_DA_NODE_MAGIC:
     416             :         case XFS_DA3_NODE_MAGIC:
     417       66210 :                 xfs_trans_buf_set_type(dargs->trans, blk->bp,
     418             :                                 XFS_BLFT_DA_NODE_BUF);
     419       66207 :                 blk->magic = XFS_DA_NODE_MAGIC;
     420       66207 :                 node = blk->bp->b_addr;
     421       66207 :                 xfs_da3_node_hdr_from_disk(ip->i_mount, &nodehdr, node);
     422       66211 :                 btree = nodehdr.btree;
     423       66211 :                 *pmaxrecs = nodehdr.count;
     424       66211 :                 blk->hashval = be32_to_cpu(btree[*pmaxrecs - 1].hashval);
     425       66211 :                 if (level == 0) {
     426       65802 :                         if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
     427           0 :                                 xchk_da_set_corrupt(ds, level);
     428           0 :                                 goto out_freebp;
     429             :                         }
     430       65802 :                         ds->tree_level = nodehdr.level;
     431             :                 } else {
     432         409 :                         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     2000258 :         if (level > 0) {
     450      520597 :                 struct xfs_da_node_entry        *key;
     451             : 
     452      520597 :                 key = xchk_da_btree_node_entry(ds, level - 1);
     453      520599 :                 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     2000260 : out:
     460             :         return error;
     461           0 : out_freebp:
     462           0 :         xfs_trans_brelse(dargs->trans, blk->bp);
     463           0 :         blk->bp = NULL;
     464      192444 : out_nobuf:
     465      192444 :         blk->blkno = 0;
     466      192444 :         return error;
     467             : }
     468             : 
     469             : /* Visit all nodes and leaves of a da btree. */
     470             : int
     471    90877077 : xchk_da_btree(
     472             :         struct xfs_scrub                *sc,
     473             :         int                             whichfork,
     474             :         xchk_da_btree_rec_fn            scrub_fn,
     475             :         void                            *private)
     476             : {
     477    90877077 :         struct xchk_da_btree            *ds;
     478    90877077 :         struct xfs_mount                *mp = sc->mp;
     479    90877077 :         struct xfs_da_state_blk         *blks;
     480    90877077 :         struct xfs_da_node_entry        *key;
     481    90877077 :         xfs_dablk_t                     blkno;
     482    90877077 :         int                             level;
     483    90877077 :         int                             error;
     484             : 
     485             :         /* Skip short format data structures; no btree to scan. */
     486    90877077 :         if (!xfs_ifork_has_extents(xfs_ifork_ptr(sc->ip, whichfork)))
     487             :                 return 0;
     488             : 
     489             :         /* Set up initial da state. */
     490     1670171 :         ds = kzalloc(sizeof(struct xchk_da_btree), XCHK_GFP_FLAGS);
     491     1673258 :         if (!ds)
     492             :                 return -ENOMEM;
     493     1673258 :         ds->dargs.dp = sc->ip;
     494     1673258 :         ds->dargs.whichfork = whichfork;
     495     1673258 :         ds->dargs.trans = sc->tp;
     496     1673258 :         ds->dargs.op_flags = XFS_DA_OP_OKNOENT;
     497     1673258 :         ds->state = xfs_da_state_alloc(&ds->dargs);
     498     1674313 :         ds->sc = sc;
     499     1674313 :         ds->private = private;
     500     1674313 :         if (whichfork == XFS_ATTR_FORK) {
     501     1400466 :                 ds->dargs.geo = mp->m_attr_geo;
     502     1400466 :                 ds->lowest = 0;
     503     1400466 :                 ds->highest = 0;
     504             :         } else {
     505      273847 :                 ds->dargs.geo = mp->m_dir_geo;
     506      273847 :                 ds->lowest = ds->dargs.geo->leafblk;
     507      273847 :                 ds->highest = ds->dargs.geo->freeblk;
     508             :         }
     509     1674313 :         blkno = ds->lowest;
     510     1674313 :         level = 0;
     511             : 
     512             :         /* Find the root of the da tree, if present. */
     513     1674313 :         blks = ds->state->path.blk;
     514     1674313 :         error = xchk_da_btree_block(ds, level, blkno);
     515     1673343 :         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     1673343 :         if (blks[level].bp == NULL)
     523      192443 :                 goto out_state;
     524             : 
     525     1480900 :         blks[level].index = 0;
     526   156285964 :         while (level >= 0 && level < XFS_DA_NODE_MAXDEPTH) {
     527             :                 /* Handle leaf block. */
     528   154802149 :                 if (blks[level].magic != XFS_DA_NODE_MAGIC) {
     529             :                         /* End of leaf, pop back towards the root. */
     530   154215347 :                         if (blks[level].index >= ds->maxrecs[level]) {
     531     1938288 :                                 if (level > 0)
     532      520183 :                                         blks[level - 1].index++;
     533     1938288 :                                 ds->tree_level++;
     534     1938288 :                                 level--;
     535     1938288 :                                 continue;
     536             :                         }
     537             : 
     538             :                         /* Dispatch record scrubbing. */
     539   152292231 :                         error = scrub_fn(ds, level);
     540   152258747 :                         if (error)
     541             :                                 break;
     542   152258747 :                         if (xchk_should_terminate(sc, &error) ||
     543   152279981 :                             (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
     544             :                                 break;
     545             : 
     546   152279981 :                         blks[level].index++;
     547   152279981 :                         continue;
     548             :                 }
     549             : 
     550             : 
     551             :                 /* End of node, pop back towards the root. */
     552      586802 :                 if (blks[level].index >= ds->maxrecs[level]) {
     553       66202 :                         if (level > 0)
     554         409 :                                 blks[level - 1].index++;
     555       66202 :                         ds->tree_level++;
     556       66202 :                         level--;
     557       66202 :                         continue;
     558             :                 }
     559             : 
     560             :                 /* Hashes in order for scrub? */
     561      520599 :                 key = xchk_da_btree_node_entry(ds, level);
     562      520597 :                 error = xchk_da_btree_hash(ds, level, &key->hashval);
     563      520596 :                 if (error)
     564           0 :                         goto out;
     565             : 
     566             :                 /* Drill another level deeper. */
     567      520596 :                 blkno = be32_to_cpu(key->before);
     568      520596 :                 level++;
     569      520596 :                 if (level >= XFS_DA_NODE_MAXDEPTH) {
     570             :                         /* Too deep! */
     571           0 :                         xchk_da_set_corrupt(ds, level - 1);
     572           0 :                         break;
     573             :                 }
     574      520596 :                 ds->tree_level--;
     575      520596 :                 error = xchk_da_btree_block(ds, level, blkno);
     576      520593 :                 if (error)
     577           0 :                         goto out;
     578      520593 :                 if (blks[level].bp == NULL)
     579           0 :                         goto out;
     580             : 
     581      520593 :                 blks[level].index = 0;
     582             :         }
     583             : 
     584     1483830 : out:
     585             :         /* Release all the buffers we're tracking. */
     586     8897451 :         for (level = 0; level < XFS_DA_NODE_MAXDEPTH; level++) {
     587     7414491 :                 if (blks[level].bp == NULL)
     588     5864955 :                         continue;
     589     1549536 :                 xfs_trans_brelse(sc->tp, blks[level].bp);
     590     1548666 :                 blks[level].bp = NULL;
     591             :         }
     592             : 
     593     1482960 : out_state:
     594     1675403 :         xfs_da_state_free(ds->state);
     595     1672887 :         kfree(ds);
     596     1673807 :         return error;
     597             : }

Generated by: LCOV version 1.14