LCOV - code coverage report
Current view: top level - fs/xfs/scrub - bmap.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsx @ Mon Jul 31 20:08:34 PDT 2023 Lines: 379 474 80.0 %
Date: 2023-07-31 20:08:34 Functions: 22 22 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 2017-2023 Oracle.  All Rights Reserved.
       4             :  * Author: Darrick J. Wong <djwong@kernel.org>
       5             :  */
       6             : #include "xfs.h"
       7             : #include "xfs_fs.h"
       8             : #include "xfs_shared.h"
       9             : #include "xfs_format.h"
      10             : #include "xfs_trans_resv.h"
      11             : #include "xfs_mount.h"
      12             : #include "xfs_btree.h"
      13             : #include "xfs_bit.h"
      14             : #include "xfs_log_format.h"
      15             : #include "xfs_trans.h"
      16             : #include "xfs_inode.h"
      17             : #include "xfs_alloc.h"
      18             : #include "xfs_bmap.h"
      19             : #include "xfs_bmap_btree.h"
      20             : #include "xfs_rmap.h"
      21             : #include "xfs_rmap_btree.h"
      22             : #include "xfs_rtgroup.h"
      23             : #include "xfs_rtalloc.h"
      24             : #include "xfs_rtrmap_btree.h"
      25             : #include "scrub/scrub.h"
      26             : #include "scrub/common.h"
      27             : #include "scrub/btree.h"
      28             : #include "xfs_ag.h"
      29             : 
      30             : /* Set us up with an inode's bmap. */
      31             : int
      32   404296494 : xchk_setup_inode_bmap(
      33             :         struct xfs_scrub        *sc)
      34             : {
      35   404296494 :         int                     error;
      36             : 
      37   404296494 :         if (xchk_need_intent_drain(sc))
      38           0 :                 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
      39             : 
      40   404296494 :         error = xchk_iget_for_scrubbing(sc);
      41   404829507 :         if (error)
      42     2597679 :                 goto out;
      43             : 
      44   402231828 :         xchk_ilock(sc, XFS_IOLOCK_EXCL);
      45             : 
      46             :         /*
      47             :          * We don't want any ephemeral data/cow fork updates sitting around
      48             :          * while we inspect block mappings, so wait for directio to finish
      49             :          * and flush dirty data if we have delalloc reservations.
      50             :          */
      51   401800562 :         if (S_ISREG(VFS_I(sc->ip)->i_mode) &&
      52   189049210 :             sc->sm->sm_type != XFS_SCRUB_TYPE_BMBTA) {
      53   123910273 :                 struct address_space    *mapping = VFS_I(sc->ip)->i_mapping;
      54   123910273 :                 bool                    is_repair = xchk_could_repair(sc);
      55             : 
      56   123910273 :                 xchk_ilock(sc, XFS_MMAPLOCK_EXCL);
      57             : 
      58             :                 /* Break all our leases, we're going to mess with things. */
      59   123925373 :                 if (is_repair) {
      60     3331742 :                         error = xfs_break_layouts(VFS_I(sc->ip),
      61             :                                         &sc->ilock_flags, BREAK_WRITE);
      62     3331894 :                         if (error)
      63           0 :                                 goto out;
      64             :                 }
      65             : 
      66   123925525 :                 inode_dio_wait(VFS_I(sc->ip));
      67             : 
      68             :                 /*
      69             :                  * Try to flush all incore state to disk before we examine the
      70             :                  * space mappings for the data fork.  Leave accumulated errors
      71             :                  * in the mapping for the writer threads to consume.
      72             :                  *
      73             :                  * On ENOSPC or EIO writeback errors, we continue into the
      74             :                  * extent mapping checks because write failures do not
      75             :                  * necessarily imply anything about the correctness of the file
      76             :                  * metadata.  The metadata and the file data could be on
      77             :                  * completely separate devices; a media failure might only
      78             :                  * affect a subset of the disk, etc.  We can handle delalloc
      79             :                  * extents in the scrubber, so leaving them in memory is fine.
      80             :                  */
      81   123637302 :                 error = filemap_fdatawrite(mapping);
      82   123776782 :                 if (!error)
      83   123767071 :                         error = filemap_fdatawait_keep_errors(mapping);
      84   123774040 :                 if (error && (error != -ENOSPC && error != -EIO))
      85           0 :                         goto out;
      86             : 
      87             :                 /* Drop the page cache if we're repairing block mappings. */
      88   123774040 :                 if (is_repair) {
      89     3331517 :                         error = invalidate_inode_pages2(
      90     3331517 :                                         VFS_I(sc->ip)->i_mapping);
      91     3331345 :                         if (error)
      92           0 :                                 goto out;
      93             :                 }
      94             : 
      95             :         }
      96             : 
      97             :         /* Got the inode, lock it and we're ready to go. */
      98   401664157 :         error = xchk_trans_alloc(sc, 0);
      99   401987396 :         if (error)
     100           0 :                 goto out;
     101             : 
     102   401987396 :         error = xchk_ino_dqattach(sc);
     103   401987139 :         if (error)
     104           0 :                 goto out;
     105             : 
     106   401987139 :         xchk_ilock(sc, XFS_ILOCK_EXCL);
     107   404387649 : out:
     108             :         /* scrub teardown will unlock and release the inode */
     109   404387649 :         return error;
     110             : }
     111             : 
     112             : /*
     113             :  * Inode fork block mapping (BMBT) scrubber.
     114             :  * More complex than the others because we have to scrub
     115             :  * all the extents regardless of whether or not the fork
     116             :  * is in btree format.
     117             :  */
     118             : 
     119             : struct xchk_bmap_info {
     120             :         struct xfs_scrub        *sc;
     121             : 
     122             :         /* Incore extent tree cursor */
     123             :         struct xfs_iext_cursor  icur;
     124             : 
     125             :         /* Previous fork mapping that we examined */
     126             :         struct xfs_bmbt_irec    prev_rec;
     127             : 
     128             :         /* Is this a realtime fork? */
     129             :         bool                    is_rt;
     130             : 
     131             :         /* May mappings point to shared space? */
     132             :         bool                    is_shared;
     133             : 
     134             :         /* Was the incore extent tree loaded? */
     135             :         bool                    was_loaded;
     136             : 
     137             :         /* Which inode fork are we checking? */
     138             :         int                     whichfork;
     139             : };
     140             : 
     141             : /* Look for a corresponding rmap for this irec. */
     142             : static inline bool
     143   756625988 : xchk_bmap_get_rmap(
     144             :         struct xchk_bmap_info   *info,
     145             :         struct xfs_bmbt_irec    *irec,
     146             :         xfs_agblock_t           bno,
     147             :         uint64_t                owner,
     148             :         struct xfs_rmap_irec    *rmap)
     149             : {
     150   756625988 :         struct xfs_btree_cur    **curp = &info->sc->sa.rmap_cur;
     151   756625988 :         xfs_fileoff_t           offset;
     152   756625988 :         unsigned int            rflags = 0;
     153   756625988 :         int                     has_rmap;
     154   756625988 :         int                     error;
     155             : 
     156   756625988 :         if (xfs_ifork_is_realtime(info->sc->ip, info->whichfork))
     157   182173292 :                 curp = &info->sc->sr.rmap_cur;
     158             : 
     159   756580784 :         if (*curp == NULL)
     160             :                 return false;
     161             : 
     162   753070086 :         if (info->whichfork == XFS_ATTR_FORK)
     163     2275506 :                 rflags |= XFS_RMAP_ATTR_FORK;
     164   753070086 :         if (irec->br_state == XFS_EXT_UNWRITTEN)
     165    32480101 :                 rflags |= XFS_RMAP_UNWRITTEN;
     166             : 
     167             :         /*
     168             :          * CoW staging extents are owned (on disk) by the refcountbt, so
     169             :          * their rmaps do not have offsets.
     170             :          */
     171   753070086 :         if (info->whichfork == XFS_COW_FORK)
     172             :                 offset = 0;
     173             :         else
     174   751225855 :                 offset = irec->br_startoff;
     175             : 
     176             :         /*
     177             :          * If the caller thinks this could be a shared bmbt extent (IOWs,
     178             :          * any data fork extent of a reflink inode) then we have to use the
     179             :          * range rmap lookup to make sure we get the correct owner/offset.
     180             :          */
     181   753070086 :         if (info->is_shared) {
     182   257623726 :                 error = xfs_rmap_lookup_le_range(*curp, bno, owner, offset,
     183             :                                 rflags, rmap, &has_rmap);
     184             :         } else {
     185   495446360 :                 error = xfs_rmap_lookup_le(*curp, bno, owner, offset,
     186             :                                 rflags, rmap, &has_rmap);
     187             :         }
     188   753284839 :         if (!xchk_should_check_xref(info->sc, &error, curp))
     189             :                 return false;
     190             : 
     191   753216099 :         if (!has_rmap)
     192           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     193             :                         irec->br_startoff);
     194   753216099 :         return has_rmap;
     195             : }
     196             : 
     197             : /* Make sure that we have rmapbt records for this data/attr fork extent. */
     198             : STATIC void
     199   754874564 : xchk_bmap_xref_rmap(
     200             :         struct xchk_bmap_info   *info,
     201             :         struct xfs_bmbt_irec    *irec,
     202             :         xfs_agblock_t           bno)
     203             : {
     204   754874564 :         struct xfs_rmap_irec    rmap;
     205   754874564 :         unsigned long long      rmap_end;
     206   754874564 :         uint64_t                owner = info->sc->ip->i_ino;
     207             : 
     208   754874564 :         if (xchk_skip_xref(info->sc->sm))
     209     3510655 :                 return;
     210             : 
     211             :         /* Find the rmap record for this irec. */
     212   754874573 :         if (!xchk_bmap_get_rmap(info, irec, bno, owner, &rmap))
     213             :                 return;
     214             : 
     215             :         /*
     216             :          * The rmap must be an exact match for this incore file mapping record,
     217             :          * which may have arisen from multiple ondisk records.
     218             :          */
     219   751592714 :         if (rmap.rm_startblock != bno)
     220           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     221             :                                 irec->br_startoff);
     222             : 
     223   751592714 :         rmap_end = (unsigned long long)rmap.rm_startblock + rmap.rm_blockcount;
     224   751592714 :         if (rmap_end != bno + irec->br_blockcount)
     225           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     226             :                                 irec->br_startoff);
     227             : 
     228             :         /* Check the logical offsets. */
     229   751592714 :         if (rmap.rm_offset != irec->br_startoff)
     230           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     231             :                                 irec->br_startoff);
     232             : 
     233   751592714 :         rmap_end = (unsigned long long)rmap.rm_offset + rmap.rm_blockcount;
     234   751592714 :         if (rmap_end != irec->br_startoff + irec->br_blockcount)
     235           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     236             :                                 irec->br_startoff);
     237             : 
     238             :         /* Check the owner */
     239   751592714 :         if (rmap.rm_owner != owner)
     240           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     241             :                                 irec->br_startoff);
     242             : 
     243             :         /*
     244             :          * Check for discrepancies between the unwritten flag in the irec and
     245             :          * the rmap.  Note that the (in-memory) CoW fork distinguishes between
     246             :          * unwritten and written extents, but we don't track that in the rmap
     247             :          * records because the blocks are owned (on-disk) by the refcountbt,
     248             :          * which doesn't track unwritten state.
     249             :          */
     250   751592714 :         if (!!(irec->br_state == XFS_EXT_UNWRITTEN) !=
     251   751592714 :             !!(rmap.rm_flags & XFS_RMAP_UNWRITTEN))
     252           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     253             :                                 irec->br_startoff);
     254             : 
     255   751592714 :         if (!!(info->whichfork == XFS_ATTR_FORK) !=
     256   751592714 :             !!(rmap.rm_flags & XFS_RMAP_ATTR_FORK))
     257           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     258             :                                 irec->br_startoff);
     259   751592714 :         if (rmap.rm_flags & XFS_RMAP_BMBT_BLOCK)
     260           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     261             :                                 irec->br_startoff);
     262             : }
     263             : 
     264             : /* Make sure that we have rmapbt records for this COW fork extent. */
     265             : STATIC void
     266     1973702 : xchk_bmap_xref_rmap_cow(
     267             :         struct xchk_bmap_info   *info,
     268             :         struct xfs_bmbt_irec    *irec,
     269             :         xfs_agblock_t           bno)
     270             : {
     271     1973702 :         struct xfs_rmap_irec    rmap;
     272     1973702 :         unsigned long long      rmap_end;
     273     1973702 :         uint64_t                owner = XFS_RMAP_OWN_COW;
     274             : 
     275     1973702 :         if (!info->sc->sa.rmap_cur || xchk_skip_xref(info->sc->sm))
     276      219287 :                 return;
     277             : 
     278             :         /* Find the rmap record for this irec. */
     279     1754415 :         if (!xchk_bmap_get_rmap(info, irec, bno, owner, &rmap))
     280             :                 return;
     281             : 
     282             :         /*
     283             :          * CoW staging extents are owned by the refcount btree, so the rmap
     284             :          * can start before and end after the physical space allocated to this
     285             :          * mapping.  There are no offsets to check.
     286             :          */
     287     1754433 :         if (rmap.rm_startblock > bno)
     288           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     289             :                                 irec->br_startoff);
     290             : 
     291     1754433 :         rmap_end = (unsigned long long)rmap.rm_startblock + rmap.rm_blockcount;
     292     1754433 :         if (rmap_end < bno + irec->br_blockcount)
     293           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     294             :                                 irec->br_startoff);
     295             : 
     296             :         /* Check the owner */
     297     1754433 :         if (rmap.rm_owner != owner)
     298           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     299             :                                 irec->br_startoff);
     300             : 
     301             :         /*
     302             :          * No flags allowed.  Note that the (in-memory) CoW fork distinguishes
     303             :          * between unwritten and written extents, but we don't track that in
     304             :          * the rmap records because the blocks are owned (on-disk) by the
     305             :          * refcountbt, which doesn't track unwritten state.
     306             :          */
     307     1754433 :         if (rmap.rm_flags & XFS_RMAP_ATTR_FORK)
     308           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     309             :                                 irec->br_startoff);
     310     1754433 :         if (rmap.rm_flags & XFS_RMAP_BMBT_BLOCK)
     311           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     312             :                                 irec->br_startoff);
     313     1754433 :         if (rmap.rm_flags & XFS_RMAP_UNWRITTEN)
     314           0 :                 xchk_fblock_xref_set_corrupt(info->sc, info->whichfork,
     315             :                                 irec->br_startoff);
     316             : }
     317             : 
     318             : /* Cross-reference a single rtdev extent record. */
     319             : STATIC void
     320   185909724 : xchk_bmap_rt_iextent_xref(
     321             :         struct xfs_inode        *ip,
     322             :         struct xchk_bmap_info   *info,
     323             :         struct xfs_bmbt_irec    *irec)
     324             : {
     325   185909724 :         struct xfs_owner_info   oinfo;
     326   185909724 :         struct xfs_mount        *mp = ip->i_mount;
     327   185909724 :         xfs_rgnumber_t          rgno;
     328   185909724 :         xfs_rgblock_t           rgbno;
     329   185909724 :         int                     error;
     330             : 
     331   185909724 :         if (!xfs_has_rtrmapbt(mp)) {
     332     3390552 :                 xchk_rt_init(info->sc, &info->sc->sr,
     333             :                                 XCHK_RTLOCK_BITMAP_SHARED);
     334     3397801 :                 xchk_xref_is_used_rt_space(info->sc, irec->br_startblock,
     335     3397801 :                                 irec->br_blockcount);
     336     3404910 :                 xchk_rt_unlock(info->sc, &info->sc->sr);
     337     3401052 :                 return;
     338             :         }
     339             : 
     340   182519172 :         rgbno = xfs_rtb_to_rgbno(mp, irec->br_startblock, &rgno);
     341   182469926 :         error = xchk_rtgroup_init(info->sc, rgno, &info->sc->sr,
     342             :                         XCHK_RTGLOCK_ALL);
     343   182711146 :         if (!xchk_fblock_process_error(info->sc, info->whichfork,
     344             :                         irec->br_startoff, &error))
     345           0 :                 goto out_free;
     346             : 
     347   182812876 :         xchk_xref_is_used_rt_space(info->sc, irec->br_startblock,
     348   182812876 :                         irec->br_blockcount);
     349   182720154 :         switch (info->whichfork) {
     350   182500860 :         case XFS_DATA_FORK:
     351   182500860 :                 xchk_bmap_xref_rmap(info, irec, rgbno);
     352   182513446 :                 if (!xfs_is_reflink_inode(info->sc->ip)) {
     353    30825926 :                         xfs_rmap_ino_owner(&oinfo, info->sc->ip->i_ino,
     354             :                                         info->whichfork, irec->br_startoff);
     355    30825926 :                         xchk_xref_is_only_rt_owned_by(info->sc, rgbno,
     356    30825926 :                                         irec->br_blockcount, &oinfo);
     357    30841135 :                         xchk_xref_is_not_rt_shared(info->sc, rgbno,
     358    30841135 :                                         irec->br_blockcount);
     359             :                 }
     360   182527868 :                 xchk_xref_is_not_rt_cow_staging(info->sc, rgbno,
     361   182527868 :                                 irec->br_blockcount);
     362   182527868 :                 break;
     363      219294 :         case XFS_COW_FORK:
     364      219294 :                 xchk_bmap_xref_rmap_cow(info, irec, rgbno);
     365      219284 :                 xchk_xref_is_only_rt_owned_by(info->sc, rgbno,
     366      219284 :                                 irec->br_blockcount, &XFS_RMAP_OINFO_COW);
     367      219297 :                 xchk_xref_is_rt_cow_staging(info->sc, rgbno,
     368      219297 :                                 irec->br_blockcount);
     369      219297 :                 xchk_xref_is_not_rt_shared(info->sc, rgbno,
     370      219297 :                                 irec->br_blockcount);
     371      219297 :                 break;
     372             :         }
     373             : 
     374   182689535 : out_free:
     375   182689535 :         xchk_rtgroup_btcur_free(&info->sc->sr);
     376   182803423 :         xchk_rtgroup_free(info->sc, &info->sc->sr);
     377             : }
     378             : 
     379             : /* Cross-reference a single datadev extent record. */
     380             : STATIC void
     381   574278686 : xchk_bmap_iextent_xref(
     382             :         struct xfs_inode        *ip,
     383             :         struct xchk_bmap_info   *info,
     384             :         struct xfs_bmbt_irec    *irec)
     385             : {
     386   574278686 :         struct xfs_owner_info   oinfo;
     387   574278686 :         struct xfs_mount        *mp = info->sc->mp;
     388   574278686 :         xfs_agnumber_t          agno;
     389   574278686 :         xfs_agblock_t           agbno;
     390   574278686 :         xfs_extlen_t            len;
     391   574278686 :         int                     error;
     392             : 
     393   574278686 :         agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock);
     394   574278686 :         agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock);
     395   574224805 :         len = irec->br_blockcount;
     396             : 
     397   574224805 :         error = xchk_ag_init_existing(info->sc, agno, &info->sc->sa);
     398   574391616 :         if (!xchk_fblock_process_error(info->sc, info->whichfork,
     399             :                         irec->br_startoff, &error))
     400           0 :                 goto out_free;
     401             : 
     402   574359946 :         xchk_xref_is_used_space(info->sc, agbno, len);
     403   574344373 :         xchk_xref_is_not_inode_chunk(info->sc, agbno, len);
     404   574379202 :         switch (info->whichfork) {
     405   570316139 :         case XFS_DATA_FORK:
     406   570316139 :                 xchk_bmap_xref_rmap(info, irec, agbno);
     407   570265397 :                 if (!xfs_is_reflink_inode(info->sc->ip)) {
     408   464067889 :                         xfs_rmap_ino_owner(&oinfo, info->sc->ip->i_ino,
     409             :                                         info->whichfork, irec->br_startoff);
     410   464067889 :                         xchk_xref_is_only_owned_by(info->sc, agbno,
     411   464067889 :                                         irec->br_blockcount, &oinfo);
     412   464110768 :                         xchk_xref_is_not_shared(info->sc, agbno,
     413   464110768 :                                         irec->br_blockcount);
     414             :                 }
     415   570301769 :                 xchk_xref_is_not_cow_staging(info->sc, agbno,
     416   570301769 :                                 irec->br_blockcount);
     417   570301769 :                 break;
     418     2308534 :         case XFS_ATTR_FORK:
     419     2308534 :                 xchk_bmap_xref_rmap(info, irec, agbno);
     420     2305077 :                 xfs_rmap_ino_owner(&oinfo, info->sc->ip->i_ino,
     421             :                                 info->whichfork, irec->br_startoff);
     422     2305077 :                 xchk_xref_is_only_owned_by(info->sc, agbno, irec->br_blockcount,
     423             :                                 &oinfo);
     424     2315458 :                 xchk_xref_is_not_shared(info->sc, agbno,
     425     2315458 :                                 irec->br_blockcount);
     426     2313002 :                 xchk_xref_is_not_cow_staging(info->sc, agbno,
     427     2313002 :                                 irec->br_blockcount);
     428     2313002 :                 break;
     429     1754529 :         case XFS_COW_FORK:
     430     1754529 :                 xchk_bmap_xref_rmap_cow(info, irec, agbno);
     431     1754407 :                 xchk_xref_is_only_owned_by(info->sc, agbno, irec->br_blockcount,
     432             :                                 &XFS_RMAP_OINFO_COW);
     433     1754639 :                 xchk_xref_is_cow_staging(info->sc, agbno,
     434     1754639 :                                 irec->br_blockcount);
     435     1754619 :                 xchk_xref_is_not_shared(info->sc, agbno,
     436     1754619 :                                 irec->br_blockcount);
     437     1754619 :                 break;
     438             :         }
     439             : 
     440   574368582 : out_free:
     441   574368582 :         xchk_ag_free(info->sc, &info->sc->sa);
     442   574409850 : }
     443             : 
     444             : /*
     445             :  * Directories and attr forks should never have blocks that can't be addressed
     446             :  * by a xfs_dablk_t.
     447             :  */
     448             : STATIC void
     449   760101297 : xchk_bmap_dirattr_extent(
     450             :         struct xfs_inode        *ip,
     451             :         struct xchk_bmap_info   *info,
     452             :         struct xfs_bmbt_irec    *irec)
     453             : {
     454   760101297 :         struct xfs_mount        *mp = ip->i_mount;
     455   760101297 :         xfs_fileoff_t           off;
     456             : 
     457   760101297 :         if (!S_ISDIR(VFS_I(ip)->i_mode) && info->whichfork != XFS_ATTR_FORK)
     458             :                 return;
     459             : 
     460     3218002 :         if (!xfs_verify_dablk(mp, irec->br_startoff))
     461           0 :                 xchk_fblock_set_corrupt(info->sc, info->whichfork,
     462             :                                 irec->br_startoff);
     463             : 
     464     3212203 :         off = irec->br_startoff + irec->br_blockcount - 1;
     465     3212203 :         if (!xfs_verify_dablk(mp, off))
     466           0 :                 xchk_fblock_set_corrupt(info->sc, info->whichfork, off);
     467             : }
     468             : 
     469             : /* Scrub a single extent record. */
     470             : STATIC void
     471   760087718 : xchk_bmap_iextent(
     472             :         struct xfs_inode        *ip,
     473             :         struct xchk_bmap_info   *info,
     474             :         struct xfs_bmbt_irec    *irec)
     475             : {
     476   760087718 :         struct xfs_mount        *mp = info->sc->mp;
     477             : 
     478             :         /*
     479             :          * Check for out-of-order extents.  This record could have come
     480             :          * from the incore list, for which there is no ordering check.
     481             :          */
     482   760087718 :         if (irec->br_startoff < info->prev_rec.br_startoff +
     483   760087718 :                                 info->prev_rec.br_blockcount)
     484           0 :                 xchk_fblock_set_corrupt(info->sc, info->whichfork,
     485             :                                 irec->br_startoff);
     486             : 
     487   760087718 :         if (!xfs_verify_fileext(mp, irec->br_startoff, irec->br_blockcount))
     488           0 :                 xchk_fblock_set_corrupt(info->sc, info->whichfork,
     489             :                                 irec->br_startoff);
     490             : 
     491   760075048 :         xchk_bmap_dirattr_extent(ip, info, irec);
     492             : 
     493             :         /* Make sure the extent points to a valid place. */
     494   946095828 :         if (info->is_rt &&
     495   185888351 :             !xfs_verify_rtbext(mp, irec->br_startblock, irec->br_blockcount))
     496           0 :                 xchk_fblock_set_corrupt(info->sc, info->whichfork,
     497             :                                 irec->br_startoff);
     498  1334485000 :         if (!info->is_rt &&
     499   574276758 :             !xfs_verify_fsbext(mp, irec->br_startblock, irec->br_blockcount))
     500           0 :                 xchk_fblock_set_corrupt(info->sc, info->whichfork,
     501             :                                 irec->br_startoff);
     502             : 
     503             :         /* We don't allow unwritten extents on attr forks. */
     504   760208242 :         if (irec->br_state == XFS_EXT_UNWRITTEN &&
     505    33480884 :             info->whichfork == XFS_ATTR_FORK)
     506           0 :                 xchk_fblock_set_corrupt(info->sc, info->whichfork,
     507             :                                 irec->br_startoff);
     508             : 
     509   760208242 :         if (info->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     510             :                 return;
     511             : 
     512   760208242 :         if (info->is_rt)
     513   185916868 :                 xchk_bmap_rt_iextent_xref(ip, info, irec);
     514             :         else
     515   574291374 :                 xchk_bmap_iextent_xref(ip, info, irec);
     516             : }
     517             : 
     518             : /* Scrub a bmbt record. */
     519             : STATIC int
     520   703954900 : xchk_bmapbt_rec(
     521             :         struct xchk_btree       *bs,
     522             :         const union xfs_btree_rec *rec)
     523             : {
     524   703954900 :         struct xfs_bmbt_irec    irec;
     525   703954900 :         struct xfs_bmbt_irec    iext_irec;
     526   703954900 :         struct xfs_iext_cursor  icur;
     527   703954900 :         struct xchk_bmap_info   *info = bs->private;
     528   703954900 :         struct xfs_inode        *ip = bs->cur->bc_ino.ip;
     529   703954900 :         struct xfs_buf          *bp = NULL;
     530   703954900 :         struct xfs_btree_block  *block;
     531   703954900 :         struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, info->whichfork);
     532   703949103 :         uint64_t                owner;
     533   703949103 :         int                     i;
     534             : 
     535             :         /*
     536             :          * Check the owners of the btree blocks up to the level below
     537             :          * the root since the verifiers don't do that.
     538             :          */
     539   703949103 :         if (xfs_has_crc(bs->cur->bc_mp) &&
     540   703954674 :             bs->cur->bc_levels[0].ptr == 1) {
     541    13631558 :                 for (i = 0; i < bs->cur->bc_nlevels - 1; i++) {
     542     8253505 :                         block = xfs_btree_get_block(bs->cur, i, &bp);
     543     8253546 :                         owner = be64_to_cpu(block->bb_u.l.bb_owner);
     544     8253546 :                         if (owner != ip->i_ino)
     545           0 :                                 xchk_fblock_set_corrupt(bs->sc,
     546             :                                                 info->whichfork, 0);
     547             :                 }
     548             :         }
     549             : 
     550             :         /*
     551             :          * Check that the incore extent tree contains an extent that matches
     552             :          * this one exactly.  We validate those cached bmaps later, so we don't
     553             :          * need to check them here.  If the incore extent tree was just loaded
     554             :          * from disk by the scrubber, we assume that its contents match what's
     555             :          * on disk (we still hold the ILOCK) and skip the equivalence check.
     556             :          */
     557   703949144 :         if (!info->was_loaded)
     558             :                 return 0;
     559             : 
     560   703965745 :         xfs_bmbt_disk_get_all(&rec->bmbt, &irec);
     561   703972083 :         if (xfs_bmap_validate_extent(ip, info->whichfork, &irec) != NULL) {
     562           0 :                 xchk_fblock_set_corrupt(bs->sc, info->whichfork,
     563             :                                 irec.br_startoff);
     564           0 :                 return 0;
     565             :         }
     566             : 
     567   704008185 :         if (!xfs_iext_lookup_extent(ip, ifp, irec.br_startoff, &icur,
     568   704215139 :                                 &iext_irec) ||
     569   704215139 :             irec.br_startoff != iext_irec.br_startoff ||
     570   704220229 :             irec.br_startblock != iext_irec.br_startblock ||
     571   704222807 :             irec.br_blockcount != iext_irec.br_blockcount ||
     572   704223704 :             irec.br_state != iext_irec.br_state)
     573           0 :                 xchk_fblock_set_corrupt(bs->sc, info->whichfork,
     574             :                                 irec.br_startoff);
     575             :         return 0;
     576             : }
     577             : 
     578             : /* Scan the btree records. */
     579             : STATIC int
     580     2508660 : xchk_bmap_btree(
     581             :         struct xfs_scrub        *sc,
     582             :         int                     whichfork,
     583             :         struct xchk_bmap_info   *info)
     584             : {
     585     2508660 :         struct xfs_owner_info   oinfo;
     586     2508660 :         struct xfs_ifork        *ifp = xfs_ifork_ptr(sc->ip, whichfork);
     587     2508420 :         struct xfs_mount        *mp = sc->mp;
     588     2508420 :         struct xfs_inode        *ip = sc->ip;
     589     2508420 :         struct xfs_btree_cur    *cur;
     590     2508420 :         int                     error;
     591             : 
     592             :         /* Load the incore bmap cache if it's not loaded. */
     593     2508420 :         info->was_loaded = !xfs_need_iread_extents(ifp);
     594             : 
     595     2508429 :         error = xfs_iread_extents(sc->tp, ip, whichfork);
     596     2508591 :         if (!xchk_fblock_process_error(sc, whichfork, 0, &error))
     597           0 :                 goto out;
     598             : 
     599             :         /* Check the btree structure. */
     600     2508677 :         cur = xfs_bmbt_init_cursor(mp, sc->tp, ip, whichfork);
     601     2509260 :         xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork);
     602     2509260 :         error = xchk_btree(sc, cur, xchk_bmapbt_rec, &oinfo, info);
     603     2509343 :         xfs_btree_del_cursor(cur, error);
     604     2509307 : out:
     605     2509307 :         return error;
     606             : }
     607             : 
     608             : struct xchk_bmap_check_rmap_info {
     609             :         struct xfs_scrub        *sc;
     610             :         int                     whichfork;
     611             :         struct xfs_iext_cursor  icur;
     612             : };
     613             : 
     614             : /* Can we find bmaps that fit this rmap? */
     615             : STATIC int
     616 78191847796 : xchk_bmap_check_rmap(
     617             :         struct xfs_btree_cur            *cur,
     618             :         const struct xfs_rmap_irec      *rec,
     619             :         void                            *priv)
     620             : {
     621 78191847796 :         struct xfs_bmbt_irec            irec;
     622 78191847796 :         struct xfs_rmap_irec            check_rec;
     623 78191847796 :         struct xchk_bmap_check_rmap_info        *sbcri = priv;
     624 78191847796 :         struct xfs_ifork                *ifp;
     625 78191847796 :         struct xfs_scrub                *sc = sbcri->sc;
     626 78191847796 :         bool                            have_map;
     627             : 
     628             :         /* Is this even the right fork? */
     629 78191847796 :         if (rec->rm_owner != sc->ip->i_ino)
     630             :                 return 0;
     631       15016 :         if ((sbcri->whichfork == XFS_ATTR_FORK) ^
     632       15016 :             !!(rec->rm_flags & XFS_RMAP_ATTR_FORK))
     633             :                 return 0;
     634           0 :         if (rec->rm_flags & XFS_RMAP_BMBT_BLOCK)
     635             :                 return 0;
     636             : 
     637             :         /* Now look up the bmbt record. */
     638           0 :         ifp = xfs_ifork_ptr(sc->ip, sbcri->whichfork);
     639           0 :         if (!ifp) {
     640           0 :                 xchk_fblock_set_corrupt(sc, sbcri->whichfork,
     641           0 :                                 rec->rm_offset);
     642           0 :                 goto out;
     643             :         }
     644           0 :         have_map = xfs_iext_lookup_extent(sc->ip, ifp, rec->rm_offset,
     645             :                         &sbcri->icur, &irec);
     646           0 :         if (!have_map)
     647           0 :                 xchk_fblock_set_corrupt(sc, sbcri->whichfork,
     648           0 :                                 rec->rm_offset);
     649             :         /*
     650             :          * bmap extent record lengths are constrained to 2^21 blocks in length
     651             :          * because of space constraints in the on-disk metadata structure.
     652             :          * However, rmap extent record lengths are constrained only by AG
     653             :          * length, so we have to loop through the bmbt to make sure that the
     654             :          * entire rmap is covered by bmbt records.
     655             :          */
     656           0 :         check_rec = *rec;
     657           0 :         while (have_map) {
     658           0 :                 xfs_fsblock_t   startblock;
     659             : 
     660           0 :                 if (irec.br_startoff != check_rec.rm_offset)
     661           0 :                         xchk_fblock_set_corrupt(sc, sbcri->whichfork,
     662             :                                         check_rec.rm_offset);
     663           0 :                 if (cur->bc_btnum == XFS_BTNUM_RMAP)
     664           0 :                         startblock = XFS_AGB_TO_FSB(sc->mp,
     665             :                                         cur->bc_ag.pag->pag_agno,
     666             :                                         check_rec.rm_startblock);
     667             :                 else
     668           0 :                         startblock = xfs_rgbno_to_rtb(sc->mp,
     669           0 :                                         cur->bc_ino.rtg->rtg_rgno,
     670             :                                         check_rec.rm_startblock);
     671           0 :                 if (irec.br_startblock != startblock)
     672           0 :                         xchk_fblock_set_corrupt(sc, sbcri->whichfork,
     673             :                                         check_rec.rm_offset);
     674           0 :                 if (irec.br_blockcount > check_rec.rm_blockcount)
     675           0 :                         xchk_fblock_set_corrupt(sc, sbcri->whichfork,
     676             :                                         check_rec.rm_offset);
     677           0 :                 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     678             :                         break;
     679           0 :                 check_rec.rm_startblock += irec.br_blockcount;
     680           0 :                 check_rec.rm_offset += irec.br_blockcount;
     681           0 :                 check_rec.rm_blockcount -= irec.br_blockcount;
     682           0 :                 if (check_rec.rm_blockcount == 0)
     683             :                         break;
     684           0 :                 have_map = xfs_iext_next_extent(ifp, &sbcri->icur, &irec);
     685           0 :                 if (!have_map)
     686           0 :                         xchk_fblock_set_corrupt(sc, sbcri->whichfork,
     687             :                                         check_rec.rm_offset);
     688             :         }
     689             : 
     690           0 : out:
     691           0 :         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     692           0 :                 return -ECANCELED;
     693             :         return 0;
     694             : }
     695             : 
     696             : /* Make sure each rmap has a corresponding bmbt entry. */
     697             : STATIC int
     698      872047 : xchk_bmap_check_ag_rmaps(
     699             :         struct xfs_scrub                *sc,
     700             :         int                             whichfork,
     701             :         struct xfs_perag                *pag)
     702             : {
     703      872047 :         struct xchk_bmap_check_rmap_info        sbcri;
     704      872047 :         struct xfs_btree_cur            *cur;
     705      872047 :         struct xfs_buf                  *agf;
     706      872047 :         int                             error;
     707             : 
     708      872047 :         error = xfs_alloc_read_agf(pag, sc->tp, 0, &agf);
     709      872043 :         if (error)
     710             :                 return error;
     711             : 
     712      872045 :         cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, pag);
     713             : 
     714      872055 :         sbcri.sc = sc;
     715      872055 :         sbcri.whichfork = whichfork;
     716      872055 :         error = xfs_rmap_query_all(cur, xchk_bmap_check_rmap, &sbcri);
     717      872050 :         if (error == -ECANCELED)
     718           0 :                 error = 0;
     719             : 
     720      872050 :         xfs_btree_del_cursor(cur, error);
     721      872060 :         xfs_trans_brelse(sc->tp, agf);
     722      872060 :         return error;
     723             : }
     724             : 
     725             : /* Make sure each rt rmap has a corresponding bmbt entry. */
     726             : STATIC int
     727      949243 : xchk_bmap_check_rt_rmaps(
     728             :         struct xfs_scrub                *sc,
     729             :         struct xfs_rtgroup              *rtg)
     730             : {
     731      949243 :         struct xchk_bmap_check_rmap_info sbcri;
     732      949243 :         struct xfs_btree_cur            *cur;
     733      949243 :         int                             error;
     734             : 
     735      949243 :         xfs_rtgroup_lock(NULL, rtg, XFS_RTGLOCK_RMAP);
     736      948594 :         cur = xfs_rtrmapbt_init_cursor(sc->mp, sc->tp, rtg, rtg->rtg_rmapip);
     737             : 
     738      948580 :         sbcri.sc = sc;
     739      948580 :         sbcri.whichfork = XFS_DATA_FORK;
     740      948580 :         error = xfs_rmap_query_all(cur, xchk_bmap_check_rmap, &sbcri);
     741      949245 :         if (error == -ECANCELED)
     742           0 :                 error = 0;
     743             : 
     744      949245 :         xfs_btree_del_cursor(cur, error);
     745      949243 :         xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_RMAP);
     746      949244 :         return error;
     747             : }
     748             : 
     749             : /*
     750             :  * Decide if we want to walk every rmap btree in the fs to make sure that each
     751             :  * rmap for this file fork has corresponding bmbt entries.
     752             :  */
     753             : static bool
     754    85186619 : xchk_bmap_want_check_rmaps(
     755             :         struct xchk_bmap_info   *info)
     756             : {
     757    85186619 :         struct xfs_scrub        *sc = info->sc;
     758    85186619 :         struct xfs_ifork        *ifp;
     759             : 
     760    85186619 :         if (!xfs_has_rmapbt(sc->mp))
     761             :                 return false;
     762    82063490 :         if (info->whichfork == XFS_COW_FORK)
     763             :                 return false;
     764    75375583 :         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     765             :                 return false;
     766             : 
     767             :         /*
     768             :          * The inode repair code zaps broken inode forks by resetting them back
     769             :          * to EXTENTS format and zero extent records.  If we encounter a fork
     770             :          * in this state along with evidence that the fork isn't supposed to be
     771             :          * empty, we need to scan the reverse mappings to decide if we're going
     772             :          * to rebuild the fork.  Data forks with nonzero file size are scanned.
     773             :          * xattr forks are never empty of content, so they are always scanned.
     774             :          */
     775    75361265 :         ifp = xfs_ifork_ptr(sc->ip, info->whichfork);
     776    75397634 :         if (ifp->if_format == XFS_DINODE_FMT_EXTENTS && ifp->if_nextents == 0) {
     777    42275399 :                 if (info->whichfork == XFS_DATA_FORK &&
     778    42262189 :                     i_size_read(VFS_I(sc->ip)) == 0)
     779             :                         return false;
     780             : 
     781      376402 :                 return true;
     782             :         }
     783             : 
     784             :         return false;
     785             : }
     786             : 
     787             : /* Make sure each rmap has a corresponding bmbt entry. */
     788             : STATIC int
     789      376399 : xchk_bmap_check_rmaps(
     790             :         struct xfs_scrub        *sc,
     791             :         int                     whichfork)
     792             : {
     793      376399 :         struct xfs_perag        *pag;
     794      376399 :         xfs_agnumber_t          agno;
     795      376399 :         int                     error;
     796             : 
     797      376399 :         if (xfs_ifork_is_realtime(sc->ip, whichfork)) {
     798      189839 :                 struct xfs_rtgroup      *rtg;
     799      189839 :                 xfs_rgnumber_t          rgno;
     800             : 
     801     1139083 :                 for_each_rtgroup(sc->mp, rgno, rtg) {
     802      949243 :                         error = xchk_bmap_check_rt_rmaps(sc, rtg);
     803      949244 :                         if (error ||
     804      949244 :                             (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) {
     805           0 :                                 xfs_rtgroup_rele(rtg);
     806           0 :                                 return error;
     807             :                         }
     808             :                 }
     809             : 
     810             :                 return 0;
     811             :         }
     812             : 
     813     1058609 :         for_each_perag(sc->mp, agno, pag) {
     814      872055 :                 error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag);
     815      872050 :                 if (error ||
     816      872050 :                     (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) {
     817           0 :                         xfs_perag_rele(pag);
     818           0 :                         return error;
     819             :                 }
     820             :         }
     821             : 
     822             :         return 0;
     823             : }
     824             : 
     825             : /* Scrub a delalloc reservation from the incore extent map tree. */
     826             : STATIC void
     827         824 : xchk_bmap_iextent_delalloc(
     828             :         struct xfs_inode        *ip,
     829             :         struct xchk_bmap_info   *info,
     830             :         struct xfs_bmbt_irec    *irec)
     831             : {
     832         824 :         struct xfs_mount        *mp = info->sc->mp;
     833             : 
     834             :         /*
     835             :          * Check for out-of-order extents.  This record could have come
     836             :          * from the incore list, for which there is no ordering check.
     837             :          */
     838         824 :         if (irec->br_startoff < info->prev_rec.br_startoff +
     839         824 :                                 info->prev_rec.br_blockcount)
     840           0 :                 xchk_fblock_set_corrupt(info->sc, info->whichfork,
     841             :                                 irec->br_startoff);
     842             : 
     843         824 :         if (!xfs_verify_fileext(mp, irec->br_startoff, irec->br_blockcount))
     844           0 :                 xchk_fblock_set_corrupt(info->sc, info->whichfork,
     845             :                                 irec->br_startoff);
     846             : 
     847             :         /* Make sure the extent points to a valid place. */
     848         824 :         if (irec->br_blockcount > XFS_MAX_BMBT_EXTLEN)
     849           0 :                 xchk_fblock_set_corrupt(info->sc, info->whichfork,
     850             :                                 irec->br_startoff);
     851         824 : }
     852             : 
     853             : /* Decide if this individual fork mapping is ok. */
     854             : static bool
     855             : xchk_bmap_iext_mapping(
     856             :         struct xchk_bmap_info           *info,
     857             :         const struct xfs_bmbt_irec      *irec)
     858             : {
     859             :         /* There should never be a "hole" extent in either extent list. */
     860   760306789 :         if (irec->br_startblock == HOLESTARTBLOCK)
     861             :                 return false;
     862   760306789 :         if (irec->br_blockcount > XFS_MAX_BMBT_EXTLEN)
     863             :                 return false;
     864             :         return true;
     865             : }
     866             : 
     867             : /* Are these two mappings contiguous with each other? */
     868             : static inline bool
     869   725458577 : xchk_are_bmaps_contiguous(
     870             :         const struct xfs_bmbt_irec      *b1,
     871             :         const struct xfs_bmbt_irec      *b2)
     872             : {
     873             :         /* Don't try to combine unallocated mappings. */
     874  1450976284 :         if (!xfs_bmap_is_real_extent(b1))
     875             :                 return false;
     876  1450966973 :         if (!xfs_bmap_is_real_extent(b2))
     877             :                 return false;
     878             : 
     879             :         /* Does b2 come right after b1 in the logical and physical range? */
     880   725457740 :         if (b1->br_startoff + b1->br_blockcount != b2->br_startoff)
     881             :                 return false;
     882   255496447 :         if (b1->br_startblock + b1->br_blockcount != b2->br_startblock)
     883             :                 return false;
     884    11870035 :         if (b1->br_state != b2->br_state)
     885    11868036 :                 return false;
     886             :         return true;
     887             : }
     888             : 
     889             : /*
     890             :  * Walk the incore extent records, accumulating consecutive contiguous records
     891             :  * into a single incore mapping.  Returns true if @irec has been set to a
     892             :  * mapping or false if there are no more mappings.  Caller must ensure that
     893             :  * @info.icur is zeroed before the first call.
     894             :  */
     895             : static bool
     896   845577188 : xchk_bmap_iext_iter(
     897             :         struct xchk_bmap_info   *info,
     898             :         struct xfs_bmbt_irec    *irec)
     899             : {
     900   845577188 :         struct xfs_bmbt_irec    got;
     901   845577188 :         struct xfs_ifork        *ifp;
     902   845577188 :         unsigned int            nr = 0;
     903             : 
     904   845577188 :         ifp = xfs_ifork_ptr(info->sc->ip, info->whichfork);
     905             : 
     906             :         /* Advance to the next iextent record and check the mapping. */
     907   845430786 :         xfs_iext_next(ifp, &info->icur);
     908   845389513 :         if (!xfs_iext_get_extent(ifp, &info->icur, irec))
     909             :                 return false;
     910             : 
     911   760304687 :         if (!xchk_bmap_iext_mapping(info, irec)) {
     912           0 :                 xchk_fblock_set_corrupt(info->sc, info->whichfork,
     913             :                                 irec->br_startoff);
     914           0 :                 return false;
     915             :         }
     916             :         nr++;
     917             : 
     918             :         /*
     919             :          * Iterate subsequent iextent records and merge them with the one
     920             :          * that we just read, if possible.
     921             :          */
     922   760306789 :         while (xfs_iext_peek_next_extent(ifp, &info->icur, &got)) {
     923   725456617 :                 if (!xchk_are_bmaps_contiguous(irec, &got))
     924             :                         break;
     925             : 
     926        2102 :                 if (!xchk_bmap_iext_mapping(info, &got)) {
     927           0 :                         xchk_fblock_set_corrupt(info->sc, info->whichfork,
     928             :                                         got.br_startoff);
     929           0 :                         return false;
     930             :                 }
     931        2102 :                 nr++;
     932             : 
     933        2102 :                 irec->br_blockcount += got.br_blockcount;
     934        2102 :                 xfs_iext_next(ifp, &info->icur);
     935             :         }
     936             : 
     937             :         /*
     938             :          * If the merged mapping could be expressed with fewer bmbt records
     939             :          * than we actually found, notify the user that this fork could be
     940             :          * optimized.  CoW forks only exist in memory so we ignore them.
     941             :          */
     942   760197358 :         if (nr > 1 && info->whichfork != XFS_COW_FORK &&
     943         119 :             howmany_64(irec->br_blockcount, XFS_MAX_BMBT_EXTLEN) < nr)
     944           1 :                 xchk_ino_set_preen(info->sc, info->sc->ip->i_ino);
     945             : 
     946             :         return true;
     947             : }
     948             : 
     949             : /*
     950             :  * Scrub an inode fork's block mappings.
     951             :  *
     952             :  * First we scan every record in every btree block, if applicable.
     953             :  * Then we unconditionally scan the incore extent cache.
     954             :  */
     955             : STATIC int
     956   403093082 : xchk_bmap(
     957             :         struct xfs_scrub        *sc,
     958             :         int                     whichfork)
     959             : {
     960   403093082 :         struct xfs_bmbt_irec    irec;
     961   403093082 :         struct xchk_bmap_info   info = { NULL };
     962   403093082 :         struct xfs_mount        *mp = sc->mp;
     963   403093082 :         struct xfs_inode        *ip = sc->ip;
     964   403093082 :         struct xfs_ifork        *ifp = xfs_ifork_ptr(ip, whichfork);
     965   402518120 :         xfs_fileoff_t           endoff;
     966   402518120 :         int                     error = 0;
     967             : 
     968             :         /* Non-existent forks can be ignored. */
     969   402518120 :         if (!ifp)
     970             :                 return -ENOENT;
     971             : 
     972   275642043 :         info.is_rt = xfs_ifork_is_realtime(ip, whichfork);
     973   275943377 :         info.whichfork = whichfork;
     974   275943377 :         info.is_shared = whichfork == XFS_DATA_FORK && xfs_is_reflink_inode(ip);
     975   275943377 :         info.sc = sc;
     976             : 
     977   275943377 :         switch (whichfork) {
     978             :         case XFS_COW_FORK:
     979             :                 /* No CoW forks on non-reflink filesystems. */
     980     6689478 :                 if (!xfs_has_reflink(mp)) {
     981           0 :                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
     982           0 :                         return 0;
     983             :                 }
     984             :                 break;
     985             :         case XFS_ATTR_FORK:
     986   132318629 :                 if (!xfs_has_attr(mp) && !xfs_has_attr2(mp))
     987           0 :                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
     988             :                 break;
     989   136935270 :         default:
     990   136935270 :                 ASSERT(whichfork == XFS_DATA_FORK);
     991             :                 break;
     992             :         }
     993             : 
     994             :         /* Check the fork values */
     995   275943377 :         switch (ifp->if_format) {
     996   190934436 :         case XFS_DINODE_FMT_UUID:
     997             :         case XFS_DINODE_FMT_DEV:
     998             :         case XFS_DINODE_FMT_LOCAL:
     999             :         case XFS_DINODE_FMT_RMAP:
    1000             :         case XFS_DINODE_FMT_REFCOUNT:
    1001             :                 /* No mappings to check. */
    1002   190934436 :                 if (whichfork == XFS_COW_FORK)
    1003           0 :                         xchk_fblock_set_corrupt(sc, whichfork, 0);
    1004             :                 return 0;
    1005             :         case XFS_DINODE_FMT_EXTENTS:
    1006             :                 break;
    1007     2508741 :         case XFS_DINODE_FMT_BTREE:
    1008     2508741 :                 if (whichfork == XFS_COW_FORK) {
    1009           0 :                         xchk_fblock_set_corrupt(sc, whichfork, 0);
    1010           0 :                         return 0;
    1011             :                 }
    1012             : 
    1013     2508741 :                 error = xchk_bmap_btree(sc, whichfork, &info);
    1014     2509311 :                 if (error)
    1015             :                         return error;
    1016             :                 break;
    1017           0 :         default:
    1018           0 :                 xchk_fblock_set_corrupt(sc, whichfork, 0);
    1019           0 :                 return 0;
    1020             :         }
    1021             : 
    1022    85009508 :         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
    1023             :                 return 0;
    1024             : 
    1025             :         /* Find the offset of the last extent in the mapping. */
    1026    85091768 :         error = xfs_bmap_last_offset(ip, &endoff, whichfork);
    1027    85167233 :         if (!xchk_fblock_process_error(sc, whichfork, 0, &error))
    1028           0 :                 return error;
    1029             : 
    1030             :         /*
    1031             :          * Scrub extent records.  We use a special iterator function here that
    1032             :          * combines adjacent mappings if they are logically and physically
    1033             :          * contiguous.   For large allocations that require multiple bmbt
    1034             :          * records, this reduces the number of cross-referencing calls, which
    1035             :          * reduces runtime.  Cross referencing with the rmap is simpler because
    1036             :          * the rmap must match the combined mapping exactly.
    1037             :          */
    1038   845724077 :         while (xchk_bmap_iext_iter(&info, &irec)) {
    1039   760163497 :                 if (xchk_should_terminate(sc, &error) ||
    1040   760076927 :                     (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
    1041             :                         return 0;
    1042             : 
    1043   760076927 :                 if (irec.br_startoff >= endoff) {
    1044           0 :                         xchk_fblock_set_corrupt(sc, whichfork,
    1045             :                                         irec.br_startoff);
    1046           0 :                         return 0;
    1047             :                 }
    1048             : 
    1049   760076927 :                 if (isnullstartblock(irec.br_startblock))
    1050         824 :                         xchk_bmap_iextent_delalloc(ip, &info, &irec);
    1051             :                 else
    1052   760076103 :                         xchk_bmap_iextent(ip, &info, &irec);
    1053   760618564 :                 memcpy(&info.prev_rec, &irec, sizeof(struct xfs_bmbt_irec));
    1054             :         }
    1055             : 
    1056    85227178 :         if (xchk_bmap_want_check_rmaps(&info)) {
    1057      376402 :                 error = xchk_bmap_check_rmaps(sc, whichfork);
    1058      376415 :                 if (!xchk_fblock_xref_process_error(sc, whichfork, 0, &error))
    1059           0 :                         return error;
    1060             :         }
    1061             : 
    1062             :         return 0;
    1063             : }
    1064             : 
    1065             : /* Scrub an inode's data fork. */
    1066             : int
    1067   137463773 : xchk_bmap_data(
    1068             :         struct xfs_scrub        *sc)
    1069             : {
    1070   137463773 :         return xchk_bmap(sc, XFS_DATA_FORK);
    1071             : }
    1072             : 
    1073             : /* Scrub an inode's attr fork. */
    1074             : int
    1075   136841451 : xchk_bmap_attr(
    1076             :         struct xfs_scrub        *sc)
    1077             : {
    1078   136841451 :         return xchk_bmap(sc, XFS_ATTR_FORK);
    1079             : }
    1080             : 
    1081             : /* Scrub an inode's CoW fork. */
    1082             : int
    1083   129241671 : xchk_bmap_cow(
    1084             :         struct xfs_scrub        *sc)
    1085             : {
    1086   129241671 :         return xchk_bmap(sc, XFS_COW_FORK);
    1087             : }

Generated by: LCOV version 1.14