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_btree.h"
0013 #include "xfs_bit.h"
0014 #include "xfs_log_format.h"
0015 #include "xfs_trans.h"
0016 #include "xfs_inode.h"
0017 #include "xfs_alloc.h"
0018 #include "xfs_bmap.h"
0019 #include "xfs_bmap_btree.h"
0020 #include "xfs_rmap.h"
0021 #include "xfs_rmap_btree.h"
0022 #include "scrub/scrub.h"
0023 #include "scrub/common.h"
0024 #include "scrub/btree.h"
0025 #include "xfs_ag.h"
0026 
0027 /* Set us up with an inode's bmap. */
0028 int
0029 xchk_setup_inode_bmap(
0030     struct xfs_scrub    *sc)
0031 {
0032     int         error;
0033 
0034     error = xchk_get_inode(sc);
0035     if (error)
0036         goto out;
0037 
0038     sc->ilock_flags = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
0039     xfs_ilock(sc->ip, sc->ilock_flags);
0040 
0041     /*
0042      * We don't want any ephemeral data fork updates sitting around
0043      * while we inspect block mappings, so wait for directio to finish
0044      * and flush dirty data if we have delalloc reservations.
0045      */
0046     if (S_ISREG(VFS_I(sc->ip)->i_mode) &&
0047         sc->sm->sm_type == XFS_SCRUB_TYPE_BMBTD) {
0048         struct address_space    *mapping = VFS_I(sc->ip)->i_mapping;
0049 
0050         inode_dio_wait(VFS_I(sc->ip));
0051 
0052         /*
0053          * Try to flush all incore state to disk before we examine the
0054          * space mappings for the data fork.  Leave accumulated errors
0055          * in the mapping for the writer threads to consume.
0056          *
0057          * On ENOSPC or EIO writeback errors, we continue into the
0058          * extent mapping checks because write failures do not
0059          * necessarily imply anything about the correctness of the file
0060          * metadata.  The metadata and the file data could be on
0061          * completely separate devices; a media failure might only
0062          * affect a subset of the disk, etc.  We can handle delalloc
0063          * extents in the scrubber, so leaving them in memory is fine.
0064          */
0065         error = filemap_fdatawrite(mapping);
0066         if (!error)
0067             error = filemap_fdatawait_keep_errors(mapping);
0068         if (error && (error != -ENOSPC && error != -EIO))
0069             goto out;
0070     }
0071 
0072     /* Got the inode, lock it and we're ready to go. */
0073     error = xchk_trans_alloc(sc, 0);
0074     if (error)
0075         goto out;
0076     sc->ilock_flags |= XFS_ILOCK_EXCL;
0077     xfs_ilock(sc->ip, XFS_ILOCK_EXCL);
0078 
0079 out:
0080     /* scrub teardown will unlock and release the inode */
0081     return error;
0082 }
0083 
0084 /*
0085  * Inode fork block mapping (BMBT) scrubber.
0086  * More complex than the others because we have to scrub
0087  * all the extents regardless of whether or not the fork
0088  * is in btree format.
0089  */
0090 
0091 struct xchk_bmap_info {
0092     struct xfs_scrub    *sc;
0093     xfs_fileoff_t       lastoff;
0094     bool            is_rt;
0095     bool            is_shared;
0096     bool            was_loaded;
0097     int         whichfork;
0098 };
0099 
0100 /* Look for a corresponding rmap for this irec. */
0101 static inline bool
0102 xchk_bmap_get_rmap(
0103     struct xchk_bmap_info   *info,
0104     struct xfs_bmbt_irec    *irec,
0105     xfs_agblock_t       agbno,
0106     uint64_t        owner,
0107     struct xfs_rmap_irec    *rmap)
0108 {
0109     xfs_fileoff_t       offset;
0110     unsigned int        rflags = 0;
0111     int         has_rmap;
0112     int         error;
0113 
0114     if (info->whichfork == XFS_ATTR_FORK)
0115         rflags |= XFS_RMAP_ATTR_FORK;
0116     if (irec->br_state == XFS_EXT_UNWRITTEN)
0117         rflags |= XFS_RMAP_UNWRITTEN;
0118 
0119     /*
0120      * CoW staging extents are owned (on disk) by the refcountbt, so
0121      * their rmaps do not have offsets.
0122      */
0123     if (info->whichfork == XFS_COW_FORK)
0124         offset = 0;
0125     else
0126         offset = irec->br_startoff;
0127 
0128     /*
0129      * If the caller thinks this could be a shared bmbt extent (IOWs,
0130      * any data fork extent of a reflink inode) then we have to use the
0131      * range rmap lookup to make sure we get the correct owner/offset.
0132      */
0133     if (info->is_shared) {
0134         error = xfs_rmap_lookup_le_range(info->sc->sa.rmap_cur, agbno,
0135                 owner, offset, rflags, rmap, &has_rmap);
0136     } else {
0137         error = xfs_rmap_lookup_le(info->sc->sa.rmap_cur, agbno,
0138                 owner, offset, rflags, rmap, &has_rmap);
0139     }
0140     if (!xchk_should_check_xref(info->sc, &error, &info->sc->sa.rmap_cur))
0141         return false;
0142 
0143     if (!has_rmap)
0144         xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
0145             irec->br_startoff);
0146     return has_rmap;
0147 }
0148 
0149 /* Make sure that we have rmapbt records for this extent. */
0150 STATIC void
0151 xchk_bmap_xref_rmap(
0152     struct xchk_bmap_info   *info,
0153     struct xfs_bmbt_irec    *irec,
0154     xfs_agblock_t       agbno)
0155 {
0156     struct xfs_rmap_irec    rmap;
0157     unsigned long long  rmap_end;
0158     uint64_t        owner;
0159 
0160     if (!info->sc->sa.rmap_cur || xchk_skip_xref(info->sc->sm))
0161         return;
0162 
0163     if (info->whichfork == XFS_COW_FORK)
0164         owner = XFS_RMAP_OWN_COW;
0165     else
0166         owner = info->sc->ip->i_ino;
0167 
0168     /* Find the rmap record for this irec. */
0169     if (!xchk_bmap_get_rmap(info, irec, agbno, owner, &rmap))
0170         return;
0171 
0172     /* Check the rmap. */
0173     rmap_end = (unsigned long long)rmap.rm_startblock + rmap.rm_blockcount;
0174     if (rmap.rm_startblock > agbno ||
0175         agbno + irec->br_blockcount > rmap_end)
0176         xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
0177                 irec->br_startoff);
0178 
0179     /*
0180      * Check the logical offsets if applicable.  CoW staging extents
0181      * don't track logical offsets since the mappings only exist in
0182      * memory.
0183      */
0184     if (info->whichfork != XFS_COW_FORK) {
0185         rmap_end = (unsigned long long)rmap.rm_offset +
0186                 rmap.rm_blockcount;
0187         if (rmap.rm_offset > irec->br_startoff ||
0188             irec->br_startoff + irec->br_blockcount > rmap_end)
0189             xchk_fblock_xref_set_corrupt(info->sc,
0190                     info->whichfork, irec->br_startoff);
0191     }
0192 
0193     if (rmap.rm_owner != owner)
0194         xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
0195                 irec->br_startoff);
0196 
0197     /*
0198      * Check for discrepancies between the unwritten flag in the irec and
0199      * the rmap.  Note that the (in-memory) CoW fork distinguishes between
0200      * unwritten and written extents, but we don't track that in the rmap
0201      * records because the blocks are owned (on-disk) by the refcountbt,
0202      * which doesn't track unwritten state.
0203      */
0204     if (owner != XFS_RMAP_OWN_COW &&
0205         !!(irec->br_state == XFS_EXT_UNWRITTEN) !=
0206         !!(rmap.rm_flags & XFS_RMAP_UNWRITTEN))
0207         xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
0208                 irec->br_startoff);
0209 
0210     if (!!(info->whichfork == XFS_ATTR_FORK) !=
0211         !!(rmap.rm_flags & XFS_RMAP_ATTR_FORK))
0212         xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
0213                 irec->br_startoff);
0214     if (rmap.rm_flags & XFS_RMAP_BMBT_BLOCK)
0215         xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
0216                 irec->br_startoff);
0217 }
0218 
0219 /* Cross-reference a single rtdev extent record. */
0220 STATIC void
0221 xchk_bmap_rt_iextent_xref(
0222     struct xfs_inode    *ip,
0223     struct xchk_bmap_info   *info,
0224     struct xfs_bmbt_irec    *irec)
0225 {
0226     xchk_xref_is_used_rt_space(info->sc, irec->br_startblock,
0227             irec->br_blockcount);
0228 }
0229 
0230 /* Cross-reference a single datadev extent record. */
0231 STATIC void
0232 xchk_bmap_iextent_xref(
0233     struct xfs_inode    *ip,
0234     struct xchk_bmap_info   *info,
0235     struct xfs_bmbt_irec    *irec)
0236 {
0237     struct xfs_mount    *mp = info->sc->mp;
0238     xfs_agnumber_t      agno;
0239     xfs_agblock_t       agbno;
0240     xfs_extlen_t        len;
0241     int         error;
0242 
0243     agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock);
0244     agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock);
0245     len = irec->br_blockcount;
0246 
0247     error = xchk_ag_init_existing(info->sc, agno, &info->sc->sa);
0248     if (!xchk_fblock_process_error(info->sc, info->whichfork,
0249             irec->br_startoff, &error))
0250         goto out_free;
0251 
0252     xchk_xref_is_used_space(info->sc, agbno, len);
0253     xchk_xref_is_not_inode_chunk(info->sc, agbno, len);
0254     xchk_bmap_xref_rmap(info, irec, agbno);
0255     switch (info->whichfork) {
0256     case XFS_DATA_FORK:
0257         if (xfs_is_reflink_inode(info->sc->ip))
0258             break;
0259         fallthrough;
0260     case XFS_ATTR_FORK:
0261         xchk_xref_is_not_shared(info->sc, agbno,
0262                 irec->br_blockcount);
0263         break;
0264     case XFS_COW_FORK:
0265         xchk_xref_is_cow_staging(info->sc, agbno,
0266                 irec->br_blockcount);
0267         break;
0268     }
0269 
0270 out_free:
0271     xchk_ag_free(info->sc, &info->sc->sa);
0272 }
0273 
0274 /*
0275  * Directories and attr forks should never have blocks that can't be addressed
0276  * by a xfs_dablk_t.
0277  */
0278 STATIC void
0279 xchk_bmap_dirattr_extent(
0280     struct xfs_inode    *ip,
0281     struct xchk_bmap_info   *info,
0282     struct xfs_bmbt_irec    *irec)
0283 {
0284     struct xfs_mount    *mp = ip->i_mount;
0285     xfs_fileoff_t       off;
0286 
0287     if (!S_ISDIR(VFS_I(ip)->i_mode) && info->whichfork != XFS_ATTR_FORK)
0288         return;
0289 
0290     if (!xfs_verify_dablk(mp, irec->br_startoff))
0291         xchk_fblock_set_corrupt(info->sc, info->whichfork,
0292                 irec->br_startoff);
0293 
0294     off = irec->br_startoff + irec->br_blockcount - 1;
0295     if (!xfs_verify_dablk(mp, off))
0296         xchk_fblock_set_corrupt(info->sc, info->whichfork, off);
0297 }
0298 
0299 /* Scrub a single extent record. */
0300 STATIC int
0301 xchk_bmap_iextent(
0302     struct xfs_inode    *ip,
0303     struct xchk_bmap_info   *info,
0304     struct xfs_bmbt_irec    *irec)
0305 {
0306     struct xfs_mount    *mp = info->sc->mp;
0307     int         error = 0;
0308 
0309     /*
0310      * Check for out-of-order extents.  This record could have come
0311      * from the incore list, for which there is no ordering check.
0312      */
0313     if (irec->br_startoff < info->lastoff)
0314         xchk_fblock_set_corrupt(info->sc, info->whichfork,
0315                 irec->br_startoff);
0316 
0317     if (!xfs_verify_fileext(mp, irec->br_startoff, irec->br_blockcount))
0318         xchk_fblock_set_corrupt(info->sc, info->whichfork,
0319                 irec->br_startoff);
0320 
0321     xchk_bmap_dirattr_extent(ip, info, irec);
0322 
0323     /* There should never be a "hole" extent in either extent list. */
0324     if (irec->br_startblock == HOLESTARTBLOCK)
0325         xchk_fblock_set_corrupt(info->sc, info->whichfork,
0326                 irec->br_startoff);
0327 
0328     /*
0329      * Check for delalloc extents.  We never iterate the ones in the
0330      * in-core extent scan, and we should never see these in the bmbt.
0331      */
0332     if (isnullstartblock(irec->br_startblock))
0333         xchk_fblock_set_corrupt(info->sc, info->whichfork,
0334                 irec->br_startoff);
0335 
0336     /* Make sure the extent points to a valid place. */
0337     if (irec->br_blockcount > XFS_MAX_BMBT_EXTLEN)
0338         xchk_fblock_set_corrupt(info->sc, info->whichfork,
0339                 irec->br_startoff);
0340     if (info->is_rt &&
0341         !xfs_verify_rtext(mp, irec->br_startblock, irec->br_blockcount))
0342         xchk_fblock_set_corrupt(info->sc, info->whichfork,
0343                 irec->br_startoff);
0344     if (!info->is_rt &&
0345         !xfs_verify_fsbext(mp, irec->br_startblock, irec->br_blockcount))
0346         xchk_fblock_set_corrupt(info->sc, info->whichfork,
0347                 irec->br_startoff);
0348 
0349     /* We don't allow unwritten extents on attr forks. */
0350     if (irec->br_state == XFS_EXT_UNWRITTEN &&
0351         info->whichfork == XFS_ATTR_FORK)
0352         xchk_fblock_set_corrupt(info->sc, info->whichfork,
0353                 irec->br_startoff);
0354 
0355     if (info->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
0356         return 0;
0357 
0358     if (info->is_rt)
0359         xchk_bmap_rt_iextent_xref(ip, info, irec);
0360     else
0361         xchk_bmap_iextent_xref(ip, info, irec);
0362 
0363     info->lastoff = irec->br_startoff + irec->br_blockcount;
0364     return error;
0365 }
0366 
0367 /* Scrub a bmbt record. */
0368 STATIC int
0369 xchk_bmapbt_rec(
0370     struct xchk_btree   *bs,
0371     const union xfs_btree_rec *rec)
0372 {
0373     struct xfs_bmbt_irec    irec;
0374     struct xfs_bmbt_irec    iext_irec;
0375     struct xfs_iext_cursor  icur;
0376     struct xchk_bmap_info   *info = bs->private;
0377     struct xfs_inode    *ip = bs->cur->bc_ino.ip;
0378     struct xfs_buf      *bp = NULL;
0379     struct xfs_btree_block  *block;
0380     struct xfs_ifork    *ifp = xfs_ifork_ptr(ip, info->whichfork);
0381     uint64_t        owner;
0382     int         i;
0383 
0384     /*
0385      * Check the owners of the btree blocks up to the level below
0386      * the root since the verifiers don't do that.
0387      */
0388     if (xfs_has_crc(bs->cur->bc_mp) &&
0389         bs->cur->bc_levels[0].ptr == 1) {
0390         for (i = 0; i < bs->cur->bc_nlevels - 1; i++) {
0391             block = xfs_btree_get_block(bs->cur, i, &bp);
0392             owner = be64_to_cpu(block->bb_u.l.bb_owner);
0393             if (owner != ip->i_ino)
0394                 xchk_fblock_set_corrupt(bs->sc,
0395                         info->whichfork, 0);
0396         }
0397     }
0398 
0399     /*
0400      * Check that the incore extent tree contains an extent that matches
0401      * this one exactly.  We validate those cached bmaps later, so we don't
0402      * need to check them here.  If the incore extent tree was just loaded
0403      * from disk by the scrubber, we assume that its contents match what's
0404      * on disk (we still hold the ILOCK) and skip the equivalence check.
0405      */
0406     if (!info->was_loaded)
0407         return 0;
0408 
0409     xfs_bmbt_disk_get_all(&rec->bmbt, &irec);
0410     if (!xfs_iext_lookup_extent(ip, ifp, irec.br_startoff, &icur,
0411                 &iext_irec) ||
0412         irec.br_startoff != iext_irec.br_startoff ||
0413         irec.br_startblock != iext_irec.br_startblock ||
0414         irec.br_blockcount != iext_irec.br_blockcount ||
0415         irec.br_state != iext_irec.br_state)
0416         xchk_fblock_set_corrupt(bs->sc, info->whichfork,
0417                 irec.br_startoff);
0418     return 0;
0419 }
0420 
0421 /* Scan the btree records. */
0422 STATIC int
0423 xchk_bmap_btree(
0424     struct xfs_scrub    *sc,
0425     int         whichfork,
0426     struct xchk_bmap_info   *info)
0427 {
0428     struct xfs_owner_info   oinfo;
0429     struct xfs_ifork    *ifp = xfs_ifork_ptr(sc->ip, whichfork);
0430     struct xfs_mount    *mp = sc->mp;
0431     struct xfs_inode    *ip = sc->ip;
0432     struct xfs_btree_cur    *cur;
0433     int         error;
0434 
0435     /* Load the incore bmap cache if it's not loaded. */
0436     info->was_loaded = !xfs_need_iread_extents(ifp);
0437 
0438     error = xfs_iread_extents(sc->tp, ip, whichfork);
0439     if (!xchk_fblock_process_error(sc, whichfork, 0, &error))
0440         goto out;
0441 
0442     /* Check the btree structure. */
0443     cur = xfs_bmbt_init_cursor(mp, sc->tp, ip, whichfork);
0444     xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork);
0445     error = xchk_btree(sc, cur, xchk_bmapbt_rec, &oinfo, info);
0446     xfs_btree_del_cursor(cur, error);
0447 out:
0448     return error;
0449 }
0450 
0451 struct xchk_bmap_check_rmap_info {
0452     struct xfs_scrub    *sc;
0453     int         whichfork;
0454     struct xfs_iext_cursor  icur;
0455 };
0456 
0457 /* Can we find bmaps that fit this rmap? */
0458 STATIC int
0459 xchk_bmap_check_rmap(
0460     struct xfs_btree_cur        *cur,
0461     const struct xfs_rmap_irec  *rec,
0462     void                *priv)
0463 {
0464     struct xfs_bmbt_irec        irec;
0465     struct xfs_rmap_irec        check_rec;
0466     struct xchk_bmap_check_rmap_info    *sbcri = priv;
0467     struct xfs_ifork        *ifp;
0468     struct xfs_scrub        *sc = sbcri->sc;
0469     bool                have_map;
0470 
0471     /* Is this even the right fork? */
0472     if (rec->rm_owner != sc->ip->i_ino)
0473         return 0;
0474     if ((sbcri->whichfork == XFS_ATTR_FORK) ^
0475         !!(rec->rm_flags & XFS_RMAP_ATTR_FORK))
0476         return 0;
0477     if (rec->rm_flags & XFS_RMAP_BMBT_BLOCK)
0478         return 0;
0479 
0480     /* Now look up the bmbt record. */
0481     ifp = xfs_ifork_ptr(sc->ip, sbcri->whichfork);
0482     if (!ifp) {
0483         xchk_fblock_set_corrupt(sc, sbcri->whichfork,
0484                 rec->rm_offset);
0485         goto out;
0486     }
0487     have_map = xfs_iext_lookup_extent(sc->ip, ifp, rec->rm_offset,
0488             &sbcri->icur, &irec);
0489     if (!have_map)
0490         xchk_fblock_set_corrupt(sc, sbcri->whichfork,
0491                 rec->rm_offset);
0492     /*
0493      * bmap extent record lengths are constrained to 2^21 blocks in length
0494      * because of space constraints in the on-disk metadata structure.
0495      * However, rmap extent record lengths are constrained only by AG
0496      * length, so we have to loop through the bmbt to make sure that the
0497      * entire rmap is covered by bmbt records.
0498      */
0499     check_rec = *rec;
0500     while (have_map) {
0501         if (irec.br_startoff != check_rec.rm_offset)
0502             xchk_fblock_set_corrupt(sc, sbcri->whichfork,
0503                     check_rec.rm_offset);
0504         if (irec.br_startblock != XFS_AGB_TO_FSB(sc->mp,
0505                 cur->bc_ag.pag->pag_agno,
0506                 check_rec.rm_startblock))
0507             xchk_fblock_set_corrupt(sc, sbcri->whichfork,
0508                     check_rec.rm_offset);
0509         if (irec.br_blockcount > check_rec.rm_blockcount)
0510             xchk_fblock_set_corrupt(sc, sbcri->whichfork,
0511                     check_rec.rm_offset);
0512         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
0513             break;
0514         check_rec.rm_startblock += irec.br_blockcount;
0515         check_rec.rm_offset += irec.br_blockcount;
0516         check_rec.rm_blockcount -= irec.br_blockcount;
0517         if (check_rec.rm_blockcount == 0)
0518             break;
0519         have_map = xfs_iext_next_extent(ifp, &sbcri->icur, &irec);
0520         if (!have_map)
0521             xchk_fblock_set_corrupt(sc, sbcri->whichfork,
0522                     check_rec.rm_offset);
0523     }
0524 
0525 out:
0526     if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
0527         return -ECANCELED;
0528     return 0;
0529 }
0530 
0531 /* Make sure each rmap has a corresponding bmbt entry. */
0532 STATIC int
0533 xchk_bmap_check_ag_rmaps(
0534     struct xfs_scrub        *sc,
0535     int             whichfork,
0536     struct xfs_perag        *pag)
0537 {
0538     struct xchk_bmap_check_rmap_info    sbcri;
0539     struct xfs_btree_cur        *cur;
0540     struct xfs_buf          *agf;
0541     int             error;
0542 
0543     error = xfs_alloc_read_agf(pag, sc->tp, 0, &agf);
0544     if (error)
0545         return error;
0546 
0547     cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, pag);
0548 
0549     sbcri.sc = sc;
0550     sbcri.whichfork = whichfork;
0551     error = xfs_rmap_query_all(cur, xchk_bmap_check_rmap, &sbcri);
0552     if (error == -ECANCELED)
0553         error = 0;
0554 
0555     xfs_btree_del_cursor(cur, error);
0556     xfs_trans_brelse(sc->tp, agf);
0557     return error;
0558 }
0559 
0560 /* Make sure each rmap has a corresponding bmbt entry. */
0561 STATIC int
0562 xchk_bmap_check_rmaps(
0563     struct xfs_scrub    *sc,
0564     int         whichfork)
0565 {
0566     struct xfs_ifork    *ifp = xfs_ifork_ptr(sc->ip, whichfork);
0567     struct xfs_perag    *pag;
0568     xfs_agnumber_t      agno;
0569     bool            zero_size;
0570     int         error;
0571 
0572     if (!xfs_has_rmapbt(sc->mp) ||
0573         whichfork == XFS_COW_FORK ||
0574         (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
0575         return 0;
0576 
0577     /* Don't support realtime rmap checks yet. */
0578     if (XFS_IS_REALTIME_INODE(sc->ip) && whichfork == XFS_DATA_FORK)
0579         return 0;
0580 
0581     ASSERT(xfs_ifork_ptr(sc->ip, whichfork) != NULL);
0582 
0583     /*
0584      * Only do this for complex maps that are in btree format, or for
0585      * situations where we would seem to have a size but zero extents.
0586      * The inode repair code can zap broken iforks, which means we have
0587      * to flag this bmap as corrupt if there are rmaps that need to be
0588      * reattached.
0589      */
0590 
0591     if (whichfork == XFS_DATA_FORK)
0592         zero_size = i_size_read(VFS_I(sc->ip)) == 0;
0593     else
0594         zero_size = false;
0595 
0596     if (ifp->if_format != XFS_DINODE_FMT_BTREE &&
0597         (zero_size || ifp->if_nextents > 0))
0598         return 0;
0599 
0600     for_each_perag(sc->mp, agno, pag) {
0601         error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag);
0602         if (error)
0603             break;
0604         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
0605             break;
0606     }
0607     if (pag)
0608         xfs_perag_put(pag);
0609     return error;
0610 }
0611 
0612 /*
0613  * Scrub an inode fork's block mappings.
0614  *
0615  * First we scan every record in every btree block, if applicable.
0616  * Then we unconditionally scan the incore extent cache.
0617  */
0618 STATIC int
0619 xchk_bmap(
0620     struct xfs_scrub    *sc,
0621     int         whichfork)
0622 {
0623     struct xfs_bmbt_irec    irec;
0624     struct xchk_bmap_info   info = { NULL };
0625     struct xfs_mount    *mp = sc->mp;
0626     struct xfs_inode    *ip = sc->ip;
0627     struct xfs_ifork    *ifp = xfs_ifork_ptr(ip, whichfork);
0628     xfs_fileoff_t       endoff;
0629     struct xfs_iext_cursor  icur;
0630     int         error = 0;
0631 
0632     /* Non-existent forks can be ignored. */
0633     if (!ifp)
0634         goto out;
0635 
0636     info.is_rt = whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip);
0637     info.whichfork = whichfork;
0638     info.is_shared = whichfork == XFS_DATA_FORK && xfs_is_reflink_inode(ip);
0639     info.sc = sc;
0640 
0641     switch (whichfork) {
0642     case XFS_COW_FORK:
0643         /* No CoW forks on non-reflink inodes/filesystems. */
0644         if (!xfs_is_reflink_inode(ip)) {
0645             xchk_ino_set_corrupt(sc, sc->ip->i_ino);
0646             goto out;
0647         }
0648         break;
0649     case XFS_ATTR_FORK:
0650         if (!xfs_has_attr(mp) && !xfs_has_attr2(mp))
0651             xchk_ino_set_corrupt(sc, sc->ip->i_ino);
0652         break;
0653     default:
0654         ASSERT(whichfork == XFS_DATA_FORK);
0655         break;
0656     }
0657 
0658     /* Check the fork values */
0659     switch (ifp->if_format) {
0660     case XFS_DINODE_FMT_UUID:
0661     case XFS_DINODE_FMT_DEV:
0662     case XFS_DINODE_FMT_LOCAL:
0663         /* No mappings to check. */
0664         goto out;
0665     case XFS_DINODE_FMT_EXTENTS:
0666         break;
0667     case XFS_DINODE_FMT_BTREE:
0668         if (whichfork == XFS_COW_FORK) {
0669             xchk_fblock_set_corrupt(sc, whichfork, 0);
0670             goto out;
0671         }
0672 
0673         error = xchk_bmap_btree(sc, whichfork, &info);
0674         if (error)
0675             goto out;
0676         break;
0677     default:
0678         xchk_fblock_set_corrupt(sc, whichfork, 0);
0679         goto out;
0680     }
0681 
0682     if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
0683         goto out;
0684 
0685     /* Find the offset of the last extent in the mapping. */
0686     error = xfs_bmap_last_offset(ip, &endoff, whichfork);
0687     if (!xchk_fblock_process_error(sc, whichfork, 0, &error))
0688         goto out;
0689 
0690     /* Scrub extent records. */
0691     info.lastoff = 0;
0692     ifp = xfs_ifork_ptr(ip, whichfork);
0693     for_each_xfs_iext(ifp, &icur, &irec) {
0694         if (xchk_should_terminate(sc, &error) ||
0695             (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
0696             goto out;
0697         if (isnullstartblock(irec.br_startblock))
0698             continue;
0699         if (irec.br_startoff >= endoff) {
0700             xchk_fblock_set_corrupt(sc, whichfork,
0701                     irec.br_startoff);
0702             goto out;
0703         }
0704         error = xchk_bmap_iextent(ip, &info, &irec);
0705         if (error)
0706             goto out;
0707     }
0708 
0709     error = xchk_bmap_check_rmaps(sc, whichfork);
0710     if (!xchk_fblock_xref_process_error(sc, whichfork, 0, &error))
0711         goto out;
0712 out:
0713     return error;
0714 }
0715 
0716 /* Scrub an inode's data fork. */
0717 int
0718 xchk_bmap_data(
0719     struct xfs_scrub    *sc)
0720 {
0721     return xchk_bmap(sc, XFS_DATA_FORK);
0722 }
0723 
0724 /* Scrub an inode's attr fork. */
0725 int
0726 xchk_bmap_attr(
0727     struct xfs_scrub    *sc)
0728 {
0729     return xchk_bmap(sc, XFS_ATTR_FORK);
0730 }
0731 
0732 /* Scrub an inode's CoW fork. */
0733 int
0734 xchk_bmap_cow(
0735     struct xfs_scrub    *sc)
0736 {
0737     if (!xfs_is_reflink_inode(sc->ip))
0738         return -ENOENT;
0739 
0740     return xchk_bmap(sc, XFS_COW_FORK);
0741 }