Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (C) 2017 Oracle.  All Rights Reserved.
0004  * Author: Darrick J. Wong <darrick.wong@oracle.com>
0005  */
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_trans_resv.h"
0011 #include "xfs_mount.h"
0012 #include "xfs_log_format.h"
0013 #include "xfs_trans.h"
0014 #include "xfs_inode.h"
0015 #include "xfs_dir2.h"
0016 #include "xfs_dir2_priv.h"
0017 #include "xfs_attr_leaf.h"
0018 #include "scrub/scrub.h"
0019 #include "scrub/common.h"
0020 #include "scrub/trace.h"
0021 #include "scrub/dabtree.h"
0022 
0023 /* Directory/Attribute Btree */
0024 
0025 /*
0026  * Check for da btree operation errors.  See the section about handling
0027  * operational errors in common.c.
0028  */
0029 bool
0030 xchk_da_process_error(
0031     struct xchk_da_btree    *ds,
0032     int         level,
0033     int         *error)
0034 {
0035     struct xfs_scrub    *sc = ds->sc;
0036 
0037     if (*error == 0)
0038         return true;
0039 
0040     switch (*error) {
0041     case -EDEADLOCK:
0042         /* Used to restart an op with deadlock avoidance. */
0043         trace_xchk_deadlock_retry(sc->ip, sc->sm, *error);
0044         break;
0045     case -EFSBADCRC:
0046     case -EFSCORRUPTED:
0047         /* Note the badness but don't abort. */
0048         sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
0049         *error = 0;
0050         fallthrough;
0051     default:
0052         trace_xchk_file_op_error(sc, ds->dargs.whichfork,
0053                 xfs_dir2_da_to_db(ds->dargs.geo,
0054                     ds->state->path.blk[level].blkno),
0055                 *error, __return_address);
0056         break;
0057     }
0058     return false;
0059 }
0060 
0061 /*
0062  * Check for da btree corruption.  See the section about handling
0063  * operational errors in common.c.
0064  */
0065 void
0066 xchk_da_set_corrupt(
0067     struct xchk_da_btree    *ds,
0068     int         level)
0069 {
0070     struct xfs_scrub    *sc = ds->sc;
0071 
0072     sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
0073 
0074     trace_xchk_fblock_error(sc, ds->dargs.whichfork,
0075             xfs_dir2_da_to_db(ds->dargs.geo,
0076                 ds->state->path.blk[level].blkno),
0077             __return_address);
0078 }
0079 
0080 static struct xfs_da_node_entry *
0081 xchk_da_btree_node_entry(
0082     struct xchk_da_btree        *ds,
0083     int             level)
0084 {
0085     struct xfs_da_state_blk     *blk = &ds->state->path.blk[level];
0086     struct xfs_da3_icnode_hdr   hdr;
0087 
0088     ASSERT(blk->magic == XFS_DA_NODE_MAGIC);
0089 
0090     xfs_da3_node_hdr_from_disk(ds->sc->mp, &hdr, blk->bp->b_addr);
0091     return hdr.btree + blk->index;
0092 }
0093 
0094 /* Scrub a da btree hash (key). */
0095 int
0096 xchk_da_btree_hash(
0097     struct xchk_da_btree        *ds,
0098     int             level,
0099     __be32              *hashp)
0100 {
0101     struct xfs_da_node_entry    *entry;
0102     xfs_dahash_t            hash;
0103     xfs_dahash_t            parent_hash;
0104 
0105     /* Is this hash in order? */
0106     hash = be32_to_cpu(*hashp);
0107     if (hash < ds->hashes[level])
0108         xchk_da_set_corrupt(ds, level);
0109     ds->hashes[level] = hash;
0110 
0111     if (level == 0)
0112         return 0;
0113 
0114     /* Is this hash no larger than the parent hash? */
0115     entry = xchk_da_btree_node_entry(ds, level - 1);
0116     parent_hash = be32_to_cpu(entry->hashval);
0117     if (parent_hash < hash)
0118         xchk_da_set_corrupt(ds, level);
0119 
0120     return 0;
0121 }
0122 
0123 /*
0124  * Check a da btree pointer.  Returns true if it's ok to use this
0125  * pointer.
0126  */
0127 STATIC bool
0128 xchk_da_btree_ptr_ok(
0129     struct xchk_da_btree    *ds,
0130     int         level,
0131     xfs_dablk_t     blkno)
0132 {
0133     if (blkno < ds->lowest || (ds->highest != 0 && blkno >= ds->highest)) {
0134         xchk_da_set_corrupt(ds, level);
0135         return false;
0136     }
0137 
0138     return true;
0139 }
0140 
0141 /*
0142  * The da btree scrubber can handle leaf1 blocks as a degenerate
0143  * form of leafn blocks.  Since the regular da code doesn't handle
0144  * leaf1, we must multiplex the verifiers.
0145  */
0146 static void
0147 xchk_da_btree_read_verify(
0148     struct xfs_buf      *bp)
0149 {
0150     struct xfs_da_blkinfo   *info = bp->b_addr;
0151 
0152     switch (be16_to_cpu(info->magic)) {
0153     case XFS_DIR2_LEAF1_MAGIC:
0154     case XFS_DIR3_LEAF1_MAGIC:
0155         bp->b_ops = &xfs_dir3_leaf1_buf_ops;
0156         bp->b_ops->verify_read(bp);
0157         return;
0158     default:
0159         /*
0160          * xfs_da3_node_buf_ops already know how to handle
0161          * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks.
0162          */
0163         bp->b_ops = &xfs_da3_node_buf_ops;
0164         bp->b_ops->verify_read(bp);
0165         return;
0166     }
0167 }
0168 static void
0169 xchk_da_btree_write_verify(
0170     struct xfs_buf      *bp)
0171 {
0172     struct xfs_da_blkinfo   *info = bp->b_addr;
0173 
0174     switch (be16_to_cpu(info->magic)) {
0175     case XFS_DIR2_LEAF1_MAGIC:
0176     case XFS_DIR3_LEAF1_MAGIC:
0177         bp->b_ops = &xfs_dir3_leaf1_buf_ops;
0178         bp->b_ops->verify_write(bp);
0179         return;
0180     default:
0181         /*
0182          * xfs_da3_node_buf_ops already know how to handle
0183          * DA*_NODE, ATTR*_LEAF, and DIR*_LEAFN blocks.
0184          */
0185         bp->b_ops = &xfs_da3_node_buf_ops;
0186         bp->b_ops->verify_write(bp);
0187         return;
0188     }
0189 }
0190 static void *
0191 xchk_da_btree_verify(
0192     struct xfs_buf      *bp)
0193 {
0194     struct xfs_da_blkinfo   *info = bp->b_addr;
0195 
0196     switch (be16_to_cpu(info->magic)) {
0197     case XFS_DIR2_LEAF1_MAGIC:
0198     case XFS_DIR3_LEAF1_MAGIC:
0199         bp->b_ops = &xfs_dir3_leaf1_buf_ops;
0200         return bp->b_ops->verify_struct(bp);
0201     default:
0202         bp->b_ops = &xfs_da3_node_buf_ops;
0203         return bp->b_ops->verify_struct(bp);
0204     }
0205 }
0206 
0207 static const struct xfs_buf_ops xchk_da_btree_buf_ops = {
0208     .name = "xchk_da_btree",
0209     .verify_read = xchk_da_btree_read_verify,
0210     .verify_write = xchk_da_btree_write_verify,
0211     .verify_struct = xchk_da_btree_verify,
0212 };
0213 
0214 /* Check a block's sibling. */
0215 STATIC int
0216 xchk_da_btree_block_check_sibling(
0217     struct xchk_da_btree    *ds,
0218     int         level,
0219     int         direction,
0220     xfs_dablk_t     sibling)
0221 {
0222     struct xfs_da_state_path *path = &ds->state->path;
0223     struct xfs_da_state_path *altpath = &ds->state->altpath;
0224     int         retval;
0225     int         plevel;
0226     int         error;
0227 
0228     memcpy(altpath, path, sizeof(ds->state->altpath));
0229 
0230     /*
0231      * If the pointer is null, we shouldn't be able to move the upper
0232      * level pointer anywhere.
0233      */
0234     if (sibling == 0) {
0235         error = xfs_da3_path_shift(ds->state, altpath, direction,
0236                 false, &retval);
0237         if (error == 0 && retval == 0)
0238             xchk_da_set_corrupt(ds, level);
0239         error = 0;
0240         goto out;
0241     }
0242 
0243     /* Move the alternate cursor one block in the direction given. */
0244     error = xfs_da3_path_shift(ds->state, altpath, direction, false,
0245             &retval);
0246     if (!xchk_da_process_error(ds, level, &error))
0247         goto out;
0248     if (retval) {
0249         xchk_da_set_corrupt(ds, level);
0250         goto out;
0251     }
0252     if (altpath->blk[level].bp)
0253         xchk_buffer_recheck(ds->sc, altpath->blk[level].bp);
0254 
0255     /* Compare upper level pointer to sibling pointer. */
0256     if (altpath->blk[level].blkno != sibling)
0257         xchk_da_set_corrupt(ds, level);
0258 
0259 out:
0260     /* Free all buffers in the altpath that aren't referenced from path. */
0261     for (plevel = 0; plevel < altpath->active; plevel++) {
0262         if (altpath->blk[plevel].bp == NULL ||
0263             (plevel < path->active &&
0264              altpath->blk[plevel].bp == path->blk[plevel].bp))
0265             continue;
0266 
0267         xfs_trans_brelse(ds->dargs.trans, altpath->blk[plevel].bp);
0268         altpath->blk[plevel].bp = NULL;
0269     }
0270 
0271     return error;
0272 }
0273 
0274 /* Check a block's sibling pointers. */
0275 STATIC int
0276 xchk_da_btree_block_check_siblings(
0277     struct xchk_da_btree    *ds,
0278     int         level,
0279     struct xfs_da_blkinfo   *hdr)
0280 {
0281     xfs_dablk_t     forw;
0282     xfs_dablk_t     back;
0283     int         error = 0;
0284 
0285     forw = be32_to_cpu(hdr->forw);
0286     back = be32_to_cpu(hdr->back);
0287 
0288     /* Top level blocks should not have sibling pointers. */
0289     if (level == 0) {
0290         if (forw != 0 || back != 0)
0291             xchk_da_set_corrupt(ds, level);
0292         return 0;
0293     }
0294 
0295     /*
0296      * Check back (left) and forw (right) pointers.  These functions
0297      * absorb error codes for us.
0298      */
0299     error = xchk_da_btree_block_check_sibling(ds, level, 0, back);
0300     if (error)
0301         goto out;
0302     error = xchk_da_btree_block_check_sibling(ds, level, 1, forw);
0303 
0304 out:
0305     memset(&ds->state->altpath, 0, sizeof(ds->state->altpath));
0306     return error;
0307 }
0308 
0309 /* Load a dir/attribute block from a btree. */
0310 STATIC int
0311 xchk_da_btree_block(
0312     struct xchk_da_btree        *ds,
0313     int             level,
0314     xfs_dablk_t         blkno)
0315 {
0316     struct xfs_da_state_blk     *blk;
0317     struct xfs_da_intnode       *node;
0318     struct xfs_da_node_entry    *btree;
0319     struct xfs_da3_blkinfo      *hdr3;
0320     struct xfs_da_args      *dargs = &ds->dargs;
0321     struct xfs_inode        *ip = ds->dargs.dp;
0322     xfs_ino_t           owner;
0323     int             *pmaxrecs;
0324     struct xfs_da3_icnode_hdr   nodehdr;
0325     int             error = 0;
0326 
0327     blk = &ds->state->path.blk[level];
0328     ds->state->path.active = level + 1;
0329 
0330     /* Release old block. */
0331     if (blk->bp) {
0332         xfs_trans_brelse(dargs->trans, blk->bp);
0333         blk->bp = NULL;
0334     }
0335 
0336     /* Check the pointer. */
0337     blk->blkno = blkno;
0338     if (!xchk_da_btree_ptr_ok(ds, level, blkno))
0339         goto out_nobuf;
0340 
0341     /* Read the buffer. */
0342     error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno,
0343             XFS_DABUF_MAP_HOLE_OK, &blk->bp, dargs->whichfork,
0344             &xchk_da_btree_buf_ops);
0345     if (!xchk_da_process_error(ds, level, &error))
0346         goto out_nobuf;
0347     if (blk->bp)
0348         xchk_buffer_recheck(ds->sc, blk->bp);
0349 
0350     /*
0351      * We didn't find a dir btree root block, which means that
0352      * there's no LEAF1/LEAFN tree (at least not where it's supposed
0353      * to be), so jump out now.
0354      */
0355     if (ds->dargs.whichfork == XFS_DATA_FORK && level == 0 &&
0356             blk->bp == NULL)
0357         goto out_nobuf;
0358 
0359     /* It's /not/ ok for attr trees not to have a da btree. */
0360     if (blk->bp == NULL) {
0361         xchk_da_set_corrupt(ds, level);
0362         goto out_nobuf;
0363     }
0364 
0365     hdr3 = blk->bp->b_addr;
0366     blk->magic = be16_to_cpu(hdr3->hdr.magic);
0367     pmaxrecs = &ds->maxrecs[level];
0368 
0369     /* We only started zeroing the header on v5 filesystems. */
0370     if (xfs_has_crc(ds->sc->mp) && hdr3->hdr.pad)
0371         xchk_da_set_corrupt(ds, level);
0372 
0373     /* Check the owner. */
0374     if (xfs_has_crc(ip->i_mount)) {
0375         owner = be64_to_cpu(hdr3->owner);
0376         if (owner != ip->i_ino)
0377             xchk_da_set_corrupt(ds, level);
0378     }
0379 
0380     /* Check the siblings. */
0381     error = xchk_da_btree_block_check_siblings(ds, level, &hdr3->hdr);
0382     if (error)
0383         goto out;
0384 
0385     /* Interpret the buffer. */
0386     switch (blk->magic) {
0387     case XFS_ATTR_LEAF_MAGIC:
0388     case XFS_ATTR3_LEAF_MAGIC:
0389         xfs_trans_buf_set_type(dargs->trans, blk->bp,
0390                 XFS_BLFT_ATTR_LEAF_BUF);
0391         blk->magic = XFS_ATTR_LEAF_MAGIC;
0392         blk->hashval = xfs_attr_leaf_lasthash(blk->bp, pmaxrecs);
0393         if (ds->tree_level != 0)
0394             xchk_da_set_corrupt(ds, level);
0395         break;
0396     case XFS_DIR2_LEAFN_MAGIC:
0397     case XFS_DIR3_LEAFN_MAGIC:
0398         xfs_trans_buf_set_type(dargs->trans, blk->bp,
0399                 XFS_BLFT_DIR_LEAFN_BUF);
0400         blk->magic = XFS_DIR2_LEAFN_MAGIC;
0401         blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
0402         if (ds->tree_level != 0)
0403             xchk_da_set_corrupt(ds, level);
0404         break;
0405     case XFS_DIR2_LEAF1_MAGIC:
0406     case XFS_DIR3_LEAF1_MAGIC:
0407         xfs_trans_buf_set_type(dargs->trans, blk->bp,
0408                 XFS_BLFT_DIR_LEAF1_BUF);
0409         blk->magic = XFS_DIR2_LEAF1_MAGIC;
0410         blk->hashval = xfs_dir2_leaf_lasthash(ip, blk->bp, pmaxrecs);
0411         if (ds->tree_level != 0)
0412             xchk_da_set_corrupt(ds, level);
0413         break;
0414     case XFS_DA_NODE_MAGIC:
0415     case XFS_DA3_NODE_MAGIC:
0416         xfs_trans_buf_set_type(dargs->trans, blk->bp,
0417                 XFS_BLFT_DA_NODE_BUF);
0418         blk->magic = XFS_DA_NODE_MAGIC;
0419         node = blk->bp->b_addr;
0420         xfs_da3_node_hdr_from_disk(ip->i_mount, &nodehdr, node);
0421         btree = nodehdr.btree;
0422         *pmaxrecs = nodehdr.count;
0423         blk->hashval = be32_to_cpu(btree[*pmaxrecs - 1].hashval);
0424         if (level == 0) {
0425             if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) {
0426                 xchk_da_set_corrupt(ds, level);
0427                 goto out_freebp;
0428             }
0429             ds->tree_level = nodehdr.level;
0430         } else {
0431             if (ds->tree_level != nodehdr.level) {
0432                 xchk_da_set_corrupt(ds, level);
0433                 goto out_freebp;
0434             }
0435         }
0436 
0437         /* XXX: Check hdr3.pad32 once we know how to fix it. */
0438         break;
0439     default:
0440         xchk_da_set_corrupt(ds, level);
0441         goto out_freebp;
0442     }
0443 
0444     /*
0445      * If we've been handed a block that is below the dabtree root, does
0446      * its hashval match what the parent block expected to see?
0447      */
0448     if (level > 0) {
0449         struct xfs_da_node_entry    *key;
0450 
0451         key = xchk_da_btree_node_entry(ds, level - 1);
0452         if (be32_to_cpu(key->hashval) != blk->hashval) {
0453             xchk_da_set_corrupt(ds, level);
0454             goto out_freebp;
0455         }
0456     }
0457 
0458 out:
0459     return error;
0460 out_freebp:
0461     xfs_trans_brelse(dargs->trans, blk->bp);
0462     blk->bp = NULL;
0463 out_nobuf:
0464     blk->blkno = 0;
0465     return error;
0466 }
0467 
0468 /* Visit all nodes and leaves of a da btree. */
0469 int
0470 xchk_da_btree(
0471     struct xfs_scrub        *sc,
0472     int             whichfork,
0473     xchk_da_btree_rec_fn        scrub_fn,
0474     void                *private)
0475 {
0476     struct xchk_da_btree        *ds;
0477     struct xfs_mount        *mp = sc->mp;
0478     struct xfs_da_state_blk     *blks;
0479     struct xfs_da_node_entry    *key;
0480     xfs_dablk_t         blkno;
0481     int             level;
0482     int             error;
0483 
0484     /* Skip short format data structures; no btree to scan. */
0485     if (!xfs_ifork_has_extents(xfs_ifork_ptr(sc->ip, whichfork)))
0486         return 0;
0487 
0488     /* Set up initial da state. */
0489     ds = kmem_zalloc(sizeof(struct xchk_da_btree), KM_NOFS | KM_MAYFAIL);
0490     if (!ds)
0491         return -ENOMEM;
0492     ds->dargs.dp = sc->ip;
0493     ds->dargs.whichfork = whichfork;
0494     ds->dargs.trans = sc->tp;
0495     ds->dargs.op_flags = XFS_DA_OP_OKNOENT;
0496     ds->state = xfs_da_state_alloc(&ds->dargs);
0497     ds->sc = sc;
0498     ds->private = private;
0499     if (whichfork == XFS_ATTR_FORK) {
0500         ds->dargs.geo = mp->m_attr_geo;
0501         ds->lowest = 0;
0502         ds->highest = 0;
0503     } else {
0504         ds->dargs.geo = mp->m_dir_geo;
0505         ds->lowest = ds->dargs.geo->leafblk;
0506         ds->highest = ds->dargs.geo->freeblk;
0507     }
0508     blkno = ds->lowest;
0509     level = 0;
0510 
0511     /* Find the root of the da tree, if present. */
0512     blks = ds->state->path.blk;
0513     error = xchk_da_btree_block(ds, level, blkno);
0514     if (error)
0515         goto out_state;
0516     /*
0517      * We didn't find a block at ds->lowest, which means that there's
0518      * no LEAF1/LEAFN tree (at least not where it's supposed to be),
0519      * so jump out now.
0520      */
0521     if (blks[level].bp == NULL)
0522         goto out_state;
0523 
0524     blks[level].index = 0;
0525     while (level >= 0 && level < XFS_DA_NODE_MAXDEPTH) {
0526         /* Handle leaf block. */
0527         if (blks[level].magic != XFS_DA_NODE_MAGIC) {
0528             /* End of leaf, pop back towards the root. */
0529             if (blks[level].index >= ds->maxrecs[level]) {
0530                 if (level > 0)
0531                     blks[level - 1].index++;
0532                 ds->tree_level++;
0533                 level--;
0534                 continue;
0535             }
0536 
0537             /* Dispatch record scrubbing. */
0538             error = scrub_fn(ds, level);
0539             if (error)
0540                 break;
0541             if (xchk_should_terminate(sc, &error) ||
0542                 (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
0543                 break;
0544 
0545             blks[level].index++;
0546             continue;
0547         }
0548 
0549 
0550         /* End of node, pop back towards the root. */
0551         if (blks[level].index >= ds->maxrecs[level]) {
0552             if (level > 0)
0553                 blks[level - 1].index++;
0554             ds->tree_level++;
0555             level--;
0556             continue;
0557         }
0558 
0559         /* Hashes in order for scrub? */
0560         key = xchk_da_btree_node_entry(ds, level);
0561         error = xchk_da_btree_hash(ds, level, &key->hashval);
0562         if (error)
0563             goto out;
0564 
0565         /* Drill another level deeper. */
0566         blkno = be32_to_cpu(key->before);
0567         level++;
0568         if (level >= XFS_DA_NODE_MAXDEPTH) {
0569             /* Too deep! */
0570             xchk_da_set_corrupt(ds, level - 1);
0571             break;
0572         }
0573         ds->tree_level--;
0574         error = xchk_da_btree_block(ds, level, blkno);
0575         if (error)
0576             goto out;
0577         if (blks[level].bp == NULL)
0578             goto out;
0579 
0580         blks[level].index = 0;
0581     }
0582 
0583 out:
0584     /* Release all the buffers we're tracking. */
0585     for (level = 0; level < XFS_DA_NODE_MAXDEPTH; level++) {
0586         if (blks[level].bp == NULL)
0587             continue;
0588         xfs_trans_brelse(sc->tp, blks[level].bp);
0589         blks[level].bp = NULL;
0590     }
0591 
0592 out_state:
0593     xfs_da_state_free(ds->state);
0594     kmem_free(ds);
0595     return error;
0596 }