10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0+ 27c4a07a4SDarrick J. Wong /* 37c4a07a4SDarrick J. Wong * Copyright (C) 2017 Oracle. All Rights Reserved. 47c4a07a4SDarrick J. Wong * Author: Darrick J. Wong <darrick.wong@oracle.com> 57c4a07a4SDarrick J. Wong */ 67c4a07a4SDarrick J. Wong #include "xfs.h" 77c4a07a4SDarrick J. Wong #include "xfs_fs.h" 87c4a07a4SDarrick J. Wong #include "xfs_shared.h" 97c4a07a4SDarrick J. Wong #include "xfs_format.h" 107c4a07a4SDarrick J. Wong #include "xfs_trans_resv.h" 117c4a07a4SDarrick J. Wong #include "xfs_mount.h" 127c4a07a4SDarrick J. Wong #include "xfs_log_format.h" 137c4a07a4SDarrick J. Wong #include "xfs_trans.h" 147c4a07a4SDarrick J. Wong #include "xfs_inode.h" 157c4a07a4SDarrick J. Wong #include "xfs_dir2.h" 167c4a07a4SDarrick J. Wong #include "xfs_dir2_priv.h" 177c4a07a4SDarrick J. Wong #include "xfs_attr_leaf.h" 187c4a07a4SDarrick J. Wong #include "scrub/scrub.h" 197c4a07a4SDarrick J. Wong #include "scrub/common.h" 207c4a07a4SDarrick J. Wong #include "scrub/trace.h" 217c4a07a4SDarrick J. Wong #include "scrub/dabtree.h" 227c4a07a4SDarrick J. Wong 237c4a07a4SDarrick J. Wong /* Directory/Attribute Btree */ 247c4a07a4SDarrick J. Wong 257c4a07a4SDarrick J. Wong /* 267c4a07a4SDarrick J. Wong * Check for da btree operation errors. See the section about handling 277c4a07a4SDarrick J. Wong * operational errors in common.c. 287c4a07a4SDarrick J. Wong */ 297c4a07a4SDarrick J. Wong bool 30c517b3aaSDarrick J. Wong xchk_da_process_error( 31c517b3aaSDarrick J. Wong struct xchk_da_btree *ds, 327c4a07a4SDarrick J. Wong int level, 337c4a07a4SDarrick J. Wong int *error) 347c4a07a4SDarrick J. Wong { 351d8a748aSDarrick J. Wong struct xfs_scrub *sc = ds->sc; 367c4a07a4SDarrick J. Wong 377c4a07a4SDarrick J. Wong if (*error == 0) 387c4a07a4SDarrick J. Wong return true; 397c4a07a4SDarrick J. Wong 407c4a07a4SDarrick J. Wong switch (*error) { 417c4a07a4SDarrick J. Wong case -EDEADLOCK: 427c4a07a4SDarrick J. Wong /* Used to restart an op with deadlock avoidance. */ 43c517b3aaSDarrick J. Wong trace_xchk_deadlock_retry(sc->ip, sc->sm, *error); 447c4a07a4SDarrick J. Wong break; 457c4a07a4SDarrick J. Wong case -EFSBADCRC: 467c4a07a4SDarrick J. Wong case -EFSCORRUPTED: 477c4a07a4SDarrick J. Wong /* Note the badness but don't abort. */ 487c4a07a4SDarrick J. Wong sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT; 497c4a07a4SDarrick J. Wong *error = 0; 507c4a07a4SDarrick J. Wong /* fall through */ 517c4a07a4SDarrick J. Wong default: 52c517b3aaSDarrick J. Wong trace_xchk_file_op_error(sc, ds->dargs.whichfork, 537c4a07a4SDarrick J. Wong xfs_dir2_da_to_db(ds->dargs.geo, 547c4a07a4SDarrick J. Wong ds->state->path.blk[level].blkno), 557c4a07a4SDarrick J. Wong *error, __return_address); 567c4a07a4SDarrick J. Wong break; 577c4a07a4SDarrick J. Wong } 587c4a07a4SDarrick J. Wong return false; 597c4a07a4SDarrick J. Wong } 607c4a07a4SDarrick J. Wong 617c4a07a4SDarrick J. Wong /* 627c4a07a4SDarrick J. Wong * Check for da btree corruption. See the section about handling 637c4a07a4SDarrick J. Wong * operational errors in common.c. 647c4a07a4SDarrick J. Wong */ 657c4a07a4SDarrick J. Wong void 66c517b3aaSDarrick J. Wong xchk_da_set_corrupt( 67c517b3aaSDarrick J. Wong struct xchk_da_btree *ds, 687c4a07a4SDarrick J. Wong int level) 697c4a07a4SDarrick J. Wong { 701d8a748aSDarrick J. Wong struct xfs_scrub *sc = ds->sc; 717c4a07a4SDarrick J. Wong 727c4a07a4SDarrick J. Wong sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT; 737c4a07a4SDarrick J. Wong 74c517b3aaSDarrick J. Wong trace_xchk_fblock_error(sc, ds->dargs.whichfork, 757c4a07a4SDarrick J. Wong xfs_dir2_da_to_db(ds->dargs.geo, 767c4a07a4SDarrick J. Wong ds->state->path.blk[level].blkno), 777c4a07a4SDarrick J. Wong __return_address); 787c4a07a4SDarrick J. Wong } 797c4a07a4SDarrick J. Wong 80649d9d98SChristoph Hellwig static struct xfs_da_node_entry * 81649d9d98SChristoph Hellwig xchk_da_btree_node_entry( 82c517b3aaSDarrick J. Wong struct xchk_da_btree *ds, 83649d9d98SChristoph Hellwig int level) 847c4a07a4SDarrick J. Wong { 85649d9d98SChristoph Hellwig struct xfs_da_state_blk *blk = &ds->state->path.blk[level]; 8651908ca7SChristoph Hellwig struct xfs_da3_icnode_hdr hdr; 877c4a07a4SDarrick J. Wong 88649d9d98SChristoph Hellwig ASSERT(blk->magic == XFS_DA_NODE_MAGIC); 897c4a07a4SDarrick J. Wong 9051908ca7SChristoph Hellwig xfs_da3_node_hdr_from_disk(ds->sc->mp, &hdr, blk->bp->b_addr); 9151908ca7SChristoph Hellwig return hdr.btree + blk->index; 927c4a07a4SDarrick J. Wong } 937c4a07a4SDarrick J. Wong 947c4a07a4SDarrick J. Wong /* Scrub a da btree hash (key). */ 957c4a07a4SDarrick J. Wong int 96c517b3aaSDarrick J. Wong xchk_da_btree_hash( 97c517b3aaSDarrick J. Wong struct xchk_da_btree *ds, 987c4a07a4SDarrick J. Wong int level, 997c4a07a4SDarrick J. Wong __be32 *hashp) 1007c4a07a4SDarrick J. Wong { 1017c4a07a4SDarrick J. Wong struct xfs_da_node_entry *entry; 1027c4a07a4SDarrick J. Wong xfs_dahash_t hash; 1037c4a07a4SDarrick J. Wong xfs_dahash_t parent_hash; 1047c4a07a4SDarrick J. Wong 1057c4a07a4SDarrick J. Wong /* Is this hash in order? */ 1067c4a07a4SDarrick J. Wong hash = be32_to_cpu(*hashp); 1077c4a07a4SDarrick J. Wong if (hash < ds->hashes[level]) 108c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 1097c4a07a4SDarrick J. Wong ds->hashes[level] = hash; 1107c4a07a4SDarrick J. Wong 1117c4a07a4SDarrick J. Wong if (level == 0) 1127c4a07a4SDarrick J. Wong return 0; 1137c4a07a4SDarrick J. Wong 1147c4a07a4SDarrick J. Wong /* Is this hash no larger than the parent hash? */ 115649d9d98SChristoph Hellwig entry = xchk_da_btree_node_entry(ds, level - 1); 1167c4a07a4SDarrick J. Wong parent_hash = be32_to_cpu(entry->hashval); 1177c4a07a4SDarrick J. Wong if (parent_hash < hash) 118c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 1197c4a07a4SDarrick J. Wong 1207c4a07a4SDarrick J. Wong return 0; 1217c4a07a4SDarrick J. Wong } 1227c4a07a4SDarrick J. Wong 1237c4a07a4SDarrick J. Wong /* 1247c4a07a4SDarrick J. Wong * Check a da btree pointer. Returns true if it's ok to use this 1257c4a07a4SDarrick J. Wong * pointer. 1267c4a07a4SDarrick J. Wong */ 1277c4a07a4SDarrick J. Wong STATIC bool 128c517b3aaSDarrick J. Wong xchk_da_btree_ptr_ok( 129c517b3aaSDarrick J. Wong struct xchk_da_btree *ds, 1307c4a07a4SDarrick J. Wong int level, 1317c4a07a4SDarrick J. Wong xfs_dablk_t blkno) 1327c4a07a4SDarrick J. Wong { 1337c4a07a4SDarrick J. Wong if (blkno < ds->lowest || (ds->highest != 0 && blkno >= ds->highest)) { 134c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 1357c4a07a4SDarrick J. Wong return false; 1367c4a07a4SDarrick J. Wong } 1377c4a07a4SDarrick J. Wong 1387c4a07a4SDarrick J. Wong return true; 1397c4a07a4SDarrick J. Wong } 1407c4a07a4SDarrick J. Wong 1417c4a07a4SDarrick J. Wong /* 1427c4a07a4SDarrick J. Wong * The da btree scrubber can handle leaf1 blocks as a degenerate 1437c4a07a4SDarrick J. Wong * form of leafn blocks. Since the regular da code doesn't handle 1447c4a07a4SDarrick J. Wong * leaf1, we must multiplex the verifiers. 1457c4a07a4SDarrick J. Wong */ 1467c4a07a4SDarrick J. Wong static void 147c517b3aaSDarrick J. Wong xchk_da_btree_read_verify( 1487c4a07a4SDarrick J. Wong struct xfs_buf *bp) 1497c4a07a4SDarrick J. Wong { 1507c4a07a4SDarrick J. Wong struct xfs_da_blkinfo *info = bp->b_addr; 1517c4a07a4SDarrick J. Wong 1527c4a07a4SDarrick J. Wong switch (be16_to_cpu(info->magic)) { 1537c4a07a4SDarrick J. Wong case XFS_DIR2_LEAF1_MAGIC: 1547c4a07a4SDarrick J. Wong case XFS_DIR3_LEAF1_MAGIC: 1557c4a07a4SDarrick J. Wong bp->b_ops = &xfs_dir3_leaf1_buf_ops; 1567c4a07a4SDarrick J. Wong bp->b_ops->verify_read(bp); 1577c4a07a4SDarrick J. Wong return; 1587c4a07a4SDarrick J. Wong default: 1597c4a07a4SDarrick J. Wong /* 1607c4a07a4SDarrick J. Wong * xfs_da3_node_buf_ops already know how to handle 1617c4a07a4SDarrick J. Wong * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks. 1627c4a07a4SDarrick J. Wong */ 1637c4a07a4SDarrick J. Wong bp->b_ops = &xfs_da3_node_buf_ops; 1647c4a07a4SDarrick J. Wong bp->b_ops->verify_read(bp); 1657c4a07a4SDarrick J. Wong return; 1667c4a07a4SDarrick J. Wong } 1677c4a07a4SDarrick J. Wong } 1687c4a07a4SDarrick J. Wong static void 169c517b3aaSDarrick J. Wong xchk_da_btree_write_verify( 1707c4a07a4SDarrick J. Wong struct xfs_buf *bp) 1717c4a07a4SDarrick J. Wong { 1727c4a07a4SDarrick J. Wong struct xfs_da_blkinfo *info = bp->b_addr; 1737c4a07a4SDarrick J. Wong 1747c4a07a4SDarrick J. Wong switch (be16_to_cpu(info->magic)) { 1757c4a07a4SDarrick J. Wong case XFS_DIR2_LEAF1_MAGIC: 1767c4a07a4SDarrick J. Wong case XFS_DIR3_LEAF1_MAGIC: 1777c4a07a4SDarrick J. Wong bp->b_ops = &xfs_dir3_leaf1_buf_ops; 1787c4a07a4SDarrick J. Wong bp->b_ops->verify_write(bp); 1797c4a07a4SDarrick J. Wong return; 1807c4a07a4SDarrick J. Wong default: 1817c4a07a4SDarrick J. Wong /* 1827c4a07a4SDarrick J. Wong * xfs_da3_node_buf_ops already know how to handle 1837c4a07a4SDarrick J. Wong * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks. 1847c4a07a4SDarrick J. Wong */ 1857c4a07a4SDarrick J. Wong bp->b_ops = &xfs_da3_node_buf_ops; 1867c4a07a4SDarrick J. Wong bp->b_ops->verify_write(bp); 1877c4a07a4SDarrick J. Wong return; 1887c4a07a4SDarrick J. Wong } 1897c4a07a4SDarrick J. Wong } 190cf1b0b8bSDarrick J. Wong static void * 191c517b3aaSDarrick J. Wong xchk_da_btree_verify( 192cf1b0b8bSDarrick J. Wong struct xfs_buf *bp) 193cf1b0b8bSDarrick J. Wong { 194cf1b0b8bSDarrick J. Wong struct xfs_da_blkinfo *info = bp->b_addr; 195cf1b0b8bSDarrick J. Wong 196cf1b0b8bSDarrick J. Wong switch (be16_to_cpu(info->magic)) { 197cf1b0b8bSDarrick J. Wong case XFS_DIR2_LEAF1_MAGIC: 198cf1b0b8bSDarrick J. Wong case XFS_DIR3_LEAF1_MAGIC: 199cf1b0b8bSDarrick J. Wong bp->b_ops = &xfs_dir3_leaf1_buf_ops; 200cf1b0b8bSDarrick J. Wong return bp->b_ops->verify_struct(bp); 201cf1b0b8bSDarrick J. Wong default: 202cf1b0b8bSDarrick J. Wong bp->b_ops = &xfs_da3_node_buf_ops; 203cf1b0b8bSDarrick J. Wong return bp->b_ops->verify_struct(bp); 204cf1b0b8bSDarrick J. Wong } 205cf1b0b8bSDarrick J. Wong } 2067c4a07a4SDarrick J. Wong 207c517b3aaSDarrick J. Wong static const struct xfs_buf_ops xchk_da_btree_buf_ops = { 208c517b3aaSDarrick J. Wong .name = "xchk_da_btree", 209c517b3aaSDarrick J. Wong .verify_read = xchk_da_btree_read_verify, 210c517b3aaSDarrick J. Wong .verify_write = xchk_da_btree_write_verify, 211c517b3aaSDarrick J. Wong .verify_struct = xchk_da_btree_verify, 2127c4a07a4SDarrick J. Wong }; 2137c4a07a4SDarrick J. Wong 2147c4a07a4SDarrick J. Wong /* Check a block's sibling. */ 2157c4a07a4SDarrick J. Wong STATIC int 216c517b3aaSDarrick J. Wong xchk_da_btree_block_check_sibling( 217c517b3aaSDarrick J. Wong struct xchk_da_btree *ds, 2187c4a07a4SDarrick J. Wong int level, 2197c4a07a4SDarrick J. Wong int direction, 2207c4a07a4SDarrick J. Wong xfs_dablk_t sibling) 2217c4a07a4SDarrick J. Wong { 222afbabf56SDarrick J. Wong struct xfs_da_state_path *path = &ds->state->path; 223afbabf56SDarrick J. Wong struct xfs_da_state_path *altpath = &ds->state->altpath; 2247c4a07a4SDarrick J. Wong int retval; 225afbabf56SDarrick J. Wong int plevel; 2267c4a07a4SDarrick J. Wong int error; 2277c4a07a4SDarrick J. Wong 228afbabf56SDarrick J. Wong memcpy(altpath, path, sizeof(ds->state->altpath)); 2297c4a07a4SDarrick J. Wong 2307c4a07a4SDarrick J. Wong /* 2317c4a07a4SDarrick J. Wong * If the pointer is null, we shouldn't be able to move the upper 2327c4a07a4SDarrick J. Wong * level pointer anywhere. 2337c4a07a4SDarrick J. Wong */ 2347c4a07a4SDarrick J. Wong if (sibling == 0) { 235afbabf56SDarrick J. Wong error = xfs_da3_path_shift(ds->state, altpath, direction, 236afbabf56SDarrick J. Wong false, &retval); 2377c4a07a4SDarrick J. Wong if (error == 0 && retval == 0) 238c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 2397c4a07a4SDarrick J. Wong error = 0; 2407c4a07a4SDarrick J. Wong goto out; 2417c4a07a4SDarrick J. Wong } 2427c4a07a4SDarrick J. Wong 2437c4a07a4SDarrick J. Wong /* Move the alternate cursor one block in the direction given. */ 244afbabf56SDarrick J. Wong error = xfs_da3_path_shift(ds->state, altpath, direction, false, 245afbabf56SDarrick J. Wong &retval); 246c517b3aaSDarrick J. Wong if (!xchk_da_process_error(ds, level, &error)) 247afbabf56SDarrick J. Wong goto out; 2487c4a07a4SDarrick J. Wong if (retval) { 249c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 250afbabf56SDarrick J. Wong goto out; 2517c4a07a4SDarrick J. Wong } 252afbabf56SDarrick J. Wong if (altpath->blk[level].bp) 253afbabf56SDarrick J. Wong xchk_buffer_recheck(ds->sc, altpath->blk[level].bp); 2547c4a07a4SDarrick J. Wong 2557c4a07a4SDarrick J. Wong /* Compare upper level pointer to sibling pointer. */ 256afbabf56SDarrick J. Wong if (altpath->blk[level].blkno != sibling) 257c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 258afbabf56SDarrick J. Wong 2597c4a07a4SDarrick J. Wong out: 260afbabf56SDarrick J. Wong /* Free all buffers in the altpath that aren't referenced from path. */ 261afbabf56SDarrick J. Wong for (plevel = 0; plevel < altpath->active; plevel++) { 262afbabf56SDarrick J. Wong if (altpath->blk[plevel].bp == NULL || 263afbabf56SDarrick J. Wong (plevel < path->active && 264afbabf56SDarrick J. Wong altpath->blk[plevel].bp == path->blk[plevel].bp)) 265afbabf56SDarrick J. Wong continue; 266afbabf56SDarrick J. Wong 267afbabf56SDarrick J. Wong xfs_trans_brelse(ds->dargs.trans, altpath->blk[plevel].bp); 268afbabf56SDarrick J. Wong altpath->blk[plevel].bp = NULL; 269afbabf56SDarrick J. Wong } 270afbabf56SDarrick J. Wong 2717c4a07a4SDarrick J. Wong return error; 2727c4a07a4SDarrick J. Wong } 2737c4a07a4SDarrick J. Wong 2747c4a07a4SDarrick J. Wong /* Check a block's sibling pointers. */ 2757c4a07a4SDarrick J. Wong STATIC int 276c517b3aaSDarrick J. Wong xchk_da_btree_block_check_siblings( 277c517b3aaSDarrick J. Wong struct xchk_da_btree *ds, 2787c4a07a4SDarrick J. Wong int level, 2797c4a07a4SDarrick J. Wong struct xfs_da_blkinfo *hdr) 2807c4a07a4SDarrick J. Wong { 2817c4a07a4SDarrick J. Wong xfs_dablk_t forw; 2827c4a07a4SDarrick J. Wong xfs_dablk_t back; 2837c4a07a4SDarrick J. Wong int error = 0; 2847c4a07a4SDarrick J. Wong 2857c4a07a4SDarrick J. Wong forw = be32_to_cpu(hdr->forw); 2867c4a07a4SDarrick J. Wong back = be32_to_cpu(hdr->back); 2877c4a07a4SDarrick J. Wong 2887c4a07a4SDarrick J. Wong /* Top level blocks should not have sibling pointers. */ 2897c4a07a4SDarrick J. Wong if (level == 0) { 2907c4a07a4SDarrick J. Wong if (forw != 0 || back != 0) 291c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 2927c4a07a4SDarrick J. Wong return 0; 2937c4a07a4SDarrick J. Wong } 2947c4a07a4SDarrick J. Wong 2957c4a07a4SDarrick J. Wong /* 2967c4a07a4SDarrick J. Wong * Check back (left) and forw (right) pointers. These functions 2977c4a07a4SDarrick J. Wong * absorb error codes for us. 2987c4a07a4SDarrick J. Wong */ 299c517b3aaSDarrick J. Wong error = xchk_da_btree_block_check_sibling(ds, level, 0, back); 3007c4a07a4SDarrick J. Wong if (error) 3017c4a07a4SDarrick J. Wong goto out; 302c517b3aaSDarrick J. Wong error = xchk_da_btree_block_check_sibling(ds, level, 1, forw); 3037c4a07a4SDarrick J. Wong 3047c4a07a4SDarrick J. Wong out: 3057c4a07a4SDarrick J. Wong memset(&ds->state->altpath, 0, sizeof(ds->state->altpath)); 3067c4a07a4SDarrick J. Wong return error; 3077c4a07a4SDarrick J. Wong } 3087c4a07a4SDarrick J. Wong 3097c4a07a4SDarrick J. Wong /* Load a dir/attribute block from a btree. */ 3107c4a07a4SDarrick J. Wong STATIC int 311c517b3aaSDarrick J. Wong xchk_da_btree_block( 312c517b3aaSDarrick J. Wong struct xchk_da_btree *ds, 3137c4a07a4SDarrick J. Wong int level, 3147c4a07a4SDarrick J. Wong xfs_dablk_t blkno) 3157c4a07a4SDarrick J. Wong { 3167c4a07a4SDarrick J. Wong struct xfs_da_state_blk *blk; 3177c4a07a4SDarrick J. Wong struct xfs_da_intnode *node; 3187c4a07a4SDarrick J. Wong struct xfs_da_node_entry *btree; 3197c4a07a4SDarrick J. Wong struct xfs_da3_blkinfo *hdr3; 3207c4a07a4SDarrick J. Wong struct xfs_da_args *dargs = &ds->dargs; 3217c4a07a4SDarrick J. Wong struct xfs_inode *ip = ds->dargs.dp; 3227c4a07a4SDarrick J. Wong xfs_ino_t owner; 3237c4a07a4SDarrick J. Wong int *pmaxrecs; 3247c4a07a4SDarrick J. Wong struct xfs_da3_icnode_hdr nodehdr; 3250dca060cSDarrick J. Wong int error = 0; 3267c4a07a4SDarrick J. Wong 3277c4a07a4SDarrick J. Wong blk = &ds->state->path.blk[level]; 3287c4a07a4SDarrick J. Wong ds->state->path.active = level + 1; 3297c4a07a4SDarrick J. Wong 3307c4a07a4SDarrick J. Wong /* Release old block. */ 3317c4a07a4SDarrick J. Wong if (blk->bp) { 3327c4a07a4SDarrick J. Wong xfs_trans_brelse(dargs->trans, blk->bp); 3337c4a07a4SDarrick J. Wong blk->bp = NULL; 3347c4a07a4SDarrick J. Wong } 3357c4a07a4SDarrick J. Wong 3367c4a07a4SDarrick J. Wong /* Check the pointer. */ 3377c4a07a4SDarrick J. Wong blk->blkno = blkno; 338c517b3aaSDarrick J. Wong if (!xchk_da_btree_ptr_ok(ds, level, blkno)) 3397c4a07a4SDarrick J. Wong goto out_nobuf; 3407c4a07a4SDarrick J. Wong 3417c4a07a4SDarrick J. Wong /* Read the buffer. */ 342cd2c9f1bSChristoph Hellwig error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno, 343cd2c9f1bSChristoph Hellwig XFS_DABUF_MAP_HOLE_OK, &blk->bp, dargs->whichfork, 344c517b3aaSDarrick J. Wong &xchk_da_btree_buf_ops); 345c517b3aaSDarrick J. Wong if (!xchk_da_process_error(ds, level, &error)) 3467c4a07a4SDarrick J. Wong goto out_nobuf; 347cf1b0b8bSDarrick J. Wong if (blk->bp) 348c517b3aaSDarrick J. Wong xchk_buffer_recheck(ds->sc, blk->bp); 3497c4a07a4SDarrick J. Wong 3507c4a07a4SDarrick J. Wong /* 3517c4a07a4SDarrick J. Wong * We didn't find a dir btree root block, which means that 3527c4a07a4SDarrick J. Wong * there's no LEAF1/LEAFN tree (at least not where it's supposed 3537c4a07a4SDarrick J. Wong * to be), so jump out now. 3547c4a07a4SDarrick J. Wong */ 3557c4a07a4SDarrick J. Wong if (ds->dargs.whichfork == XFS_DATA_FORK && level == 0 && 3567c4a07a4SDarrick J. Wong blk->bp == NULL) 3577c4a07a4SDarrick J. Wong goto out_nobuf; 3587c4a07a4SDarrick J. Wong 3597c4a07a4SDarrick J. Wong /* It's /not/ ok for attr trees not to have a da btree. */ 3607c4a07a4SDarrick J. Wong if (blk->bp == NULL) { 361c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 3627c4a07a4SDarrick J. Wong goto out_nobuf; 3637c4a07a4SDarrick J. Wong } 3647c4a07a4SDarrick J. Wong 3657c4a07a4SDarrick J. Wong hdr3 = blk->bp->b_addr; 3667c4a07a4SDarrick J. Wong blk->magic = be16_to_cpu(hdr3->hdr.magic); 3677c4a07a4SDarrick J. Wong pmaxrecs = &ds->maxrecs[level]; 3687c4a07a4SDarrick J. Wong 3694da4b10bSDarrick J. Wong /* We only started zeroing the header on v5 filesystems. */ 3704da4b10bSDarrick J. Wong if (xfs_sb_version_hascrc(&ds->sc->mp->m_sb) && hdr3->hdr.pad) 371c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 3727c4a07a4SDarrick J. Wong 3737c4a07a4SDarrick J. Wong /* Check the owner. */ 3747c4a07a4SDarrick J. Wong if (xfs_sb_version_hascrc(&ip->i_mount->m_sb)) { 3757c4a07a4SDarrick J. Wong owner = be64_to_cpu(hdr3->owner); 3767c4a07a4SDarrick J. Wong if (owner != ip->i_ino) 377c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 3787c4a07a4SDarrick J. Wong } 3797c4a07a4SDarrick J. Wong 3807c4a07a4SDarrick J. Wong /* Check the siblings. */ 381c517b3aaSDarrick J. Wong error = xchk_da_btree_block_check_siblings(ds, level, &hdr3->hdr); 3827c4a07a4SDarrick J. Wong if (error) 3837c4a07a4SDarrick J. Wong goto out; 3847c4a07a4SDarrick J. Wong 3857c4a07a4SDarrick J. Wong /* Interpret the buffer. */ 3867c4a07a4SDarrick J. Wong switch (blk->magic) { 3877c4a07a4SDarrick J. Wong case XFS_ATTR_LEAF_MAGIC: 3887c4a07a4SDarrick J. Wong case XFS_ATTR3_LEAF_MAGIC: 3897c4a07a4SDarrick J. Wong xfs_trans_buf_set_type(dargs->trans, blk->bp, 3907c4a07a4SDarrick J. Wong XFS_BLFT_ATTR_LEAF_BUF); 3917c4a07a4SDarrick J. Wong blk->magic = XFS_ATTR_LEAF_MAGIC; 3927c4a07a4SDarrick J. Wong blk->hashval = xfs_attr_leaf_lasthash(blk->bp, pmaxrecs); 3937c4a07a4SDarrick J. Wong if (ds->tree_level != 0) 394c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 3957c4a07a4SDarrick J. Wong break; 3967c4a07a4SDarrick J. Wong case XFS_DIR2_LEAFN_MAGIC: 3977c4a07a4SDarrick J. Wong case XFS_DIR3_LEAFN_MAGIC: 3987c4a07a4SDarrick J. Wong xfs_trans_buf_set_type(dargs->trans, blk->bp, 3997c4a07a4SDarrick J. Wong XFS_BLFT_DIR_LEAFN_BUF); 4007c4a07a4SDarrick J. Wong blk->magic = XFS_DIR2_LEAFN_MAGIC; 4017c4a07a4SDarrick J. Wong blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs); 4027c4a07a4SDarrick J. Wong if (ds->tree_level != 0) 403c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 4047c4a07a4SDarrick J. Wong break; 4057c4a07a4SDarrick J. Wong case XFS_DIR2_LEAF1_MAGIC: 4067c4a07a4SDarrick J. Wong case XFS_DIR3_LEAF1_MAGIC: 4077c4a07a4SDarrick J. Wong xfs_trans_buf_set_type(dargs->trans, blk->bp, 4087c4a07a4SDarrick J. Wong XFS_BLFT_DIR_LEAF1_BUF); 4097c4a07a4SDarrick J. Wong blk->magic = XFS_DIR2_LEAF1_MAGIC; 4107c4a07a4SDarrick J. Wong blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs); 4117c4a07a4SDarrick J. Wong if (ds->tree_level != 0) 412c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 4137c4a07a4SDarrick J. Wong break; 4147c4a07a4SDarrick J. Wong case XFS_DA_NODE_MAGIC: 4157c4a07a4SDarrick J. Wong case XFS_DA3_NODE_MAGIC: 4167c4a07a4SDarrick J. Wong xfs_trans_buf_set_type(dargs->trans, blk->bp, 4177c4a07a4SDarrick J. Wong XFS_BLFT_DA_NODE_BUF); 4187c4a07a4SDarrick J. Wong blk->magic = XFS_DA_NODE_MAGIC; 4197c4a07a4SDarrick J. Wong node = blk->bp->b_addr; 420f475dc4dSChristoph Hellwig xfs_da3_node_hdr_from_disk(ip->i_mount, &nodehdr, node); 42151908ca7SChristoph Hellwig btree = nodehdr.btree; 4227c4a07a4SDarrick J. Wong *pmaxrecs = nodehdr.count; 4237c4a07a4SDarrick J. Wong blk->hashval = be32_to_cpu(btree[*pmaxrecs - 1].hashval); 4247c4a07a4SDarrick J. Wong if (level == 0) { 4257c4a07a4SDarrick J. Wong if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) { 426c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 4277c4a07a4SDarrick J. Wong goto out_freebp; 4287c4a07a4SDarrick J. Wong } 4297c4a07a4SDarrick J. Wong ds->tree_level = nodehdr.level; 4307c4a07a4SDarrick J. Wong } else { 4317c4a07a4SDarrick J. Wong if (ds->tree_level != nodehdr.level) { 432c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 4337c4a07a4SDarrick J. Wong goto out_freebp; 4347c4a07a4SDarrick J. Wong } 4357c4a07a4SDarrick J. Wong } 4367c4a07a4SDarrick J. Wong 4377c4a07a4SDarrick J. Wong /* XXX: Check hdr3.pad32 once we know how to fix it. */ 4387c4a07a4SDarrick J. Wong break; 4397c4a07a4SDarrick J. Wong default: 440c517b3aaSDarrick J. Wong xchk_da_set_corrupt(ds, level); 4417c4a07a4SDarrick J. Wong goto out_freebp; 4427c4a07a4SDarrick J. Wong } 4437c4a07a4SDarrick J. Wong 444*e581c939SDarrick J. Wong /* 445*e581c939SDarrick J. Wong * If we've been handed a block that is below the dabtree root, does 446*e581c939SDarrick J. Wong * its hashval match what the parent block expected to see? 447*e581c939SDarrick J. Wong */ 448*e581c939SDarrick J. Wong if (level > 0) { 449*e581c939SDarrick J. Wong struct xfs_da_node_entry *key; 450*e581c939SDarrick J. Wong 451*e581c939SDarrick J. Wong key = xchk_da_btree_node_entry(ds, level - 1); 452*e581c939SDarrick J. Wong if (be32_to_cpu(key->hashval) != blk->hashval) { 453*e581c939SDarrick J. Wong xchk_da_set_corrupt(ds, level); 454*e581c939SDarrick J. Wong goto out_freebp; 455*e581c939SDarrick J. Wong } 456*e581c939SDarrick J. Wong } 457*e581c939SDarrick J. Wong 4587c4a07a4SDarrick J. Wong out: 4597c4a07a4SDarrick J. Wong return error; 4607c4a07a4SDarrick J. Wong out_freebp: 4617c4a07a4SDarrick J. Wong xfs_trans_brelse(dargs->trans, blk->bp); 4627c4a07a4SDarrick J. Wong blk->bp = NULL; 4637c4a07a4SDarrick J. Wong out_nobuf: 4647c4a07a4SDarrick J. Wong blk->blkno = 0; 4657c4a07a4SDarrick J. Wong return error; 4667c4a07a4SDarrick J. Wong } 4677c4a07a4SDarrick J. Wong 4687c4a07a4SDarrick J. Wong /* Visit all nodes and leaves of a da btree. */ 4697c4a07a4SDarrick J. Wong int 470c517b3aaSDarrick J. Wong xchk_da_btree( 4711d8a748aSDarrick J. Wong struct xfs_scrub *sc, 4727c4a07a4SDarrick J. Wong int whichfork, 473c517b3aaSDarrick J. Wong xchk_da_btree_rec_fn scrub_fn, 47413791d3bSDarrick J. Wong void *private) 4757c4a07a4SDarrick J. Wong { 476c517b3aaSDarrick J. Wong struct xchk_da_btree ds = {}; 4777c4a07a4SDarrick J. Wong struct xfs_mount *mp = sc->mp; 4787c4a07a4SDarrick J. Wong struct xfs_da_state_blk *blks; 4797c4a07a4SDarrick J. Wong struct xfs_da_node_entry *key; 4807c4a07a4SDarrick J. Wong xfs_dablk_t blkno; 4817c4a07a4SDarrick J. Wong int level; 4827c4a07a4SDarrick J. Wong int error; 4837c4a07a4SDarrick J. Wong 4847c4a07a4SDarrick J. Wong /* Skip short format data structures; no btree to scan. */ 485f7e67b20SChristoph Hellwig if (!xfs_ifork_has_extents(XFS_IFORK_PTR(sc->ip, whichfork))) 4867c4a07a4SDarrick J. Wong return 0; 4877c4a07a4SDarrick J. Wong 4887c4a07a4SDarrick J. Wong /* Set up initial da state. */ 4897c4a07a4SDarrick J. Wong ds.dargs.dp = sc->ip; 4907c4a07a4SDarrick J. Wong ds.dargs.whichfork = whichfork; 4917c4a07a4SDarrick J. Wong ds.dargs.trans = sc->tp; 4927c4a07a4SDarrick J. Wong ds.dargs.op_flags = XFS_DA_OP_OKNOENT; 4934491a3ddSCarlos Maiolino ds.state = xfs_da_state_alloc(&ds.dargs); 4947c4a07a4SDarrick J. Wong ds.sc = sc; 49513791d3bSDarrick J. Wong ds.private = private; 4967c4a07a4SDarrick J. Wong if (whichfork == XFS_ATTR_FORK) { 4977c4a07a4SDarrick J. Wong ds.dargs.geo = mp->m_attr_geo; 4987c4a07a4SDarrick J. Wong ds.lowest = 0; 4997c4a07a4SDarrick J. Wong ds.highest = 0; 5007c4a07a4SDarrick J. Wong } else { 5017c4a07a4SDarrick J. Wong ds.dargs.geo = mp->m_dir_geo; 5027c4a07a4SDarrick J. Wong ds.lowest = ds.dargs.geo->leafblk; 5037c4a07a4SDarrick J. Wong ds.highest = ds.dargs.geo->freeblk; 5047c4a07a4SDarrick J. Wong } 5057c4a07a4SDarrick J. Wong blkno = ds.lowest; 5067c4a07a4SDarrick J. Wong level = 0; 5077c4a07a4SDarrick J. Wong 5087c4a07a4SDarrick J. Wong /* Find the root of the da tree, if present. */ 5097c4a07a4SDarrick J. Wong blks = ds.state->path.blk; 510c517b3aaSDarrick J. Wong error = xchk_da_btree_block(&ds, level, blkno); 5117c4a07a4SDarrick J. Wong if (error) 5127c4a07a4SDarrick J. Wong goto out_state; 5137c4a07a4SDarrick J. Wong /* 5147c4a07a4SDarrick J. Wong * We didn't find a block at ds.lowest, which means that there's 5157c4a07a4SDarrick J. Wong * no LEAF1/LEAFN tree (at least not where it's supposed to be), 5167c4a07a4SDarrick J. Wong * so jump out now. 5177c4a07a4SDarrick J. Wong */ 5187c4a07a4SDarrick J. Wong if (blks[level].bp == NULL) 5197c4a07a4SDarrick J. Wong goto out_state; 5207c4a07a4SDarrick J. Wong 5217c4a07a4SDarrick J. Wong blks[level].index = 0; 5227c4a07a4SDarrick J. Wong while (level >= 0 && level < XFS_DA_NODE_MAXDEPTH) { 5237c4a07a4SDarrick J. Wong /* Handle leaf block. */ 5247c4a07a4SDarrick J. Wong if (blks[level].magic != XFS_DA_NODE_MAGIC) { 5257c4a07a4SDarrick J. Wong /* End of leaf, pop back towards the root. */ 5267c4a07a4SDarrick J. Wong if (blks[level].index >= ds.maxrecs[level]) { 5277c4a07a4SDarrick J. Wong if (level > 0) 5287c4a07a4SDarrick J. Wong blks[level - 1].index++; 5297c4a07a4SDarrick J. Wong ds.tree_level++; 5307c4a07a4SDarrick J. Wong level--; 5317c4a07a4SDarrick J. Wong continue; 5327c4a07a4SDarrick J. Wong } 5337c4a07a4SDarrick J. Wong 5347c4a07a4SDarrick J. Wong /* Dispatch record scrubbing. */ 535649d9d98SChristoph Hellwig error = scrub_fn(&ds, level); 5367c4a07a4SDarrick J. Wong if (error) 5377c4a07a4SDarrick J. Wong break; 538c517b3aaSDarrick J. Wong if (xchk_should_terminate(sc, &error) || 5397c4a07a4SDarrick J. Wong (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 5407c4a07a4SDarrick J. Wong break; 5417c4a07a4SDarrick J. Wong 5427c4a07a4SDarrick J. Wong blks[level].index++; 5437c4a07a4SDarrick J. Wong continue; 5447c4a07a4SDarrick J. Wong } 5457c4a07a4SDarrick J. Wong 5467c4a07a4SDarrick J. Wong 5477c4a07a4SDarrick J. Wong /* End of node, pop back towards the root. */ 5487c4a07a4SDarrick J. Wong if (blks[level].index >= ds.maxrecs[level]) { 5497c4a07a4SDarrick J. Wong if (level > 0) 5507c4a07a4SDarrick J. Wong blks[level - 1].index++; 5517c4a07a4SDarrick J. Wong ds.tree_level++; 5527c4a07a4SDarrick J. Wong level--; 5537c4a07a4SDarrick J. Wong continue; 5547c4a07a4SDarrick J. Wong } 5557c4a07a4SDarrick J. Wong 5567c4a07a4SDarrick J. Wong /* Hashes in order for scrub? */ 557649d9d98SChristoph Hellwig key = xchk_da_btree_node_entry(&ds, level); 558c517b3aaSDarrick J. Wong error = xchk_da_btree_hash(&ds, level, &key->hashval); 5597c4a07a4SDarrick J. Wong if (error) 5607c4a07a4SDarrick J. Wong goto out; 5617c4a07a4SDarrick J. Wong 5627c4a07a4SDarrick J. Wong /* Drill another level deeper. */ 5637c4a07a4SDarrick J. Wong blkno = be32_to_cpu(key->before); 5647c4a07a4SDarrick J. Wong level++; 565228de124SDarrick J. Wong if (level >= XFS_DA_NODE_MAXDEPTH) { 566228de124SDarrick J. Wong /* Too deep! */ 567228de124SDarrick J. Wong xchk_da_set_corrupt(&ds, level - 1); 568228de124SDarrick J. Wong break; 569228de124SDarrick J. Wong } 5707c4a07a4SDarrick J. Wong ds.tree_level--; 571c517b3aaSDarrick J. Wong error = xchk_da_btree_block(&ds, level, blkno); 5727c4a07a4SDarrick J. Wong if (error) 5737c4a07a4SDarrick J. Wong goto out; 5747c4a07a4SDarrick J. Wong if (blks[level].bp == NULL) 5757c4a07a4SDarrick J. Wong goto out; 5767c4a07a4SDarrick J. Wong 5777c4a07a4SDarrick J. Wong blks[level].index = 0; 5787c4a07a4SDarrick J. Wong } 5797c4a07a4SDarrick J. Wong 5807c4a07a4SDarrick J. Wong out: 5817c4a07a4SDarrick J. Wong /* Release all the buffers we're tracking. */ 5827c4a07a4SDarrick J. Wong for (level = 0; level < XFS_DA_NODE_MAXDEPTH; level++) { 5837c4a07a4SDarrick J. Wong if (blks[level].bp == NULL) 5847c4a07a4SDarrick J. Wong continue; 5857c4a07a4SDarrick J. Wong xfs_trans_brelse(sc->tp, blks[level].bp); 5867c4a07a4SDarrick J. Wong blks[level].bp = NULL; 5877c4a07a4SDarrick J. Wong } 5887c4a07a4SDarrick J. Wong 5897c4a07a4SDarrick J. Wong out_state: 5907c4a07a4SDarrick J. Wong xfs_da_state_free(ds.state); 5917c4a07a4SDarrick J. Wong return error; 5927c4a07a4SDarrick J. Wong } 593