linux/fs/xfs/scrub/btree.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2017 Oracle.  All Rights Reserved.
   4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
   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_defer.h"
  13#include "xfs_btree.h"
  14#include "xfs_bit.h"
  15#include "xfs_log_format.h"
  16#include "xfs_trans.h"
  17#include "xfs_sb.h"
  18#include "xfs_inode.h"
  19#include "xfs_alloc.h"
  20#include "scrub/scrub.h"
  21#include "scrub/common.h"
  22#include "scrub/btree.h"
  23#include "scrub/trace.h"
  24
  25/* btree scrubbing */
  26
  27/*
  28 * Check for btree operation errors.  See the section about handling
  29 * operational errors in common.c.
  30 */
  31static bool
  32__xchk_btree_process_error(
  33        struct xfs_scrub        *sc,
  34        struct xfs_btree_cur    *cur,
  35        int                     level,
  36        int                     *error,
  37        __u32                   errflag,
  38        void                    *ret_ip)
  39{
  40        if (*error == 0)
  41                return true;
  42
  43        switch (*error) {
  44        case -EDEADLOCK:
  45                /* Used to restart an op with deadlock avoidance. */
  46                trace_xchk_deadlock_retry(sc->ip, sc->sm, *error);
  47                break;
  48        case -EFSBADCRC:
  49        case -EFSCORRUPTED:
  50                /* Note the badness but don't abort. */
  51                sc->sm->sm_flags |= errflag;
  52                *error = 0;
  53                /* fall through */
  54        default:
  55                if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
  56                        trace_xchk_ifork_btree_op_error(sc, cur, level,
  57                                        *error, ret_ip);
  58                else
  59                        trace_xchk_btree_op_error(sc, cur, level,
  60                                        *error, ret_ip);
  61                break;
  62        }
  63        return false;
  64}
  65
  66bool
  67xchk_btree_process_error(
  68        struct xfs_scrub        *sc,
  69        struct xfs_btree_cur    *cur,
  70        int                     level,
  71        int                     *error)
  72{
  73        return __xchk_btree_process_error(sc, cur, level, error,
  74                        XFS_SCRUB_OFLAG_CORRUPT, __return_address);
  75}
  76
  77bool
  78xchk_btree_xref_process_error(
  79        struct xfs_scrub        *sc,
  80        struct xfs_btree_cur    *cur,
  81        int                     level,
  82        int                     *error)
  83{
  84        return __xchk_btree_process_error(sc, cur, level, error,
  85                        XFS_SCRUB_OFLAG_XFAIL, __return_address);
  86}
  87
  88/* Record btree block corruption. */
  89static void
  90__xchk_btree_set_corrupt(
  91        struct xfs_scrub        *sc,
  92        struct xfs_btree_cur    *cur,
  93        int                     level,
  94        __u32                   errflag,
  95        void                    *ret_ip)
  96{
  97        sc->sm->sm_flags |= errflag;
  98
  99        if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
 100                trace_xchk_ifork_btree_error(sc, cur, level,
 101                                ret_ip);
 102        else
 103                trace_xchk_btree_error(sc, cur, level,
 104                                ret_ip);
 105}
 106
 107void
 108xchk_btree_set_corrupt(
 109        struct xfs_scrub        *sc,
 110        struct xfs_btree_cur    *cur,
 111        int                     level)
 112{
 113        __xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_CORRUPT,
 114                        __return_address);
 115}
 116
 117void
 118xchk_btree_xref_set_corrupt(
 119        struct xfs_scrub        *sc,
 120        struct xfs_btree_cur    *cur,
 121        int                     level)
 122{
 123        __xchk_btree_set_corrupt(sc, cur, level, XFS_SCRUB_OFLAG_XCORRUPT,
 124                        __return_address);
 125}
 126
 127/*
 128 * Make sure this record is in order and doesn't stray outside of the parent
 129 * keys.
 130 */
 131STATIC void
 132xchk_btree_rec(
 133        struct xchk_btree       *bs)
 134{
 135        struct xfs_btree_cur    *cur = bs->cur;
 136        union xfs_btree_rec     *rec;
 137        union xfs_btree_key     key;
 138        union xfs_btree_key     hkey;
 139        union xfs_btree_key     *keyp;
 140        struct xfs_btree_block  *block;
 141        struct xfs_btree_block  *keyblock;
 142        struct xfs_buf          *bp;
 143
 144        block = xfs_btree_get_block(cur, 0, &bp);
 145        rec = xfs_btree_rec_addr(cur, cur->bc_ptrs[0], block);
 146
 147        trace_xchk_btree_rec(bs->sc, cur, 0);
 148
 149        /* If this isn't the first record, are they in order? */
 150        if (!bs->firstrec && !cur->bc_ops->recs_inorder(cur, &bs->lastrec, rec))
 151                xchk_btree_set_corrupt(bs->sc, cur, 0);
 152        bs->firstrec = false;
 153        memcpy(&bs->lastrec, rec, cur->bc_ops->rec_len);
 154
 155        if (cur->bc_nlevels == 1)
 156                return;
 157
 158        /* Is this at least as large as the parent low key? */
 159        cur->bc_ops->init_key_from_rec(&key, rec);
 160        keyblock = xfs_btree_get_block(cur, 1, &bp);
 161        keyp = xfs_btree_key_addr(cur, cur->bc_ptrs[1], keyblock);
 162        if (cur->bc_ops->diff_two_keys(cur, &key, keyp) < 0)
 163                xchk_btree_set_corrupt(bs->sc, cur, 1);
 164
 165        if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
 166                return;
 167
 168        /* Is this no larger than the parent high key? */
 169        cur->bc_ops->init_high_key_from_rec(&hkey, rec);
 170        keyp = xfs_btree_high_key_addr(cur, cur->bc_ptrs[1], keyblock);
 171        if (cur->bc_ops->diff_two_keys(cur, keyp, &hkey) < 0)
 172                xchk_btree_set_corrupt(bs->sc, cur, 1);
 173}
 174
 175/*
 176 * Make sure this key is in order and doesn't stray outside of the parent
 177 * keys.
 178 */
 179STATIC void
 180xchk_btree_key(
 181        struct xchk_btree       *bs,
 182        int                     level)
 183{
 184        struct xfs_btree_cur    *cur = bs->cur;
 185        union xfs_btree_key     *key;
 186        union xfs_btree_key     *keyp;
 187        struct xfs_btree_block  *block;
 188        struct xfs_btree_block  *keyblock;
 189        struct xfs_buf          *bp;
 190
 191        block = xfs_btree_get_block(cur, level, &bp);
 192        key = xfs_btree_key_addr(cur, cur->bc_ptrs[level], block);
 193
 194        trace_xchk_btree_key(bs->sc, cur, level);
 195
 196        /* If this isn't the first key, are they in order? */
 197        if (!bs->firstkey[level] &&
 198            !cur->bc_ops->keys_inorder(cur, &bs->lastkey[level], key))
 199                xchk_btree_set_corrupt(bs->sc, cur, level);
 200        bs->firstkey[level] = false;
 201        memcpy(&bs->lastkey[level], key, cur->bc_ops->key_len);
 202
 203        if (level + 1 >= cur->bc_nlevels)
 204                return;
 205
 206        /* Is this at least as large as the parent low key? */
 207        keyblock = xfs_btree_get_block(cur, level + 1, &bp);
 208        keyp = xfs_btree_key_addr(cur, cur->bc_ptrs[level + 1], keyblock);
 209        if (cur->bc_ops->diff_two_keys(cur, key, keyp) < 0)
 210                xchk_btree_set_corrupt(bs->sc, cur, level);
 211
 212        if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
 213                return;
 214
 215        /* Is this no larger than the parent high key? */
 216        key = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level], block);
 217        keyp = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level + 1], keyblock);
 218        if (cur->bc_ops->diff_two_keys(cur, keyp, key) < 0)
 219                xchk_btree_set_corrupt(bs->sc, cur, level);
 220}
 221
 222/*
 223 * Check a btree pointer.  Returns true if it's ok to use this pointer.
 224 * Callers do not need to set the corrupt flag.
 225 */
 226static bool
 227xchk_btree_ptr_ok(
 228        struct xchk_btree       *bs,
 229        int                     level,
 230        union xfs_btree_ptr     *ptr)
 231{
 232        bool                    res;
 233
 234        /* A btree rooted in an inode has no block pointer to the root. */
 235        if ((bs->cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
 236            level == bs->cur->bc_nlevels)
 237                return true;
 238
 239        /* Otherwise, check the pointers. */
 240        if (bs->cur->bc_flags & XFS_BTREE_LONG_PTRS)
 241                res = xfs_btree_check_lptr(bs->cur, be64_to_cpu(ptr->l), level);
 242        else
 243                res = xfs_btree_check_sptr(bs->cur, be32_to_cpu(ptr->s), level);
 244        if (!res)
 245                xchk_btree_set_corrupt(bs->sc, bs->cur, level);
 246
 247        return res;
 248}
 249
 250/* Check that a btree block's sibling matches what we expect it. */
 251STATIC int
 252xchk_btree_block_check_sibling(
 253        struct xchk_btree       *bs,
 254        int                     level,
 255        int                     direction,
 256        union xfs_btree_ptr     *sibling)
 257{
 258        struct xfs_btree_cur    *cur = bs->cur;
 259        struct xfs_btree_block  *pblock;
 260        struct xfs_buf          *pbp;
 261        struct xfs_btree_cur    *ncur = NULL;
 262        union xfs_btree_ptr     *pp;
 263        int                     success;
 264        int                     error;
 265
 266        error = xfs_btree_dup_cursor(cur, &ncur);
 267        if (!xchk_btree_process_error(bs->sc, cur, level + 1, &error) ||
 268            !ncur)
 269                return error;
 270
 271        /*
 272         * If the pointer is null, we shouldn't be able to move the upper
 273         * level pointer anywhere.
 274         */
 275        if (xfs_btree_ptr_is_null(cur, sibling)) {
 276                if (direction > 0)
 277                        error = xfs_btree_increment(ncur, level + 1, &success);
 278                else
 279                        error = xfs_btree_decrement(ncur, level + 1, &success);
 280                if (error == 0 && success)
 281                        xchk_btree_set_corrupt(bs->sc, cur, level);
 282                error = 0;
 283                goto out;
 284        }
 285
 286        /* Increment upper level pointer. */
 287        if (direction > 0)
 288                error = xfs_btree_increment(ncur, level + 1, &success);
 289        else
 290                error = xfs_btree_decrement(ncur, level + 1, &success);
 291        if (!xchk_btree_process_error(bs->sc, cur, level + 1, &error))
 292                goto out;
 293        if (!success) {
 294                xchk_btree_set_corrupt(bs->sc, cur, level + 1);
 295                goto out;
 296        }
 297
 298        /* Compare upper level pointer to sibling pointer. */
 299        pblock = xfs_btree_get_block(ncur, level + 1, &pbp);
 300        pp = xfs_btree_ptr_addr(ncur, ncur->bc_ptrs[level + 1], pblock);
 301        if (!xchk_btree_ptr_ok(bs, level + 1, pp))
 302                goto out;
 303        if (pbp)
 304                xchk_buffer_recheck(bs->sc, pbp);
 305
 306        if (xfs_btree_diff_two_ptrs(cur, pp, sibling))
 307                xchk_btree_set_corrupt(bs->sc, cur, level);
 308out:
 309        xfs_btree_del_cursor(ncur, XFS_BTREE_ERROR);
 310        return error;
 311}
 312
 313/* Check the siblings of a btree block. */
 314STATIC int
 315xchk_btree_block_check_siblings(
 316        struct xchk_btree       *bs,
 317        struct xfs_btree_block  *block)
 318{
 319        struct xfs_btree_cur    *cur = bs->cur;
 320        union xfs_btree_ptr     leftsib;
 321        union xfs_btree_ptr     rightsib;
 322        int                     level;
 323        int                     error = 0;
 324
 325        xfs_btree_get_sibling(cur, block, &leftsib, XFS_BB_LEFTSIB);
 326        xfs_btree_get_sibling(cur, block, &rightsib, XFS_BB_RIGHTSIB);
 327        level = xfs_btree_get_level(block);
 328
 329        /* Root block should never have siblings. */
 330        if (level == cur->bc_nlevels - 1) {
 331                if (!xfs_btree_ptr_is_null(cur, &leftsib) ||
 332                    !xfs_btree_ptr_is_null(cur, &rightsib))
 333                        xchk_btree_set_corrupt(bs->sc, cur, level);
 334                goto out;
 335        }
 336
 337        /*
 338         * Does the left & right sibling pointers match the adjacent
 339         * parent level pointers?
 340         * (These function absorbs error codes for us.)
 341         */
 342        error = xchk_btree_block_check_sibling(bs, level, -1, &leftsib);
 343        if (error)
 344                return error;
 345        error = xchk_btree_block_check_sibling(bs, level, 1, &rightsib);
 346        if (error)
 347                return error;
 348out:
 349        return error;
 350}
 351
 352struct check_owner {
 353        struct list_head        list;
 354        xfs_daddr_t             daddr;
 355        int                     level;
 356};
 357
 358/*
 359 * Make sure this btree block isn't in the free list and that there's
 360 * an rmap record for it.
 361 */
 362STATIC int
 363xchk_btree_check_block_owner(
 364        struct xchk_btree       *bs,
 365        int                     level,
 366        xfs_daddr_t             daddr)
 367{
 368        xfs_agnumber_t          agno;
 369        xfs_agblock_t           agbno;
 370        xfs_btnum_t             btnum;
 371        bool                    init_sa;
 372        int                     error = 0;
 373
 374        if (!bs->cur)
 375                return 0;
 376
 377        btnum = bs->cur->bc_btnum;
 378        agno = xfs_daddr_to_agno(bs->cur->bc_mp, daddr);
 379        agbno = xfs_daddr_to_agbno(bs->cur->bc_mp, daddr);
 380
 381        init_sa = bs->cur->bc_flags & XFS_BTREE_LONG_PTRS;
 382        if (init_sa) {
 383                error = xchk_ag_init(bs->sc, agno, &bs->sc->sa);
 384                if (!xchk_btree_xref_process_error(bs->sc, bs->cur,
 385                                level, &error))
 386                        return error;
 387        }
 388
 389        xchk_xref_is_used_space(bs->sc, agbno, 1);
 390        /*
 391         * The bnobt scrubber aliases bs->cur to bs->sc->sa.bno_cur, so we
 392         * have to nullify it (to shut down further block owner checks) if
 393         * self-xref encounters problems.
 394         */
 395        if (!bs->sc->sa.bno_cur && btnum == XFS_BTNUM_BNO)
 396                bs->cur = NULL;
 397
 398        xchk_xref_is_owned_by(bs->sc, agbno, 1, bs->oinfo);
 399        if (!bs->sc->sa.rmap_cur && btnum == XFS_BTNUM_RMAP)
 400                bs->cur = NULL;
 401
 402        if (init_sa)
 403                xchk_ag_free(bs->sc, &bs->sc->sa);
 404
 405        return error;
 406}
 407
 408/* Check the owner of a btree block. */
 409STATIC int
 410xchk_btree_check_owner(
 411        struct xchk_btree       *bs,
 412        int                     level,
 413        struct xfs_buf          *bp)
 414{
 415        struct xfs_btree_cur    *cur = bs->cur;
 416        struct check_owner      *co;
 417
 418        /*
 419         * In theory, xfs_btree_get_block should only give us a null buffer
 420         * pointer for the root of a root-in-inode btree type, but we need
 421         * to check defensively here in case the cursor state is also screwed
 422         * up.
 423         */
 424        if (bp == NULL) {
 425                if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE))
 426                        xchk_btree_set_corrupt(bs->sc, bs->cur, level);
 427                return 0;
 428        }
 429
 430        /*
 431         * We want to cross-reference each btree block with the bnobt
 432         * and the rmapbt.  We cannot cross-reference the bnobt or
 433         * rmapbt while scanning the bnobt or rmapbt, respectively,
 434         * because we cannot alter the cursor and we'd prefer not to
 435         * duplicate cursors.  Therefore, save the buffer daddr for
 436         * later scanning.
 437         */
 438        if (cur->bc_btnum == XFS_BTNUM_BNO || cur->bc_btnum == XFS_BTNUM_RMAP) {
 439                co = kmem_alloc(sizeof(struct check_owner),
 440                                KM_MAYFAIL);
 441                if (!co)
 442                        return -ENOMEM;
 443                co->level = level;
 444                co->daddr = XFS_BUF_ADDR(bp);
 445                list_add_tail(&co->list, &bs->to_check);
 446                return 0;
 447        }
 448
 449        return xchk_btree_check_block_owner(bs, level, XFS_BUF_ADDR(bp));
 450}
 451
 452/*
 453 * Check that this btree block has at least minrecs records or is one of the
 454 * special blocks that don't require that.
 455 */
 456STATIC void
 457xchk_btree_check_minrecs(
 458        struct xchk_btree       *bs,
 459        int                     level,
 460        struct xfs_btree_block  *block)
 461{
 462        unsigned int            numrecs;
 463        int                     ok_level;
 464
 465        numrecs = be16_to_cpu(block->bb_numrecs);
 466
 467        /* More records than minrecs means the block is ok. */
 468        if (numrecs >= bs->cur->bc_ops->get_minrecs(bs->cur, level))
 469                return;
 470
 471        /*
 472         * Certain btree blocks /can/ have fewer than minrecs records.  Any
 473         * level greater than or equal to the level of the highest dedicated
 474         * btree block are allowed to violate this constraint.
 475         *
 476         * For a btree rooted in a block, the btree root can have fewer than
 477         * minrecs records.  If the btree is rooted in an inode and does not
 478         * store records in the root, the direct children of the root and the
 479         * root itself can have fewer than minrecs records.
 480         */
 481        ok_level = bs->cur->bc_nlevels - 1;
 482        if (bs->cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)
 483                ok_level--;
 484        if (level >= ok_level)
 485                return;
 486
 487        xchk_btree_set_corrupt(bs->sc, bs->cur, level);
 488}
 489
 490/*
 491 * Grab and scrub a btree block given a btree pointer.  Returns block
 492 * and buffer pointers (if applicable) if they're ok to use.
 493 */
 494STATIC int
 495xchk_btree_get_block(
 496        struct xchk_btree       *bs,
 497        int                     level,
 498        union xfs_btree_ptr     *pp,
 499        struct xfs_btree_block  **pblock,
 500        struct xfs_buf          **pbp)
 501{
 502        xfs_failaddr_t          failed_at;
 503        int                     error;
 504
 505        *pblock = NULL;
 506        *pbp = NULL;
 507
 508        error = xfs_btree_lookup_get_block(bs->cur, level, pp, pblock);
 509        if (!xchk_btree_process_error(bs->sc, bs->cur, level, &error) ||
 510            !*pblock)
 511                return error;
 512
 513        xfs_btree_get_block(bs->cur, level, pbp);
 514        if (bs->cur->bc_flags & XFS_BTREE_LONG_PTRS)
 515                failed_at = __xfs_btree_check_lblock(bs->cur, *pblock,
 516                                level, *pbp);
 517        else
 518                failed_at = __xfs_btree_check_sblock(bs->cur, *pblock,
 519                                 level, *pbp);
 520        if (failed_at) {
 521                xchk_btree_set_corrupt(bs->sc, bs->cur, level);
 522                return 0;
 523        }
 524        if (*pbp)
 525                xchk_buffer_recheck(bs->sc, *pbp);
 526
 527        xchk_btree_check_minrecs(bs, level, *pblock);
 528
 529        /*
 530         * Check the block's owner; this function absorbs error codes
 531         * for us.
 532         */
 533        error = xchk_btree_check_owner(bs, level, *pbp);
 534        if (error)
 535                return error;
 536
 537        /*
 538         * Check the block's siblings; this function absorbs error codes
 539         * for us.
 540         */
 541        return xchk_btree_block_check_siblings(bs, *pblock);
 542}
 543
 544/*
 545 * Check that the low and high keys of this block match the keys stored
 546 * in the parent block.
 547 */
 548STATIC void
 549xchk_btree_block_keys(
 550        struct xchk_btree       *bs,
 551        int                     level,
 552        struct xfs_btree_block  *block)
 553{
 554        union xfs_btree_key     block_keys;
 555        struct xfs_btree_cur    *cur = bs->cur;
 556        union xfs_btree_key     *high_bk;
 557        union xfs_btree_key     *parent_keys;
 558        union xfs_btree_key     *high_pk;
 559        struct xfs_btree_block  *parent_block;
 560        struct xfs_buf          *bp;
 561
 562        if (level >= cur->bc_nlevels - 1)
 563                return;
 564
 565        /* Calculate the keys for this block. */
 566        xfs_btree_get_keys(cur, block, &block_keys);
 567
 568        /* Obtain the parent's copy of the keys for this block. */
 569        parent_block = xfs_btree_get_block(cur, level + 1, &bp);
 570        parent_keys = xfs_btree_key_addr(cur, cur->bc_ptrs[level + 1],
 571                        parent_block);
 572
 573        if (cur->bc_ops->diff_two_keys(cur, &block_keys, parent_keys) != 0)
 574                xchk_btree_set_corrupt(bs->sc, cur, 1);
 575
 576        if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
 577                return;
 578
 579        /* Get high keys */
 580        high_bk = xfs_btree_high_key_from_key(cur, &block_keys);
 581        high_pk = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level + 1],
 582                        parent_block);
 583
 584        if (cur->bc_ops->diff_two_keys(cur, high_bk, high_pk) != 0)
 585                xchk_btree_set_corrupt(bs->sc, cur, 1);
 586}
 587
 588/*
 589 * Visit all nodes and leaves of a btree.  Check that all pointers and
 590 * records are in order, that the keys reflect the records, and use a callback
 591 * so that the caller can verify individual records.
 592 */
 593int
 594xchk_btree(
 595        struct xfs_scrub                *sc,
 596        struct xfs_btree_cur            *cur,
 597        xchk_btree_rec_fn               scrub_fn,
 598        const struct xfs_owner_info     *oinfo,
 599        void                            *private)
 600{
 601        struct xchk_btree               bs = {
 602                .cur                    = cur,
 603                .scrub_rec              = scrub_fn,
 604                .oinfo                  = oinfo,
 605                .firstrec               = true,
 606                .private                = private,
 607                .sc                     = sc,
 608        };
 609        union xfs_btree_ptr             ptr;
 610        union xfs_btree_ptr             *pp;
 611        union xfs_btree_rec             *recp;
 612        struct xfs_btree_block          *block;
 613        int                             level;
 614        struct xfs_buf                  *bp;
 615        struct check_owner              *co;
 616        struct check_owner              *n;
 617        int                             i;
 618        int                             error = 0;
 619
 620        /* Initialize scrub state */
 621        for (i = 0; i < XFS_BTREE_MAXLEVELS; i++)
 622                bs.firstkey[i] = true;
 623        INIT_LIST_HEAD(&bs.to_check);
 624
 625        /* Don't try to check a tree with a height we can't handle. */
 626        if (cur->bc_nlevels > XFS_BTREE_MAXLEVELS) {
 627                xchk_btree_set_corrupt(sc, cur, 0);
 628                goto out;
 629        }
 630
 631        /*
 632         * Load the root of the btree.  The helper function absorbs
 633         * error codes for us.
 634         */
 635        level = cur->bc_nlevels - 1;
 636        cur->bc_ops->init_ptr_from_cur(cur, &ptr);
 637        if (!xchk_btree_ptr_ok(&bs, cur->bc_nlevels, &ptr))
 638                goto out;
 639        error = xchk_btree_get_block(&bs, level, &ptr, &block, &bp);
 640        if (error || !block)
 641                goto out;
 642
 643        cur->bc_ptrs[level] = 1;
 644
 645        while (level < cur->bc_nlevels) {
 646                block = xfs_btree_get_block(cur, level, &bp);
 647
 648                if (level == 0) {
 649                        /* End of leaf, pop back towards the root. */
 650                        if (cur->bc_ptrs[level] >
 651                            be16_to_cpu(block->bb_numrecs)) {
 652                                xchk_btree_block_keys(&bs, level, block);
 653                                if (level < cur->bc_nlevels - 1)
 654                                        cur->bc_ptrs[level + 1]++;
 655                                level++;
 656                                continue;
 657                        }
 658
 659                        /* Records in order for scrub? */
 660                        xchk_btree_rec(&bs);
 661
 662                        /* Call out to the record checker. */
 663                        recp = xfs_btree_rec_addr(cur, cur->bc_ptrs[0], block);
 664                        error = bs.scrub_rec(&bs, recp);
 665                        if (error)
 666                                break;
 667                        if (xchk_should_terminate(sc, &error) ||
 668                            (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
 669                                break;
 670
 671                        cur->bc_ptrs[level]++;
 672                        continue;
 673                }
 674
 675                /* End of node, pop back towards the root. */
 676                if (cur->bc_ptrs[level] > be16_to_cpu(block->bb_numrecs)) {
 677                        xchk_btree_block_keys(&bs, level, block);
 678                        if (level < cur->bc_nlevels - 1)
 679                                cur->bc_ptrs[level + 1]++;
 680                        level++;
 681                        continue;
 682                }
 683
 684                /* Keys in order for scrub? */
 685                xchk_btree_key(&bs, level);
 686
 687                /* Drill another level deeper. */
 688                pp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[level], block);
 689                if (!xchk_btree_ptr_ok(&bs, level, pp)) {
 690                        cur->bc_ptrs[level]++;
 691                        continue;
 692                }
 693                level--;
 694                error = xchk_btree_get_block(&bs, level, pp, &block, &bp);
 695                if (error || !block)
 696                        goto out;
 697
 698                cur->bc_ptrs[level] = 1;
 699        }
 700
 701out:
 702        /* Process deferred owner checks on btree blocks. */
 703        list_for_each_entry_safe(co, n, &bs.to_check, list) {
 704                if (!error && bs.cur)
 705                        error = xchk_btree_check_block_owner(&bs,
 706                                        co->level, co->daddr);
 707                list_del(&co->list);
 708                kmem_free(co);
 709        }
 710
 711        return error;
 712}
 713