1*7c4a07a4SDarrick J. Wong /* 2*7c4a07a4SDarrick J. Wong * Copyright (C) 2017 Oracle. All Rights Reserved. 3*7c4a07a4SDarrick J. Wong * 4*7c4a07a4SDarrick J. Wong * Author: Darrick J. Wong <darrick.wong@oracle.com> 5*7c4a07a4SDarrick J. Wong * 6*7c4a07a4SDarrick J. Wong * This program is free software; you can redistribute it and/or 7*7c4a07a4SDarrick J. Wong * modify it under the terms of the GNU General Public License 8*7c4a07a4SDarrick J. Wong * as published by the Free Software Foundation; either version 2 9*7c4a07a4SDarrick J. Wong * of the License, or (at your option) any later version. 10*7c4a07a4SDarrick J. Wong * 11*7c4a07a4SDarrick J. Wong * This program is distributed in the hope that it would be useful, 12*7c4a07a4SDarrick J. Wong * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*7c4a07a4SDarrick J. Wong * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*7c4a07a4SDarrick J. Wong * GNU General Public License for more details. 15*7c4a07a4SDarrick J. Wong * 16*7c4a07a4SDarrick J. Wong * You should have received a copy of the GNU General Public License 17*7c4a07a4SDarrick J. Wong * along with this program; if not, write the Free Software Foundation, 18*7c4a07a4SDarrick J. Wong * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 19*7c4a07a4SDarrick J. Wong */ 20*7c4a07a4SDarrick J. Wong #include "xfs.h" 21*7c4a07a4SDarrick J. Wong #include "xfs_fs.h" 22*7c4a07a4SDarrick J. Wong #include "xfs_shared.h" 23*7c4a07a4SDarrick J. Wong #include "xfs_format.h" 24*7c4a07a4SDarrick J. Wong #include "xfs_trans_resv.h" 25*7c4a07a4SDarrick J. Wong #include "xfs_mount.h" 26*7c4a07a4SDarrick J. Wong #include "xfs_defer.h" 27*7c4a07a4SDarrick J. Wong #include "xfs_btree.h" 28*7c4a07a4SDarrick J. Wong #include "xfs_bit.h" 29*7c4a07a4SDarrick J. Wong #include "xfs_log_format.h" 30*7c4a07a4SDarrick J. Wong #include "xfs_trans.h" 31*7c4a07a4SDarrick J. Wong #include "xfs_sb.h" 32*7c4a07a4SDarrick J. Wong #include "xfs_inode.h" 33*7c4a07a4SDarrick J. Wong #include "xfs_inode_fork.h" 34*7c4a07a4SDarrick J. Wong #include "xfs_da_format.h" 35*7c4a07a4SDarrick J. Wong #include "xfs_da_btree.h" 36*7c4a07a4SDarrick J. Wong #include "xfs_dir2.h" 37*7c4a07a4SDarrick J. Wong #include "xfs_dir2_priv.h" 38*7c4a07a4SDarrick J. Wong #include "xfs_attr_leaf.h" 39*7c4a07a4SDarrick J. Wong #include "scrub/xfs_scrub.h" 40*7c4a07a4SDarrick J. Wong #include "scrub/scrub.h" 41*7c4a07a4SDarrick J. Wong #include "scrub/common.h" 42*7c4a07a4SDarrick J. Wong #include "scrub/trace.h" 43*7c4a07a4SDarrick J. Wong #include "scrub/dabtree.h" 44*7c4a07a4SDarrick J. Wong 45*7c4a07a4SDarrick J. Wong /* Directory/Attribute Btree */ 46*7c4a07a4SDarrick J. Wong 47*7c4a07a4SDarrick J. Wong /* 48*7c4a07a4SDarrick J. Wong * Check for da btree operation errors. See the section about handling 49*7c4a07a4SDarrick J. Wong * operational errors in common.c. 50*7c4a07a4SDarrick J. Wong */ 51*7c4a07a4SDarrick J. Wong bool 52*7c4a07a4SDarrick J. Wong xfs_scrub_da_process_error( 53*7c4a07a4SDarrick J. Wong struct xfs_scrub_da_btree *ds, 54*7c4a07a4SDarrick J. Wong int level, 55*7c4a07a4SDarrick J. Wong int *error) 56*7c4a07a4SDarrick J. Wong { 57*7c4a07a4SDarrick J. Wong struct xfs_scrub_context *sc = ds->sc; 58*7c4a07a4SDarrick J. Wong 59*7c4a07a4SDarrick J. Wong if (*error == 0) 60*7c4a07a4SDarrick J. Wong return true; 61*7c4a07a4SDarrick J. Wong 62*7c4a07a4SDarrick J. Wong switch (*error) { 63*7c4a07a4SDarrick J. Wong case -EDEADLOCK: 64*7c4a07a4SDarrick J. Wong /* Used to restart an op with deadlock avoidance. */ 65*7c4a07a4SDarrick J. Wong trace_xfs_scrub_deadlock_retry(sc->ip, sc->sm, *error); 66*7c4a07a4SDarrick J. Wong break; 67*7c4a07a4SDarrick J. Wong case -EFSBADCRC: 68*7c4a07a4SDarrick J. Wong case -EFSCORRUPTED: 69*7c4a07a4SDarrick J. Wong /* Note the badness but don't abort. */ 70*7c4a07a4SDarrick J. Wong sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT; 71*7c4a07a4SDarrick J. Wong *error = 0; 72*7c4a07a4SDarrick J. Wong /* fall through */ 73*7c4a07a4SDarrick J. Wong default: 74*7c4a07a4SDarrick J. Wong trace_xfs_scrub_file_op_error(sc, ds->dargs.whichfork, 75*7c4a07a4SDarrick J. Wong xfs_dir2_da_to_db(ds->dargs.geo, 76*7c4a07a4SDarrick J. Wong ds->state->path.blk[level].blkno), 77*7c4a07a4SDarrick J. Wong *error, __return_address); 78*7c4a07a4SDarrick J. Wong break; 79*7c4a07a4SDarrick J. Wong } 80*7c4a07a4SDarrick J. Wong return false; 81*7c4a07a4SDarrick J. Wong } 82*7c4a07a4SDarrick J. Wong 83*7c4a07a4SDarrick J. Wong /* 84*7c4a07a4SDarrick J. Wong * Check for da btree corruption. See the section about handling 85*7c4a07a4SDarrick J. Wong * operational errors in common.c. 86*7c4a07a4SDarrick J. Wong */ 87*7c4a07a4SDarrick J. Wong void 88*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt( 89*7c4a07a4SDarrick J. Wong struct xfs_scrub_da_btree *ds, 90*7c4a07a4SDarrick J. Wong int level) 91*7c4a07a4SDarrick J. Wong { 92*7c4a07a4SDarrick J. Wong struct xfs_scrub_context *sc = ds->sc; 93*7c4a07a4SDarrick J. Wong 94*7c4a07a4SDarrick J. Wong sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT; 95*7c4a07a4SDarrick J. Wong 96*7c4a07a4SDarrick J. Wong trace_xfs_scrub_fblock_error(sc, ds->dargs.whichfork, 97*7c4a07a4SDarrick J. Wong xfs_dir2_da_to_db(ds->dargs.geo, 98*7c4a07a4SDarrick J. Wong ds->state->path.blk[level].blkno), 99*7c4a07a4SDarrick J. Wong __return_address); 100*7c4a07a4SDarrick J. Wong } 101*7c4a07a4SDarrick J. Wong 102*7c4a07a4SDarrick J. Wong /* Find an entry at a certain level in a da btree. */ 103*7c4a07a4SDarrick J. Wong STATIC void * 104*7c4a07a4SDarrick J. Wong xfs_scrub_da_btree_entry( 105*7c4a07a4SDarrick J. Wong struct xfs_scrub_da_btree *ds, 106*7c4a07a4SDarrick J. Wong int level, 107*7c4a07a4SDarrick J. Wong int rec) 108*7c4a07a4SDarrick J. Wong { 109*7c4a07a4SDarrick J. Wong char *ents; 110*7c4a07a4SDarrick J. Wong struct xfs_da_state_blk *blk; 111*7c4a07a4SDarrick J. Wong void *baddr; 112*7c4a07a4SDarrick J. Wong 113*7c4a07a4SDarrick J. Wong /* Dispatch the entry finding function. */ 114*7c4a07a4SDarrick J. Wong blk = &ds->state->path.blk[level]; 115*7c4a07a4SDarrick J. Wong baddr = blk->bp->b_addr; 116*7c4a07a4SDarrick J. Wong switch (blk->magic) { 117*7c4a07a4SDarrick J. Wong case XFS_ATTR_LEAF_MAGIC: 118*7c4a07a4SDarrick J. Wong case XFS_ATTR3_LEAF_MAGIC: 119*7c4a07a4SDarrick J. Wong ents = (char *)xfs_attr3_leaf_entryp(baddr); 120*7c4a07a4SDarrick J. Wong return ents + (rec * sizeof(struct xfs_attr_leaf_entry)); 121*7c4a07a4SDarrick J. Wong case XFS_DIR2_LEAFN_MAGIC: 122*7c4a07a4SDarrick J. Wong case XFS_DIR3_LEAFN_MAGIC: 123*7c4a07a4SDarrick J. Wong ents = (char *)ds->dargs.dp->d_ops->leaf_ents_p(baddr); 124*7c4a07a4SDarrick J. Wong return ents + (rec * sizeof(struct xfs_dir2_leaf_entry)); 125*7c4a07a4SDarrick J. Wong case XFS_DIR2_LEAF1_MAGIC: 126*7c4a07a4SDarrick J. Wong case XFS_DIR3_LEAF1_MAGIC: 127*7c4a07a4SDarrick J. Wong ents = (char *)ds->dargs.dp->d_ops->leaf_ents_p(baddr); 128*7c4a07a4SDarrick J. Wong return ents + (rec * sizeof(struct xfs_dir2_leaf_entry)); 129*7c4a07a4SDarrick J. Wong case XFS_DA_NODE_MAGIC: 130*7c4a07a4SDarrick J. Wong case XFS_DA3_NODE_MAGIC: 131*7c4a07a4SDarrick J. Wong ents = (char *)ds->dargs.dp->d_ops->node_tree_p(baddr); 132*7c4a07a4SDarrick J. Wong return ents + (rec * sizeof(struct xfs_da_node_entry)); 133*7c4a07a4SDarrick J. Wong } 134*7c4a07a4SDarrick J. Wong 135*7c4a07a4SDarrick J. Wong return NULL; 136*7c4a07a4SDarrick J. Wong } 137*7c4a07a4SDarrick J. Wong 138*7c4a07a4SDarrick J. Wong /* Scrub a da btree hash (key). */ 139*7c4a07a4SDarrick J. Wong int 140*7c4a07a4SDarrick J. Wong xfs_scrub_da_btree_hash( 141*7c4a07a4SDarrick J. Wong struct xfs_scrub_da_btree *ds, 142*7c4a07a4SDarrick J. Wong int level, 143*7c4a07a4SDarrick J. Wong __be32 *hashp) 144*7c4a07a4SDarrick J. Wong { 145*7c4a07a4SDarrick J. Wong struct xfs_da_state_blk *blks; 146*7c4a07a4SDarrick J. Wong struct xfs_da_node_entry *entry; 147*7c4a07a4SDarrick J. Wong xfs_dahash_t hash; 148*7c4a07a4SDarrick J. Wong xfs_dahash_t parent_hash; 149*7c4a07a4SDarrick J. Wong 150*7c4a07a4SDarrick J. Wong /* Is this hash in order? */ 151*7c4a07a4SDarrick J. Wong hash = be32_to_cpu(*hashp); 152*7c4a07a4SDarrick J. Wong if (hash < ds->hashes[level]) 153*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 154*7c4a07a4SDarrick J. Wong ds->hashes[level] = hash; 155*7c4a07a4SDarrick J. Wong 156*7c4a07a4SDarrick J. Wong if (level == 0) 157*7c4a07a4SDarrick J. Wong return 0; 158*7c4a07a4SDarrick J. Wong 159*7c4a07a4SDarrick J. Wong /* Is this hash no larger than the parent hash? */ 160*7c4a07a4SDarrick J. Wong blks = ds->state->path.blk; 161*7c4a07a4SDarrick J. Wong entry = xfs_scrub_da_btree_entry(ds, level - 1, blks[level - 1].index); 162*7c4a07a4SDarrick J. Wong parent_hash = be32_to_cpu(entry->hashval); 163*7c4a07a4SDarrick J. Wong if (parent_hash < hash) 164*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 165*7c4a07a4SDarrick J. Wong 166*7c4a07a4SDarrick J. Wong return 0; 167*7c4a07a4SDarrick J. Wong } 168*7c4a07a4SDarrick J. Wong 169*7c4a07a4SDarrick J. Wong /* 170*7c4a07a4SDarrick J. Wong * Check a da btree pointer. Returns true if it's ok to use this 171*7c4a07a4SDarrick J. Wong * pointer. 172*7c4a07a4SDarrick J. Wong */ 173*7c4a07a4SDarrick J. Wong STATIC bool 174*7c4a07a4SDarrick J. Wong xfs_scrub_da_btree_ptr_ok( 175*7c4a07a4SDarrick J. Wong struct xfs_scrub_da_btree *ds, 176*7c4a07a4SDarrick J. Wong int level, 177*7c4a07a4SDarrick J. Wong xfs_dablk_t blkno) 178*7c4a07a4SDarrick J. Wong { 179*7c4a07a4SDarrick J. Wong if (blkno < ds->lowest || (ds->highest != 0 && blkno >= ds->highest)) { 180*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 181*7c4a07a4SDarrick J. Wong return false; 182*7c4a07a4SDarrick J. Wong } 183*7c4a07a4SDarrick J. Wong 184*7c4a07a4SDarrick J. Wong return true; 185*7c4a07a4SDarrick J. Wong } 186*7c4a07a4SDarrick J. Wong 187*7c4a07a4SDarrick J. Wong /* 188*7c4a07a4SDarrick J. Wong * The da btree scrubber can handle leaf1 blocks as a degenerate 189*7c4a07a4SDarrick J. Wong * form of leafn blocks. Since the regular da code doesn't handle 190*7c4a07a4SDarrick J. Wong * leaf1, we must multiplex the verifiers. 191*7c4a07a4SDarrick J. Wong */ 192*7c4a07a4SDarrick J. Wong static void 193*7c4a07a4SDarrick J. Wong xfs_scrub_da_btree_read_verify( 194*7c4a07a4SDarrick J. Wong struct xfs_buf *bp) 195*7c4a07a4SDarrick J. Wong { 196*7c4a07a4SDarrick J. Wong struct xfs_da_blkinfo *info = bp->b_addr; 197*7c4a07a4SDarrick J. Wong 198*7c4a07a4SDarrick J. Wong switch (be16_to_cpu(info->magic)) { 199*7c4a07a4SDarrick J. Wong case XFS_DIR2_LEAF1_MAGIC: 200*7c4a07a4SDarrick J. Wong case XFS_DIR3_LEAF1_MAGIC: 201*7c4a07a4SDarrick J. Wong bp->b_ops = &xfs_dir3_leaf1_buf_ops; 202*7c4a07a4SDarrick J. Wong bp->b_ops->verify_read(bp); 203*7c4a07a4SDarrick J. Wong return; 204*7c4a07a4SDarrick J. Wong default: 205*7c4a07a4SDarrick J. Wong /* 206*7c4a07a4SDarrick J. Wong * xfs_da3_node_buf_ops already know how to handle 207*7c4a07a4SDarrick J. Wong * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks. 208*7c4a07a4SDarrick J. Wong */ 209*7c4a07a4SDarrick J. Wong bp->b_ops = &xfs_da3_node_buf_ops; 210*7c4a07a4SDarrick J. Wong bp->b_ops->verify_read(bp); 211*7c4a07a4SDarrick J. Wong return; 212*7c4a07a4SDarrick J. Wong } 213*7c4a07a4SDarrick J. Wong } 214*7c4a07a4SDarrick J. Wong static void 215*7c4a07a4SDarrick J. Wong xfs_scrub_da_btree_write_verify( 216*7c4a07a4SDarrick J. Wong struct xfs_buf *bp) 217*7c4a07a4SDarrick J. Wong { 218*7c4a07a4SDarrick J. Wong struct xfs_da_blkinfo *info = bp->b_addr; 219*7c4a07a4SDarrick J. Wong 220*7c4a07a4SDarrick J. Wong switch (be16_to_cpu(info->magic)) { 221*7c4a07a4SDarrick J. Wong case XFS_DIR2_LEAF1_MAGIC: 222*7c4a07a4SDarrick J. Wong case XFS_DIR3_LEAF1_MAGIC: 223*7c4a07a4SDarrick J. Wong bp->b_ops = &xfs_dir3_leaf1_buf_ops; 224*7c4a07a4SDarrick J. Wong bp->b_ops->verify_write(bp); 225*7c4a07a4SDarrick J. Wong return; 226*7c4a07a4SDarrick J. Wong default: 227*7c4a07a4SDarrick J. Wong /* 228*7c4a07a4SDarrick J. Wong * xfs_da3_node_buf_ops already know how to handle 229*7c4a07a4SDarrick J. Wong * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks. 230*7c4a07a4SDarrick J. Wong */ 231*7c4a07a4SDarrick J. Wong bp->b_ops = &xfs_da3_node_buf_ops; 232*7c4a07a4SDarrick J. Wong bp->b_ops->verify_write(bp); 233*7c4a07a4SDarrick J. Wong return; 234*7c4a07a4SDarrick J. Wong } 235*7c4a07a4SDarrick J. Wong } 236*7c4a07a4SDarrick J. Wong 237*7c4a07a4SDarrick J. Wong static const struct xfs_buf_ops xfs_scrub_da_btree_buf_ops = { 238*7c4a07a4SDarrick J. Wong .name = "xfs_scrub_da_btree", 239*7c4a07a4SDarrick J. Wong .verify_read = xfs_scrub_da_btree_read_verify, 240*7c4a07a4SDarrick J. Wong .verify_write = xfs_scrub_da_btree_write_verify, 241*7c4a07a4SDarrick J. Wong }; 242*7c4a07a4SDarrick J. Wong 243*7c4a07a4SDarrick J. Wong /* Check a block's sibling. */ 244*7c4a07a4SDarrick J. Wong STATIC int 245*7c4a07a4SDarrick J. Wong xfs_scrub_da_btree_block_check_sibling( 246*7c4a07a4SDarrick J. Wong struct xfs_scrub_da_btree *ds, 247*7c4a07a4SDarrick J. Wong int level, 248*7c4a07a4SDarrick J. Wong int direction, 249*7c4a07a4SDarrick J. Wong xfs_dablk_t sibling) 250*7c4a07a4SDarrick J. Wong { 251*7c4a07a4SDarrick J. Wong int retval; 252*7c4a07a4SDarrick J. Wong int error; 253*7c4a07a4SDarrick J. Wong 254*7c4a07a4SDarrick J. Wong memcpy(&ds->state->altpath, &ds->state->path, 255*7c4a07a4SDarrick J. Wong sizeof(ds->state->altpath)); 256*7c4a07a4SDarrick J. Wong 257*7c4a07a4SDarrick J. Wong /* 258*7c4a07a4SDarrick J. Wong * If the pointer is null, we shouldn't be able to move the upper 259*7c4a07a4SDarrick J. Wong * level pointer anywhere. 260*7c4a07a4SDarrick J. Wong */ 261*7c4a07a4SDarrick J. Wong if (sibling == 0) { 262*7c4a07a4SDarrick J. Wong error = xfs_da3_path_shift(ds->state, &ds->state->altpath, 263*7c4a07a4SDarrick J. Wong direction, false, &retval); 264*7c4a07a4SDarrick J. Wong if (error == 0 && retval == 0) 265*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 266*7c4a07a4SDarrick J. Wong error = 0; 267*7c4a07a4SDarrick J. Wong goto out; 268*7c4a07a4SDarrick J. Wong } 269*7c4a07a4SDarrick J. Wong 270*7c4a07a4SDarrick J. Wong /* Move the alternate cursor one block in the direction given. */ 271*7c4a07a4SDarrick J. Wong error = xfs_da3_path_shift(ds->state, &ds->state->altpath, 272*7c4a07a4SDarrick J. Wong direction, false, &retval); 273*7c4a07a4SDarrick J. Wong if (!xfs_scrub_da_process_error(ds, level, &error)) 274*7c4a07a4SDarrick J. Wong return error; 275*7c4a07a4SDarrick J. Wong if (retval) { 276*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 277*7c4a07a4SDarrick J. Wong return error; 278*7c4a07a4SDarrick J. Wong } 279*7c4a07a4SDarrick J. Wong 280*7c4a07a4SDarrick J. Wong /* Compare upper level pointer to sibling pointer. */ 281*7c4a07a4SDarrick J. Wong if (ds->state->altpath.blk[level].blkno != sibling) 282*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 283*7c4a07a4SDarrick J. Wong xfs_trans_brelse(ds->dargs.trans, ds->state->altpath.blk[level].bp); 284*7c4a07a4SDarrick J. Wong out: 285*7c4a07a4SDarrick J. Wong return error; 286*7c4a07a4SDarrick J. Wong } 287*7c4a07a4SDarrick J. Wong 288*7c4a07a4SDarrick J. Wong /* Check a block's sibling pointers. */ 289*7c4a07a4SDarrick J. Wong STATIC int 290*7c4a07a4SDarrick J. Wong xfs_scrub_da_btree_block_check_siblings( 291*7c4a07a4SDarrick J. Wong struct xfs_scrub_da_btree *ds, 292*7c4a07a4SDarrick J. Wong int level, 293*7c4a07a4SDarrick J. Wong struct xfs_da_blkinfo *hdr) 294*7c4a07a4SDarrick J. Wong { 295*7c4a07a4SDarrick J. Wong xfs_dablk_t forw; 296*7c4a07a4SDarrick J. Wong xfs_dablk_t back; 297*7c4a07a4SDarrick J. Wong int error = 0; 298*7c4a07a4SDarrick J. Wong 299*7c4a07a4SDarrick J. Wong forw = be32_to_cpu(hdr->forw); 300*7c4a07a4SDarrick J. Wong back = be32_to_cpu(hdr->back); 301*7c4a07a4SDarrick J. Wong 302*7c4a07a4SDarrick J. Wong /* Top level blocks should not have sibling pointers. */ 303*7c4a07a4SDarrick J. Wong if (level == 0) { 304*7c4a07a4SDarrick J. Wong if (forw != 0 || back != 0) 305*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 306*7c4a07a4SDarrick J. Wong return 0; 307*7c4a07a4SDarrick J. Wong } 308*7c4a07a4SDarrick J. Wong 309*7c4a07a4SDarrick J. Wong /* 310*7c4a07a4SDarrick J. Wong * Check back (left) and forw (right) pointers. These functions 311*7c4a07a4SDarrick J. Wong * absorb error codes for us. 312*7c4a07a4SDarrick J. Wong */ 313*7c4a07a4SDarrick J. Wong error = xfs_scrub_da_btree_block_check_sibling(ds, level, 0, back); 314*7c4a07a4SDarrick J. Wong if (error) 315*7c4a07a4SDarrick J. Wong goto out; 316*7c4a07a4SDarrick J. Wong error = xfs_scrub_da_btree_block_check_sibling(ds, level, 1, forw); 317*7c4a07a4SDarrick J. Wong 318*7c4a07a4SDarrick J. Wong out: 319*7c4a07a4SDarrick J. Wong memset(&ds->state->altpath, 0, sizeof(ds->state->altpath)); 320*7c4a07a4SDarrick J. Wong return error; 321*7c4a07a4SDarrick J. Wong } 322*7c4a07a4SDarrick J. Wong 323*7c4a07a4SDarrick J. Wong /* Load a dir/attribute block from a btree. */ 324*7c4a07a4SDarrick J. Wong STATIC int 325*7c4a07a4SDarrick J. Wong xfs_scrub_da_btree_block( 326*7c4a07a4SDarrick J. Wong struct xfs_scrub_da_btree *ds, 327*7c4a07a4SDarrick J. Wong int level, 328*7c4a07a4SDarrick J. Wong xfs_dablk_t blkno) 329*7c4a07a4SDarrick J. Wong { 330*7c4a07a4SDarrick J. Wong struct xfs_da_state_blk *blk; 331*7c4a07a4SDarrick J. Wong struct xfs_da_intnode *node; 332*7c4a07a4SDarrick J. Wong struct xfs_da_node_entry *btree; 333*7c4a07a4SDarrick J. Wong struct xfs_da3_blkinfo *hdr3; 334*7c4a07a4SDarrick J. Wong struct xfs_da_args *dargs = &ds->dargs; 335*7c4a07a4SDarrick J. Wong struct xfs_inode *ip = ds->dargs.dp; 336*7c4a07a4SDarrick J. Wong xfs_ino_t owner; 337*7c4a07a4SDarrick J. Wong int *pmaxrecs; 338*7c4a07a4SDarrick J. Wong struct xfs_da3_icnode_hdr nodehdr; 339*7c4a07a4SDarrick J. Wong int error; 340*7c4a07a4SDarrick J. Wong 341*7c4a07a4SDarrick J. Wong blk = &ds->state->path.blk[level]; 342*7c4a07a4SDarrick J. Wong ds->state->path.active = level + 1; 343*7c4a07a4SDarrick J. Wong 344*7c4a07a4SDarrick J. Wong /* Release old block. */ 345*7c4a07a4SDarrick J. Wong if (blk->bp) { 346*7c4a07a4SDarrick J. Wong xfs_trans_brelse(dargs->trans, blk->bp); 347*7c4a07a4SDarrick J. Wong blk->bp = NULL; 348*7c4a07a4SDarrick J. Wong } 349*7c4a07a4SDarrick J. Wong 350*7c4a07a4SDarrick J. Wong /* Check the pointer. */ 351*7c4a07a4SDarrick J. Wong blk->blkno = blkno; 352*7c4a07a4SDarrick J. Wong if (!xfs_scrub_da_btree_ptr_ok(ds, level, blkno)) 353*7c4a07a4SDarrick J. Wong goto out_nobuf; 354*7c4a07a4SDarrick J. Wong 355*7c4a07a4SDarrick J. Wong /* Read the buffer. */ 356*7c4a07a4SDarrick J. Wong error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno, -2, 357*7c4a07a4SDarrick J. Wong &blk->bp, dargs->whichfork, 358*7c4a07a4SDarrick J. Wong &xfs_scrub_da_btree_buf_ops); 359*7c4a07a4SDarrick J. Wong if (!xfs_scrub_da_process_error(ds, level, &error)) 360*7c4a07a4SDarrick J. Wong goto out_nobuf; 361*7c4a07a4SDarrick J. Wong 362*7c4a07a4SDarrick J. Wong /* 363*7c4a07a4SDarrick J. Wong * We didn't find a dir btree root block, which means that 364*7c4a07a4SDarrick J. Wong * there's no LEAF1/LEAFN tree (at least not where it's supposed 365*7c4a07a4SDarrick J. Wong * to be), so jump out now. 366*7c4a07a4SDarrick J. Wong */ 367*7c4a07a4SDarrick J. Wong if (ds->dargs.whichfork == XFS_DATA_FORK && level == 0 && 368*7c4a07a4SDarrick J. Wong blk->bp == NULL) 369*7c4a07a4SDarrick J. Wong goto out_nobuf; 370*7c4a07a4SDarrick J. Wong 371*7c4a07a4SDarrick J. Wong /* It's /not/ ok for attr trees not to have a da btree. */ 372*7c4a07a4SDarrick J. Wong if (blk->bp == NULL) { 373*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 374*7c4a07a4SDarrick J. Wong goto out_nobuf; 375*7c4a07a4SDarrick J. Wong } 376*7c4a07a4SDarrick J. Wong 377*7c4a07a4SDarrick J. Wong hdr3 = blk->bp->b_addr; 378*7c4a07a4SDarrick J. Wong blk->magic = be16_to_cpu(hdr3->hdr.magic); 379*7c4a07a4SDarrick J. Wong pmaxrecs = &ds->maxrecs[level]; 380*7c4a07a4SDarrick J. Wong 381*7c4a07a4SDarrick J. Wong if (hdr3->hdr.pad != cpu_to_be16(0)) 382*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 383*7c4a07a4SDarrick J. Wong 384*7c4a07a4SDarrick J. Wong /* Check the owner. */ 385*7c4a07a4SDarrick J. Wong if (xfs_sb_version_hascrc(&ip->i_mount->m_sb)) { 386*7c4a07a4SDarrick J. Wong owner = be64_to_cpu(hdr3->owner); 387*7c4a07a4SDarrick J. Wong if (owner != ip->i_ino) 388*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 389*7c4a07a4SDarrick J. Wong } 390*7c4a07a4SDarrick J. Wong 391*7c4a07a4SDarrick J. Wong /* Check the siblings. */ 392*7c4a07a4SDarrick J. Wong error = xfs_scrub_da_btree_block_check_siblings(ds, level, &hdr3->hdr); 393*7c4a07a4SDarrick J. Wong if (error) 394*7c4a07a4SDarrick J. Wong goto out; 395*7c4a07a4SDarrick J. Wong 396*7c4a07a4SDarrick J. Wong /* Interpret the buffer. */ 397*7c4a07a4SDarrick J. Wong switch (blk->magic) { 398*7c4a07a4SDarrick J. Wong case XFS_ATTR_LEAF_MAGIC: 399*7c4a07a4SDarrick J. Wong case XFS_ATTR3_LEAF_MAGIC: 400*7c4a07a4SDarrick J. Wong xfs_trans_buf_set_type(dargs->trans, blk->bp, 401*7c4a07a4SDarrick J. Wong XFS_BLFT_ATTR_LEAF_BUF); 402*7c4a07a4SDarrick J. Wong blk->magic = XFS_ATTR_LEAF_MAGIC; 403*7c4a07a4SDarrick J. Wong blk->hashval = xfs_attr_leaf_lasthash(blk->bp, pmaxrecs); 404*7c4a07a4SDarrick J. Wong if (ds->tree_level != 0) 405*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 406*7c4a07a4SDarrick J. Wong break; 407*7c4a07a4SDarrick J. Wong case XFS_DIR2_LEAFN_MAGIC: 408*7c4a07a4SDarrick J. Wong case XFS_DIR3_LEAFN_MAGIC: 409*7c4a07a4SDarrick J. Wong xfs_trans_buf_set_type(dargs->trans, blk->bp, 410*7c4a07a4SDarrick J. Wong XFS_BLFT_DIR_LEAFN_BUF); 411*7c4a07a4SDarrick J. Wong blk->magic = XFS_DIR2_LEAFN_MAGIC; 412*7c4a07a4SDarrick J. Wong blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs); 413*7c4a07a4SDarrick J. Wong if (ds->tree_level != 0) 414*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 415*7c4a07a4SDarrick J. Wong break; 416*7c4a07a4SDarrick J. Wong case XFS_DIR2_LEAF1_MAGIC: 417*7c4a07a4SDarrick J. Wong case XFS_DIR3_LEAF1_MAGIC: 418*7c4a07a4SDarrick J. Wong xfs_trans_buf_set_type(dargs->trans, blk->bp, 419*7c4a07a4SDarrick J. Wong XFS_BLFT_DIR_LEAF1_BUF); 420*7c4a07a4SDarrick J. Wong blk->magic = XFS_DIR2_LEAF1_MAGIC; 421*7c4a07a4SDarrick J. Wong blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs); 422*7c4a07a4SDarrick J. Wong if (ds->tree_level != 0) 423*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 424*7c4a07a4SDarrick J. Wong break; 425*7c4a07a4SDarrick J. Wong case XFS_DA_NODE_MAGIC: 426*7c4a07a4SDarrick J. Wong case XFS_DA3_NODE_MAGIC: 427*7c4a07a4SDarrick J. Wong xfs_trans_buf_set_type(dargs->trans, blk->bp, 428*7c4a07a4SDarrick J. Wong XFS_BLFT_DA_NODE_BUF); 429*7c4a07a4SDarrick J. Wong blk->magic = XFS_DA_NODE_MAGIC; 430*7c4a07a4SDarrick J. Wong node = blk->bp->b_addr; 431*7c4a07a4SDarrick J. Wong ip->d_ops->node_hdr_from_disk(&nodehdr, node); 432*7c4a07a4SDarrick J. Wong btree = ip->d_ops->node_tree_p(node); 433*7c4a07a4SDarrick J. Wong *pmaxrecs = nodehdr.count; 434*7c4a07a4SDarrick J. Wong blk->hashval = be32_to_cpu(btree[*pmaxrecs - 1].hashval); 435*7c4a07a4SDarrick J. Wong if (level == 0) { 436*7c4a07a4SDarrick J. Wong if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) { 437*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 438*7c4a07a4SDarrick J. Wong goto out_freebp; 439*7c4a07a4SDarrick J. Wong } 440*7c4a07a4SDarrick J. Wong ds->tree_level = nodehdr.level; 441*7c4a07a4SDarrick J. Wong } else { 442*7c4a07a4SDarrick J. Wong if (ds->tree_level != nodehdr.level) { 443*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 444*7c4a07a4SDarrick J. Wong goto out_freebp; 445*7c4a07a4SDarrick J. Wong } 446*7c4a07a4SDarrick J. Wong } 447*7c4a07a4SDarrick J. Wong 448*7c4a07a4SDarrick J. Wong /* XXX: Check hdr3.pad32 once we know how to fix it. */ 449*7c4a07a4SDarrick J. Wong break; 450*7c4a07a4SDarrick J. Wong default: 451*7c4a07a4SDarrick J. Wong xfs_scrub_da_set_corrupt(ds, level); 452*7c4a07a4SDarrick J. Wong goto out_freebp; 453*7c4a07a4SDarrick J. Wong } 454*7c4a07a4SDarrick J. Wong 455*7c4a07a4SDarrick J. Wong out: 456*7c4a07a4SDarrick J. Wong return error; 457*7c4a07a4SDarrick J. Wong out_freebp: 458*7c4a07a4SDarrick J. Wong xfs_trans_brelse(dargs->trans, blk->bp); 459*7c4a07a4SDarrick J. Wong blk->bp = NULL; 460*7c4a07a4SDarrick J. Wong out_nobuf: 461*7c4a07a4SDarrick J. Wong blk->blkno = 0; 462*7c4a07a4SDarrick J. Wong return error; 463*7c4a07a4SDarrick J. Wong } 464*7c4a07a4SDarrick J. Wong 465*7c4a07a4SDarrick J. Wong /* Visit all nodes and leaves of a da btree. */ 466*7c4a07a4SDarrick J. Wong int 467*7c4a07a4SDarrick J. Wong xfs_scrub_da_btree( 468*7c4a07a4SDarrick J. Wong struct xfs_scrub_context *sc, 469*7c4a07a4SDarrick J. Wong int whichfork, 470*7c4a07a4SDarrick J. Wong xfs_scrub_da_btree_rec_fn scrub_fn) 471*7c4a07a4SDarrick J. Wong { 472*7c4a07a4SDarrick J. Wong struct xfs_scrub_da_btree ds = {}; 473*7c4a07a4SDarrick J. Wong struct xfs_mount *mp = sc->mp; 474*7c4a07a4SDarrick J. Wong struct xfs_da_state_blk *blks; 475*7c4a07a4SDarrick J. Wong struct xfs_da_node_entry *key; 476*7c4a07a4SDarrick J. Wong void *rec; 477*7c4a07a4SDarrick J. Wong xfs_dablk_t blkno; 478*7c4a07a4SDarrick J. Wong int level; 479*7c4a07a4SDarrick J. Wong int error; 480*7c4a07a4SDarrick J. Wong 481*7c4a07a4SDarrick J. Wong /* Skip short format data structures; no btree to scan. */ 482*7c4a07a4SDarrick J. Wong if (XFS_IFORK_FORMAT(sc->ip, whichfork) != XFS_DINODE_FMT_EXTENTS && 483*7c4a07a4SDarrick J. Wong XFS_IFORK_FORMAT(sc->ip, whichfork) != XFS_DINODE_FMT_BTREE) 484*7c4a07a4SDarrick J. Wong return 0; 485*7c4a07a4SDarrick J. Wong 486*7c4a07a4SDarrick J. Wong /* Set up initial da state. */ 487*7c4a07a4SDarrick J. Wong ds.dargs.dp = sc->ip; 488*7c4a07a4SDarrick J. Wong ds.dargs.whichfork = whichfork; 489*7c4a07a4SDarrick J. Wong ds.dargs.trans = sc->tp; 490*7c4a07a4SDarrick J. Wong ds.dargs.op_flags = XFS_DA_OP_OKNOENT; 491*7c4a07a4SDarrick J. Wong ds.state = xfs_da_state_alloc(); 492*7c4a07a4SDarrick J. Wong ds.state->args = &ds.dargs; 493*7c4a07a4SDarrick J. Wong ds.state->mp = mp; 494*7c4a07a4SDarrick J. Wong ds.sc = sc; 495*7c4a07a4SDarrick J. Wong if (whichfork == XFS_ATTR_FORK) { 496*7c4a07a4SDarrick J. Wong ds.dargs.geo = mp->m_attr_geo; 497*7c4a07a4SDarrick J. Wong ds.lowest = 0; 498*7c4a07a4SDarrick J. Wong ds.highest = 0; 499*7c4a07a4SDarrick J. Wong } else { 500*7c4a07a4SDarrick J. Wong ds.dargs.geo = mp->m_dir_geo; 501*7c4a07a4SDarrick J. Wong ds.lowest = ds.dargs.geo->leafblk; 502*7c4a07a4SDarrick J. Wong ds.highest = ds.dargs.geo->freeblk; 503*7c4a07a4SDarrick J. Wong } 504*7c4a07a4SDarrick J. Wong blkno = ds.lowest; 505*7c4a07a4SDarrick J. Wong level = 0; 506*7c4a07a4SDarrick J. Wong 507*7c4a07a4SDarrick J. Wong /* Find the root of the da tree, if present. */ 508*7c4a07a4SDarrick J. Wong blks = ds.state->path.blk; 509*7c4a07a4SDarrick J. Wong error = xfs_scrub_da_btree_block(&ds, level, blkno); 510*7c4a07a4SDarrick J. Wong if (error) 511*7c4a07a4SDarrick J. Wong goto out_state; 512*7c4a07a4SDarrick J. Wong /* 513*7c4a07a4SDarrick J. Wong * We didn't find a block at ds.lowest, which means that there's 514*7c4a07a4SDarrick J. Wong * no LEAF1/LEAFN tree (at least not where it's supposed to be), 515*7c4a07a4SDarrick J. Wong * so jump out now. 516*7c4a07a4SDarrick J. Wong */ 517*7c4a07a4SDarrick J. Wong if (blks[level].bp == NULL) 518*7c4a07a4SDarrick J. Wong goto out_state; 519*7c4a07a4SDarrick J. Wong 520*7c4a07a4SDarrick J. Wong blks[level].index = 0; 521*7c4a07a4SDarrick J. Wong while (level >= 0 && level < XFS_DA_NODE_MAXDEPTH) { 522*7c4a07a4SDarrick J. Wong /* Handle leaf block. */ 523*7c4a07a4SDarrick J. Wong if (blks[level].magic != XFS_DA_NODE_MAGIC) { 524*7c4a07a4SDarrick J. Wong /* End of leaf, pop back towards the root. */ 525*7c4a07a4SDarrick J. Wong if (blks[level].index >= ds.maxrecs[level]) { 526*7c4a07a4SDarrick J. Wong if (level > 0) 527*7c4a07a4SDarrick J. Wong blks[level - 1].index++; 528*7c4a07a4SDarrick J. Wong ds.tree_level++; 529*7c4a07a4SDarrick J. Wong level--; 530*7c4a07a4SDarrick J. Wong continue; 531*7c4a07a4SDarrick J. Wong } 532*7c4a07a4SDarrick J. Wong 533*7c4a07a4SDarrick J. Wong /* Dispatch record scrubbing. */ 534*7c4a07a4SDarrick J. Wong rec = xfs_scrub_da_btree_entry(&ds, level, 535*7c4a07a4SDarrick J. Wong blks[level].index); 536*7c4a07a4SDarrick J. Wong error = scrub_fn(&ds, level, rec); 537*7c4a07a4SDarrick J. Wong if (error) 538*7c4a07a4SDarrick J. Wong break; 539*7c4a07a4SDarrick J. Wong if (xfs_scrub_should_terminate(sc, &error) || 540*7c4a07a4SDarrick J. Wong (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 541*7c4a07a4SDarrick J. Wong break; 542*7c4a07a4SDarrick J. Wong 543*7c4a07a4SDarrick J. Wong blks[level].index++; 544*7c4a07a4SDarrick J. Wong continue; 545*7c4a07a4SDarrick J. Wong } 546*7c4a07a4SDarrick J. Wong 547*7c4a07a4SDarrick J. Wong 548*7c4a07a4SDarrick J. Wong /* End of node, pop back towards the root. */ 549*7c4a07a4SDarrick J. Wong if (blks[level].index >= ds.maxrecs[level]) { 550*7c4a07a4SDarrick J. Wong if (level > 0) 551*7c4a07a4SDarrick J. Wong blks[level - 1].index++; 552*7c4a07a4SDarrick J. Wong ds.tree_level++; 553*7c4a07a4SDarrick J. Wong level--; 554*7c4a07a4SDarrick J. Wong continue; 555*7c4a07a4SDarrick J. Wong } 556*7c4a07a4SDarrick J. Wong 557*7c4a07a4SDarrick J. Wong /* Hashes in order for scrub? */ 558*7c4a07a4SDarrick J. Wong key = xfs_scrub_da_btree_entry(&ds, level, blks[level].index); 559*7c4a07a4SDarrick J. Wong error = xfs_scrub_da_btree_hash(&ds, level, &key->hashval); 560*7c4a07a4SDarrick J. Wong if (error) 561*7c4a07a4SDarrick J. Wong goto out; 562*7c4a07a4SDarrick J. Wong 563*7c4a07a4SDarrick J. Wong /* Drill another level deeper. */ 564*7c4a07a4SDarrick J. Wong blkno = be32_to_cpu(key->before); 565*7c4a07a4SDarrick J. Wong level++; 566*7c4a07a4SDarrick J. Wong ds.tree_level--; 567*7c4a07a4SDarrick J. Wong error = xfs_scrub_da_btree_block(&ds, level, blkno); 568*7c4a07a4SDarrick J. Wong if (error) 569*7c4a07a4SDarrick J. Wong goto out; 570*7c4a07a4SDarrick J. Wong if (blks[level].bp == NULL) 571*7c4a07a4SDarrick J. Wong goto out; 572*7c4a07a4SDarrick J. Wong 573*7c4a07a4SDarrick J. Wong blks[level].index = 0; 574*7c4a07a4SDarrick J. Wong } 575*7c4a07a4SDarrick J. Wong 576*7c4a07a4SDarrick J. Wong out: 577*7c4a07a4SDarrick J. Wong /* Release all the buffers we're tracking. */ 578*7c4a07a4SDarrick J. Wong for (level = 0; level < XFS_DA_NODE_MAXDEPTH; level++) { 579*7c4a07a4SDarrick J. Wong if (blks[level].bp == NULL) 580*7c4a07a4SDarrick J. Wong continue; 581*7c4a07a4SDarrick J. Wong xfs_trans_brelse(sc->tp, blks[level].bp); 582*7c4a07a4SDarrick J. Wong blks[level].bp = NULL; 583*7c4a07a4SDarrick J. Wong } 584*7c4a07a4SDarrick J. Wong 585*7c4a07a4SDarrick J. Wong out_state: 586*7c4a07a4SDarrick J. Wong xfs_da_state_free(ds.state); 587*7c4a07a4SDarrick J. Wong return error; 588*7c4a07a4SDarrick J. Wong } 589