LCOV - code coverage report
Current view: top level - fs/xfs/scrub - inode.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsx @ Mon Jul 31 20:08:34 PDT 2023 Lines: 250 349 71.6 %
Date: 2023-07-31 20:08:34 Functions: 15 15 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_log_format.h"
      14             : #include "xfs_trans.h"
      15             : #include "xfs_ag.h"
      16             : #include "xfs_inode.h"
      17             : #include "xfs_ialloc.h"
      18             : #include "xfs_icache.h"
      19             : #include "xfs_da_format.h"
      20             : #include "xfs_reflink.h"
      21             : #include "xfs_rmap.h"
      22             : #include "xfs_bmap_util.h"
      23             : #include "xfs_rtbitmap.h"
      24             : #include "scrub/scrub.h"
      25             : #include "scrub/common.h"
      26             : #include "scrub/btree.h"
      27             : #include "scrub/trace.h"
      28             : #include "scrub/repair.h"
      29             : 
      30             : /* Prepare the attached inode for scrubbing. */
      31             : static inline int
      32   136445254 : xchk_prepare_iscrub(
      33             :         struct xfs_scrub        *sc)
      34             : {
      35   136445254 :         int                     error;
      36             : 
      37   136445254 :         xchk_ilock(sc, XFS_IOLOCK_EXCL);
      38             : 
      39   136055526 :         error = xchk_trans_alloc(sc, 0);
      40   136014785 :         if (error)
      41             :                 return error;
      42             : 
      43   136040201 :         error = xchk_ino_dqattach(sc);
      44   136212241 :         if (error)
      45             :                 return error;
      46             : 
      47   136228100 :         xchk_ilock(sc, XFS_ILOCK_EXCL);
      48   136228100 :         return 0;
      49             : }
      50             : 
      51             : /* Install this scrub-by-handle inode and prepare it for scrubbing. */
      52             : static inline int
      53    80054596 : xchk_install_handle_iscrub(
      54             :         struct xfs_scrub        *sc,
      55             :         struct xfs_inode        *ip)
      56             : {
      57    80054596 :         int                     error;
      58             : 
      59    80054596 :         error = xchk_install_handle_inode(sc, ip);
      60    79865782 :         if (error)
      61             :                 return error;
      62             : 
      63    79621862 :         return xchk_prepare_iscrub(sc);
      64             : }
      65             : 
      66             : /*
      67             :  * Grab total control of the inode metadata.  In the best case, we grab the
      68             :  * incore inode and take all locks on it.  If the incore inode cannot be
      69             :  * constructed due to corruption problems, lock the AGI so that we can single
      70             :  * step the loading process to fix everything that can go wrong.
      71             :  */
      72             : int
      73   137069528 : xchk_setup_inode(
      74             :         struct xfs_scrub        *sc)
      75             : {
      76   137069528 :         struct xfs_imap         imap;
      77   137069528 :         struct xfs_inode        *ip;
      78   137069528 :         struct xfs_mount        *mp = sc->mp;
      79   137069528 :         struct xfs_inode        *ip_in = XFS_I(file_inode(sc->file));
      80   137069528 :         struct xfs_buf          *agi_bp;
      81   137069528 :         struct xfs_perag        *pag;
      82   137069528 :         xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, sc->sm->sm_ino);
      83   137069528 :         int                     error;
      84             : 
      85   137069528 :         if (xchk_need_intent_drain(sc))
      86           0 :                 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
      87             : 
      88             :         /* We want to scan the opened inode, so lock it and exit. */
      89   137069528 :         if (sc->sm->sm_ino == 0 || sc->sm->sm_ino == ip_in->i_ino) {
      90    56583155 :                 error = xchk_install_live_inode(sc, ip_in);
      91    56882608 :                 if (error)
      92             :                         return error;
      93             : 
      94    56864744 :                 return xchk_prepare_iscrub(sc);
      95             :         }
      96             : 
      97             :         /* Reject internal metadata files and obviously bad inode numbers. */
      98    80486373 :         if (xfs_internal_inum(mp, sc->sm->sm_ino))
      99             :                 return -ENOENT;
     100    80444652 :         if (!xfs_verify_ino(sc->mp, sc->sm->sm_ino))
     101             :                 return -ENOENT;
     102             : 
     103             :         /* Try a regular untrusted iget. */
     104    80311478 :         error = xchk_iget(sc, sc->sm->sm_ino, &ip);
     105    80610471 :         if (!error)
     106    80121772 :                 return xchk_install_handle_iscrub(sc, ip);
     107      488699 :         if (error == -ENOENT)
     108             :                 return error;
     109        1790 :         if (error != -EFSCORRUPTED && error != -EFSBADCRC && error != -EINVAL)
     110           0 :                 goto out_error;
     111             : 
     112             :         /*
     113             :          * EINVAL with IGET_UNTRUSTED probably means one of several things:
     114             :          * userspace gave us an inode number that doesn't correspond to fs
     115             :          * space; the inode btree lacks a record for this inode; or there is
     116             :          * a record, and it says this inode is free.
     117             :          *
     118             :          * EFSCORRUPTED/EFSBADCRC could mean that the inode was mappable, but
     119             :          * some other metadata corruption (e.g. inode forks) prevented
     120             :          * instantiation of the incore inode.  Or it could mean the inobt is
     121             :          * corrupt.
     122             :          *
     123             :          * We want to look up this inode in the inobt directly to distinguish
     124             :          * three different scenarios: (1) the inobt says the inode is free,
     125             :          * in which case there's nothing to do; (2) the inobt is corrupt so we
     126             :          * should flag the corruption and exit to userspace to let it fix the
     127             :          * inobt; and (3) the inobt says the inode is allocated, but loading it
     128             :          * failed due to corruption.
     129             :          *
     130             :          * Allocate a transaction and grab the AGI to prevent inobt activity in
     131             :          * this AG.  Retry the iget in case someone allocated a new inode after
     132             :          * the first iget failed.
     133             :          */
     134        1790 :         error = xchk_trans_alloc(sc, 0);
     135        1790 :         if (error)
     136           0 :                 goto out_error;
     137             : 
     138        1790 :         error = xchk_iget_agi(sc, sc->sm->sm_ino, &agi_bp, &ip);
     139        1790 :         if (error == 0) {
     140             :                 /* Actually got the incore inode, so install it and proceed. */
     141           0 :                 xchk_trans_cancel(sc);
     142           0 :                 return xchk_install_handle_iscrub(sc, ip);
     143             :         }
     144        1790 :         if (error == -ENOENT)
     145           0 :                 goto out_gone;
     146        1790 :         if (error != -EFSCORRUPTED && error != -EFSBADCRC && error != -EINVAL)
     147           0 :                 goto out_cancel;
     148             : 
     149             :         /* Ensure that we have protected against inode allocation/freeing. */
     150        1790 :         if (agi_bp == NULL) {
     151           0 :                 ASSERT(agi_bp != NULL);
     152           0 :                 error = -ECANCELED;
     153           0 :                 goto out_cancel;
     154             :         }
     155             : 
     156             :         /*
     157             :          * Untrusted iget failed a second time.  Let's try an inobt lookup.
     158             :          * If the inobt doesn't think this is an allocated inode then we'll
     159             :          * return ENOENT to signal that the check can be skipped.
     160             :          *
     161             :          * If the lookup signals corruption, we'll mark this inode corrupt and
     162             :          * exit to userspace.  There's little chance of fixing anything until
     163             :          * the inobt is straightened out, but there's nothing we can do here.
     164             :          *
     165             :          * If the lookup encounters a runtime error, exit to userspace.
     166             :          */
     167        1790 :         pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, sc->sm->sm_ino));
     168        1790 :         if (!pag) {
     169           0 :                 error = -EFSCORRUPTED;
     170           0 :                 goto out_cancel;
     171             :         }
     172             : 
     173        1790 :         error = xfs_imap(pag, sc->tp, sc->sm->sm_ino, &imap,
     174             :                         XFS_IGET_UNTRUSTED);
     175        1790 :         xfs_perag_put(pag);
     176        1790 :         if (error == -EINVAL || error == -ENOENT)
     177        1790 :                 goto out_gone;
     178           0 :         if (error)
     179           0 :                 goto out_cancel;
     180             : 
     181             :         /*
     182             :          * The lookup succeeded.  Chances are the ondisk inode is corrupt and
     183             :          * preventing iget from reading it.  Retain the scrub transaction and
     184             :          * the AGI buffer to prevent anyone from allocating or freeing inodes.
     185             :          * This ensures that we preserve the inconsistency between the inobt
     186             :          * saying the inode is allocated and the icache being unable to load
     187             :          * the inode until we can flag the corruption in xchk_inode.  The
     188             :          * scrub function has to note the corruption, since we're not really
     189             :          * supposed to do that from the setup function.  Save the mapping to
     190             :          * make repairs to the ondisk inode buffer.
     191             :          */
     192           0 :         if (xchk_could_repair(sc))
     193           0 :                 xrep_setup_inode(sc, &imap);
     194             :         return 0;
     195             : 
     196           0 : out_cancel:
     197           0 :         xchk_trans_cancel(sc);
     198           0 : out_error:
     199           0 :         xchk_whine(mp, "type %s agno 0x%x agbno 0x%x error %d ret_ip %pS",
     200           0 :                         xchk_type_string(sc->sm->sm_type), agno,
     201           0 :                         XFS_INO_TO_AGBNO(mp, sc->sm->sm_ino), error,
     202             :                         __return_address);
     203           0 :         trace_xchk_op_error(sc, agno, XFS_INO_TO_AGBNO(mp, sc->sm->sm_ino),
     204             :                         error, __return_address);
     205           0 :         return error;
     206        1790 : out_gone:
     207             :         /* The file is gone, so there's nothing to check. */
     208        1790 :         xchk_trans_cancel(sc);
     209        1790 :         return -ENOENT;
     210             : }
     211             : 
     212             : /* Inode core */
     213             : 
     214             : /* Validate di_extsize hint. */
     215             : STATIC void
     216   136364096 : xchk_inode_extsize(
     217             :         struct xfs_scrub        *sc,
     218             :         struct xfs_dinode       *dip,
     219             :         xfs_ino_t               ino,
     220             :         uint16_t                mode,
     221             :         uint16_t                flags)
     222             : {
     223   136364096 :         xfs_failaddr_t          fa;
     224   136364096 :         uint32_t                value = be32_to_cpu(dip->di_extsize);
     225             : 
     226   136364096 :         fa = xfs_inode_validate_extsize(sc->mp, value, mode, flags);
     227   135856652 :         if (fa)
     228           0 :                 xchk_ino_set_corrupt(sc, ino);
     229             : 
     230             :         /*
     231             :          * XFS allows a sysadmin to change the rt extent size when adding a rt
     232             :          * section to a filesystem after formatting.  If there are any
     233             :          * directories with extszinherit and rtinherit set, the hint could
     234             :          * become misaligned with the new rextsize.  The verifier doesn't check
     235             :          * this, because we allow rtinherit directories even without an rt
     236             :          * device.  Flag this as an administrative warning since we will clean
     237             :          * this up eventually.
     238             :          */
     239   135856652 :         if ((flags & XFS_DIFLAG_RTINHERIT) &&
     240        1683 :             (flags & XFS_DIFLAG_EXTSZINHERIT) &&
     241        1683 :             xfs_extlen_to_rtxmod(sc->mp, value) > 0)
     242           0 :                 xchk_ino_set_warning(sc, ino);
     243   135856652 : }
     244             : 
     245             : /* Validate di_cowextsize hint. */
     246             : STATIC void
     247   136459540 : xchk_inode_cowextsize(
     248             :         struct xfs_scrub        *sc,
     249             :         struct xfs_dinode       *dip,
     250             :         xfs_ino_t               ino,
     251             :         uint16_t                mode,
     252             :         uint16_t                flags,
     253             :         uint64_t                flags2)
     254             : {
     255   136459540 :         xfs_failaddr_t          fa;
     256   136459540 :         uint32_t                value = be32_to_cpu(dip->di_cowextsize);
     257             : 
     258   136459540 :         fa = xfs_inode_validate_cowextsize(sc->mp, value, mode, flags, flags2);
     259   135755248 :         if (fa)
     260           0 :                 xchk_ino_set_corrupt(sc, ino);
     261             : 
     262             :         /*
     263             :          * XFS allows a sysadmin to change the rt extent size when adding a rt
     264             :          * section to a filesystem after formatting.  If there are any
     265             :          * directories with cowextsize and rtinherit set, the hint could become
     266             :          * misaligned with the new rextsize.  The verifier doesn't check this,
     267             :          * because we allow rtinherit directories even without an rt device.
     268             :          * Flag this as an administrative warning since we will clean this up
     269             :          * eventually.
     270             :          */
     271   135938305 :         if ((flags & XFS_DIFLAG_RTINHERIT) &&
     272     9110161 :             (flags2 & XFS_DIFLAG2_COWEXTSIZE) &&
     273        1790 :             value % sc->mp->m_sb.sb_rextsize > 0)
     274           0 :                 xchk_ino_set_warning(sc, ino);
     275   135938305 : }
     276             : 
     277             : /* Make sure the di_flags make sense for the inode. */
     278             : STATIC void
     279   136592009 : xchk_inode_flags(
     280             :         struct xfs_scrub        *sc,
     281             :         struct xfs_dinode       *dip,
     282             :         xfs_ino_t               ino,
     283             :         uint16_t                mode,
     284             :         uint16_t                flags)
     285             : {
     286   136592009 :         struct xfs_mount        *mp = sc->mp;
     287             : 
     288             :         /* di_flags are all taken, last bit cannot be used */
     289   136592009 :         if (flags & ~XFS_DIFLAG_ANY)
     290           0 :                 goto bad;
     291             : 
     292             :         /* rt flags require rt device */
     293   136592009 :         if ((flags & XFS_DIFLAG_REALTIME) && !mp->m_rtdev_targp)
     294           0 :                 goto bad;
     295             : 
     296             :         /* new rt bitmap flag only valid for rbmino */
     297   136592009 :         if ((flags & XFS_DIFLAG_NEWRTBM) && ino != mp->m_sb.sb_rbmino)
     298           0 :                 goto bad;
     299             : 
     300             :         /* directory-only flags */
     301   136592009 :         if ((flags & (XFS_DIFLAG_RTINHERIT |
     302             :                      XFS_DIFLAG_EXTSZINHERIT |
     303             :                      XFS_DIFLAG_PROJINHERIT |
     304     9194470 :                      XFS_DIFLAG_NOSYMLINKS)) &&
     305             :             !S_ISDIR(mode))
     306           0 :                 goto bad;
     307             : 
     308             :         /* file-only flags */
     309   136592009 :         if ((flags & (XFS_DIFLAG_REALTIME | FS_XFLAG_EXTSIZE)) &&
     310             :             !S_ISREG(mode))
     311           0 :                 goto bad;
     312             : 
     313             :         /* filestreams and rt make no sense */
     314   136592009 :         if ((flags & XFS_DIFLAG_FILESTREAM) && (flags & XFS_DIFLAG_REALTIME))
     315           0 :                 goto bad;
     316             : 
     317             :         return;
     318           0 : bad:
     319           0 :         xchk_ino_set_corrupt(sc, ino);
     320             : }
     321             : 
     322             : /* Make sure the di_flags2 make sense for the inode. */
     323             : STATIC void
     324   136179052 : xchk_inode_flags2(
     325             :         struct xfs_scrub        *sc,
     326             :         struct xfs_dinode       *dip,
     327             :         xfs_ino_t               ino,
     328             :         uint16_t                mode,
     329             :         uint16_t                flags,
     330             :         uint64_t                flags2)
     331             : {
     332   136179052 :         struct xfs_mount        *mp = sc->mp;
     333             : 
     334             :         /* Unknown di_flags2 could be from a future kernel */
     335   136179052 :         if (flags2 & ~XFS_DIFLAG2_ANY)
     336           0 :                 xchk_ino_set_warning(sc, ino);
     337             : 
     338             :         /* reflink flag requires reflink feature */
     339   136179052 :         if ((flags2 & XFS_DIFLAG2_REFLINK) &&
     340             :             !xfs_has_reflink(mp))
     341           0 :                 goto bad;
     342             : 
     343             :         /* cowextsize flag is checked w.r.t. mode separately */
     344             : 
     345             :         /* file/dir-only flags */
     346   136179052 :         if ((flags2 & XFS_DIFLAG2_DAX) && !(S_ISREG(mode) || S_ISDIR(mode)))
     347           0 :                 goto bad;
     348             : 
     349             :         /* file-only flags */
     350   136179052 :         if ((flags2 & XFS_DIFLAG2_REFLINK) && !S_ISREG(mode))
     351           0 :                 goto bad;
     352             : 
     353             :         /* realtime and reflink don't always go together */
     354   136179052 :         if ((flags & XFS_DIFLAG_REALTIME) && (flags2 & XFS_DIFLAG2_REFLINK) &&
     355     2075932 :             !xfs_has_rtreflink(mp))
     356           0 :                 goto bad;
     357             : 
     358             :         /* no bigtime iflag without the bigtime feature */
     359   272358104 :         if (xfs_dinode_has_bigtime(dip) && !xfs_has_bigtime(mp))
     360           0 :                 goto bad;
     361             : 
     362             :         /* no large extent counts without the filesystem feature */
     363   136179052 :         if ((flags2 & XFS_DIFLAG2_NREXT64) && !xfs_has_large_extent_counts(mp))
     364           0 :                 goto bad;
     365             : 
     366             :         return;
     367           0 : bad:
     368           0 :         xchk_ino_set_corrupt(sc, ino);
     369             : }
     370             : 
     371             : static inline void
     372   544179070 : xchk_dinode_nsec(
     373             :         struct xfs_scrub        *sc,
     374             :         xfs_ino_t               ino,
     375             :         struct xfs_dinode       *dip,
     376             :         const xfs_timestamp_t   ts)
     377             : {
     378   544179070 :         struct timespec64       tv;
     379             : 
     380   544179070 :         tv = xfs_inode_from_disk_ts(dip, ts);
     381   543867204 :         if (tv.tv_nsec < 0 || tv.tv_nsec >= NSEC_PER_SEC)
     382           0 :                 xchk_ino_set_corrupt(sc, ino);
     383   543867204 : }
     384             : 
     385             : /* Scrub all the ondisk inode fields. */
     386             : STATIC void
     387   136852047 : xchk_dinode(
     388             :         struct xfs_scrub        *sc,
     389             :         struct xfs_dinode       *dip,
     390             :         xfs_ino_t               ino)
     391             : {
     392   136852047 :         struct xfs_mount        *mp = sc->mp;
     393   136852047 :         size_t                  fork_recs;
     394   136852047 :         unsigned long long      isize;
     395   136852047 :         uint64_t                flags2;
     396   136852047 :         xfs_extnum_t            nextents;
     397   136852047 :         xfs_extnum_t            naextents;
     398   136852047 :         prid_t                  prid;
     399   136852047 :         uint16_t                flags;
     400   136852047 :         uint16_t                mode;
     401             : 
     402   136852047 :         flags = be16_to_cpu(dip->di_flags);
     403   136852047 :         if (dip->di_version >= 3)
     404   137120929 :                 flags2 = be64_to_cpu(dip->di_flags2);
     405             :         else
     406             :                 flags2 = 0;
     407             : 
     408             :         /* di_mode */
     409   136852047 :         mode = be16_to_cpu(dip->di_mode);
     410   136852047 :         switch (mode & S_IFMT) {
     411             :         case S_IFLNK:
     412             :         case S_IFREG:
     413             :         case S_IFDIR:
     414             :         case S_IFCHR:
     415             :         case S_IFBLK:
     416             :         case S_IFIFO:
     417             :         case S_IFSOCK:
     418             :                 /* mode is recognized */
     419             :                 break;
     420           0 :         default:
     421           0 :                 xchk_ino_set_corrupt(sc, ino);
     422           0 :                 break;
     423             :         }
     424             : 
     425             :         /* v1/v2 fields */
     426   136852047 :         switch (dip->di_version) {
     427           0 :         case 1:
     428             :                 /*
     429             :                  * We autoconvert v1 inodes into v2 inodes on writeout,
     430             :                  * so just mark this inode for preening.
     431             :                  */
     432           0 :                 xchk_ino_set_preen(sc, ino);
     433           0 :                 prid = 0;
     434           0 :                 break;
     435   136852047 :         case 2:
     436             :         case 3:
     437   136852047 :                 if (dip->di_onlink != 0)
     438           0 :                         xchk_ino_set_corrupt(sc, ino);
     439             : 
     440   136852047 :                 if (dip->di_mode == 0 && sc->ip)
     441           0 :                         xchk_ino_set_corrupt(sc, ino);
     442             : 
     443   136852047 :                 if (dip->di_projid_hi != 0 &&
     444             :                     !xfs_has_projid32(mp))
     445           0 :                         xchk_ino_set_corrupt(sc, ino);
     446             : 
     447   136852047 :                 prid = be16_to_cpu(dip->di_projid_lo);
     448   136852047 :                 break;
     449           0 :         default:
     450           0 :                 xchk_ino_set_corrupt(sc, ino);
     451           0 :                 return;
     452             :         }
     453             : 
     454   136852047 :         if (xfs_has_projid32(mp))
     455   136794762 :                 prid |= (prid_t)be16_to_cpu(dip->di_projid_hi) << 16;
     456             : 
     457             :         /*
     458             :          * di_uid/di_gid -- -1 isn't invalid, but there's no way that
     459             :          * userspace could have created that.
     460             :          */
     461   136852047 :         if (dip->di_uid == cpu_to_be32(-1U) ||
     462   136852047 :             dip->di_gid == cpu_to_be32(-1U))
     463           0 :                 xchk_ino_set_warning(sc, ino);
     464             : 
     465             :         /*
     466             :          * project id of -1 isn't supposed to be valid, but the kernel didn't
     467             :          * always validate that.
     468             :          */
     469   136699158 :         if (prid == -1U)
     470           0 :                 xchk_ino_set_warning(sc, ino);
     471             : 
     472             :         /* di_format */
     473   136699158 :         switch (dip->di_format) {
     474    38274837 :         case XFS_DINODE_FMT_DEV:
     475    38274837 :                 if (!S_ISCHR(mode) && !S_ISBLK(mode) &&
     476           0 :                     !S_ISFIFO(mode) && !S_ISSOCK(mode))
     477           0 :                         xchk_ino_set_corrupt(sc, ino);
     478             :                 break;
     479    22454163 :         case XFS_DINODE_FMT_LOCAL:
     480    22454163 :                 if (!S_ISDIR(mode) && !S_ISLNK(mode))
     481           0 :                         xchk_ino_set_corrupt(sc, ino);
     482             :                 break;
     483    73123877 :         case XFS_DINODE_FMT_EXTENTS:
     484    73123877 :                 if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
     485           0 :                         xchk_ino_set_corrupt(sc, ino);
     486             :                 break;
     487     2497520 :         case XFS_DINODE_FMT_BTREE:
     488     2497520 :                 if (!S_ISREG(mode) && !S_ISDIR(mode))
     489           0 :                         xchk_ino_set_corrupt(sc, ino);
     490             :                 break;
     491      348761 :         case XFS_DINODE_FMT_RMAP:
     492             :         case XFS_DINODE_FMT_REFCOUNT:
     493      348761 :                 if (!S_ISREG(mode))
     494           0 :                         xchk_ino_set_corrupt(sc, ino);
     495             :                 break;
     496           0 :         case XFS_DINODE_FMT_UUID:
     497             :         default:
     498           0 :                 xchk_ino_set_corrupt(sc, ino);
     499           0 :                 break;
     500             :         }
     501             : 
     502             :         /* di_[amc]time.nsec */
     503   136699158 :         xchk_dinode_nsec(sc, ino, dip, dip->di_atime);
     504   136243297 :         xchk_dinode_nsec(sc, ino, dip, dip->di_mtime);
     505   136464540 :         xchk_dinode_nsec(sc, ino, dip, dip->di_ctime);
     506             : 
     507             :         /*
     508             :          * di_size.  xfs_dinode_verify checks for things that screw up
     509             :          * the VFS such as the upper bit being set and zero-length
     510             :          * symlinks/directories, but we can do more here.
     511             :          */
     512   136805083 :         isize = be64_to_cpu(dip->di_size);
     513   136805083 :         if (isize & (1ULL << 63))
     514           0 :                 xchk_ino_set_corrupt(sc, ino);
     515             : 
     516             :         /* Devices, fifos, and sockets must have zero size */
     517   136805083 :         if (!S_ISDIR(mode) && !S_ISREG(mode) && !S_ISLNK(mode) && isize != 0)
     518           0 :                 xchk_ino_set_corrupt(sc, ino);
     519             : 
     520             :         /* Directories can't be larger than the data section size (32G) */
     521   136805083 :         if (S_ISDIR(mode) && (isize == 0 || isize >= XFS_DIR2_SPACE_SIZE))
     522           0 :                 xchk_ino_set_corrupt(sc, ino);
     523             : 
     524             :         /* Symlinks can't be larger than SYMLINK_MAXLEN */
     525   136805083 :         if (S_ISLNK(mode) && (isize == 0 || isize >= XFS_SYMLINK_MAXLEN))
     526           0 :                 xchk_ino_set_corrupt(sc, ino);
     527             : 
     528             :         /*
     529             :          * Warn if the running kernel can't handle the kinds of offsets
     530             :          * needed to deal with the file size.  In other words, if the
     531             :          * pagecache can't cache all the blocks in this file due to
     532             :          * overly large offsets, flag the inode for admin review.
     533             :          */
     534   136805083 :         if (isize > mp->m_super->s_maxbytes)
     535           0 :                 xchk_ino_set_warning(sc, ino);
     536             : 
     537             :         /* di_nblocks */
     538   136805083 :         if (flags2 & XFS_DIFLAG2_REFLINK) {
     539             :                 ; /* nblocks can exceed dblocks */
     540   130724820 :         } else if (flags & XFS_DIFLAG_REALTIME) {
     541             :                 /*
     542             :                  * nblocks is the sum of data extents (in the rtdev),
     543             :                  * attr extents (in the datadev), and both forks' bmbt
     544             :                  * blocks (in the datadev).  This clumsy check is the
     545             :                  * best we can do without cross-referencing with the
     546             :                  * inode forks.
     547             :                  */
     548    27931964 :                 if (be64_to_cpu(dip->di_nblocks) >=
     549    27931964 :                     mp->m_sb.sb_dblocks + mp->m_sb.sb_rblocks)
     550           0 :                         xchk_ino_set_corrupt(sc, ino);
     551             :         } else {
     552   102792856 :                 if (be64_to_cpu(dip->di_nblocks) >= mp->m_sb.sb_dblocks)
     553           0 :                         xchk_ino_set_corrupt(sc, ino);
     554             :         }
     555             : 
     556   136805083 :         xchk_inode_flags(sc, dip, ino, mode, flags);
     557             : 
     558   136184764 :         xchk_inode_extsize(sc, dip, ino, mode, flags);
     559             : 
     560   136036927 :         nextents = xfs_dfork_data_extents(dip);
     561   136036927 :         naextents = xfs_dfork_attr_extents(dip);
     562             : 
     563             :         /* di_nextents */
     564   136037004 :         fork_recs =  XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
     565   136036927 :         switch (dip->di_format) {
     566    72853394 :         case XFS_DINODE_FMT_EXTENTS:
     567    72853394 :                 if (nextents > fork_recs)
     568           0 :                         xchk_ino_set_corrupt(sc, ino);
     569             :                 break;
     570     2496983 :         case XFS_DINODE_FMT_BTREE:
     571     2496983 :                 if (nextents <= fork_recs)
     572           0 :                         xchk_ino_set_corrupt(sc, ino);
     573             :                 break;
     574    60686550 :         default:
     575    60686550 :                 if (nextents != 0)
     576           0 :                         xchk_ino_set_corrupt(sc, ino);
     577             :                 break;
     578             :         }
     579             : 
     580             :         /* di_forkoff */
     581   272317774 :         if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
     582           0 :                 xchk_ino_set_corrupt(sc, ino);
     583   136036927 :         if (naextents != 0 && dip->di_forkoff == 0)
     584           0 :                 xchk_ino_set_corrupt(sc, ino);
     585   136036927 :         if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
     586           0 :                 xchk_ino_set_corrupt(sc, ino);
     587             : 
     588             :         /* di_aformat */
     589   136036927 :         if (dip->di_aformat != XFS_DINODE_FMT_LOCAL &&
     590   136036927 :             dip->di_aformat != XFS_DINODE_FMT_EXTENTS &&
     591             :             dip->di_aformat != XFS_DINODE_FMT_BTREE)
     592           0 :                 xchk_ino_set_corrupt(sc, ino);
     593             : 
     594             :         /* di_anextents */
     595   135910348 :         fork_recs =  XFS_DFORK_ASIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
     596   135910337 :         switch (dip->di_aformat) {
     597     7002568 :         case XFS_DINODE_FMT_EXTENTS:
     598     7002568 :                 if (naextents > fork_recs)
     599           0 :                         xchk_ino_set_corrupt(sc, ino);
     600             :                 break;
     601         167 :         case XFS_DINODE_FMT_BTREE:
     602         167 :                 if (naextents <= fork_recs)
     603           0 :                         xchk_ino_set_corrupt(sc, ino);
     604             :                 break;
     605   128907602 :         default:
     606   128907602 :                 if (naextents != 0)
     607           0 :                         xchk_ino_set_corrupt(sc, ino);
     608             :         }
     609             : 
     610   135910337 :         if (dip->di_version >= 3) {
     611   136167101 :                 xchk_dinode_nsec(sc, ino, dip, dip->di_crtime);
     612   135877065 :                 xchk_inode_flags2(sc, dip, ino, mode, flags, flags2);
     613   136343181 :                 xchk_inode_cowextsize(sc, dip, ino, mode, flags,
     614             :                                 flags2);
     615             :         }
     616             : }
     617             : 
     618             : /*
     619             :  * Make sure the finobt doesn't think this inode is free.
     620             :  * We don't have to check the inobt ourselves because we got the inode via
     621             :  * IGET_UNTRUSTED, which checks the inobt for us.
     622             :  */
     623             : static void
     624   137154612 : xchk_inode_xref_finobt(
     625             :         struct xfs_scrub                *sc,
     626             :         xfs_ino_t                       ino)
     627             : {
     628   137154612 :         struct xfs_inobt_rec_incore     rec;
     629   137154612 :         xfs_agino_t                     agino;
     630   137154612 :         int                             has_record;
     631   137154612 :         int                             error;
     632             : 
     633   137154612 :         if (!sc->sa.fino_cur || xchk_skip_xref(sc->sm))
     634   130009975 :                 return;
     635             : 
     636   137154524 :         agino = XFS_INO_TO_AGINO(sc->mp, ino);
     637             : 
     638             :         /*
     639             :          * Try to get the finobt record.  If we can't get it, then we're
     640             :          * in good shape.
     641             :          */
     642   137154524 :         error = xfs_inobt_lookup(sc->sa.fino_cur, agino, XFS_LOOKUP_LE,
     643             :                         &has_record);
     644   137785954 :         if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
     645   137638763 :             !has_record)
     646             :                 return;
     647             : 
     648    32472980 :         error = xfs_inobt_get_rec(sc->sa.fino_cur, &rec, &has_record);
     649    32452920 :         if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
     650    32458764 :             !has_record)
     651             :                 return;
     652             : 
     653             :         /*
     654             :          * Otherwise, make sure this record either doesn't cover this inode,
     655             :          * or that it does but it's marked present.
     656             :          */
     657    32458764 :         if (rec.ir_startino > agino ||
     658    32458764 :             rec.ir_startino + XFS_INODES_PER_CHUNK <= agino)
     659             :                 return;
     660             : 
     661     7614660 :         if (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino))
     662           0 :                 xchk_btree_xref_set_corrupt(sc, sc->sa.fino_cur, 0);
     663             : }
     664             : 
     665             : /* Cross reference the inode fields with the forks. */
     666             : STATIC void
     667   137751985 : xchk_inode_xref_bmap(
     668             :         struct xfs_scrub        *sc,
     669             :         struct xfs_dinode       *dip)
     670             : {
     671   137751985 :         xfs_extnum_t            nextents;
     672   137751985 :         xfs_filblks_t           count;
     673   137751985 :         xfs_filblks_t           acount;
     674   137751985 :         int                     error;
     675             : 
     676   137751985 :         if (xchk_skip_xref(sc->sm))
     677           0 :                 return;
     678             : 
     679             :         /* Walk all the extents to check nextents/naextents/nblocks. */
     680   137751985 :         error = xchk_inode_count_blocks(sc, XFS_DATA_FORK, &nextents, &count);
     681   137626344 :         if (!xchk_should_check_xref(sc, &error, NULL))
     682             :                 return;
     683   137682381 :         if (nextents < xfs_dfork_data_extents(dip))
     684           0 :                 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
     685             : 
     686   137682381 :         error = xchk_inode_count_blocks(sc, XFS_ATTR_FORK, &nextents, &acount);
     687   137732668 :         if (!xchk_should_check_xref(sc, &error, NULL))
     688             :                 return;
     689   137749660 :         if (nextents != xfs_dfork_attr_extents(dip))
     690           0 :                 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
     691             : 
     692             :         /* Check nblocks against the inode. */
     693   137749660 :         if (count + acount != be64_to_cpu(dip->di_nblocks))
     694           0 :                 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
     695             : }
     696             : 
     697             : /* Cross-reference with the other btrees. */
     698             : STATIC void
     699   136671246 : xchk_inode_xref(
     700             :         struct xfs_scrub        *sc,
     701             :         xfs_ino_t               ino,
     702             :         struct xfs_dinode       *dip)
     703             : {
     704   136671246 :         xfs_agnumber_t          agno;
     705   136671246 :         xfs_agblock_t           agbno;
     706   136671246 :         int                     error;
     707             : 
     708   136671246 :         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     709           0 :                 return;
     710             : 
     711   136671246 :         agno = XFS_INO_TO_AGNO(sc->mp, ino);
     712   136671246 :         agbno = XFS_INO_TO_AGBNO(sc->mp, ino);
     713             : 
     714   136671246 :         error = xchk_ag_init_existing(sc, agno, &sc->sa);
     715   137624518 :         if (!xchk_xref_process_error(sc, agno, agbno, &error))
     716          11 :                 goto out_free;
     717             : 
     718   136985186 :         xchk_xref_is_used_space(sc, agbno, 1);
     719   137285765 :         xchk_inode_xref_finobt(sc, ino);
     720   137688528 :         xchk_xref_is_only_owned_by(sc, agbno, 1, &XFS_RMAP_OINFO_INODES);
     721   137812118 :         xchk_xref_is_not_shared(sc, agbno, 1);
     722   137718188 :         xchk_xref_is_not_cow_staging(sc, agbno, 1);
     723   137786064 :         xchk_inode_xref_bmap(sc, dip);
     724             : 
     725   137587539 : out_free:
     726   137587539 :         xchk_ag_free(sc, &sc->sa);
     727             : }
     728             : 
     729             : /*
     730             :  * If the reflink iflag disagrees with a scan for shared data fork extents,
     731             :  * either flag an error (shared extents w/ no flag) or a preen (flag set w/o
     732             :  * any shared extents).  We already checked for reflink iflag set on a non
     733             :  * reflink filesystem.
     734             :  */
     735             : static void
     736    65297092 : xchk_inode_check_reflink_iflag(
     737             :         struct xfs_scrub        *sc,
     738             :         xfs_ino_t               ino)
     739             : {
     740    65297092 :         struct xfs_mount        *mp = sc->mp;
     741    65297092 :         bool                    has_shared;
     742    65297092 :         int                     error;
     743             : 
     744    65297092 :         if (!xfs_has_reflink(mp))
     745     3014890 :                 return;
     746             : 
     747    62282202 :         error = xfs_reflink_inode_has_shared_extents(sc->tp, sc->ip,
     748             :                         &has_shared);
     749    62464756 :         if (!xchk_xref_process_error(sc, XFS_INO_TO_AGNO(mp, ino),
     750    62464756 :                         XFS_INO_TO_AGBNO(mp, ino), &error))
     751             :                 return;
     752    62368050 :         if (xfs_is_reflink_inode(sc->ip) && !has_shared)
     753     2383454 :                 xchk_ino_set_preen(sc, ino);
     754    59984596 :         else if (!xfs_is_reflink_inode(sc->ip) && has_shared)
     755           0 :                 xchk_ino_set_corrupt(sc, ino);
     756             : }
     757             : 
     758             : /*
     759             :  * If this inode has zero link count, it must be on the unlinked list.  If
     760             :  * it has nonzero link count, it must not be on the unlinked list.
     761             :  */
     762             : STATIC void
     763   136418011 : xchk_inode_check_unlinked(
     764             :         struct xfs_scrub        *sc)
     765             : {
     766   136418011 :         if (VFS_I(sc->ip)->i_nlink == 0) {
     767        3034 :                 if (!xfs_inode_on_unlinked_list(sc->ip))
     768           0 :                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
     769             :         } else {
     770   136414977 :                 if (xfs_inode_on_unlinked_list(sc->ip))
     771           0 :                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
     772             :         }
     773   136418011 : }
     774             : 
     775             : /* Scrub an inode. */
     776             : int
     777   137283913 : xchk_inode(
     778             :         struct xfs_scrub        *sc)
     779             : {
     780   137283913 :         struct xfs_dinode       di;
     781   137283913 :         int                     error = 0;
     782             : 
     783             :         /*
     784             :          * If sc->ip is NULL, that means that the setup function called
     785             :          * xfs_iget to look up the inode.  xfs_iget returned a EFSCORRUPTED
     786             :          * and a NULL inode, so flag the corruption error and return.
     787             :          */
     788   137283913 :         if (!sc->ip) {
     789           0 :                 xchk_ino_set_corrupt(sc, sc->sm->sm_ino);
     790           0 :                 return 0;
     791             :         }
     792             : 
     793             :         /* Scrub the inode core. */
     794   137283913 :         xfs_inode_to_disk(sc->ip, &di, 0);
     795   136710993 :         xchk_dinode(sc, &di, sc->ip->i_ino);
     796   136336130 :         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     797           0 :                 goto out;
     798             : 
     799             :         /*
     800             :          * Look for discrepancies between file's data blocks and the reflink
     801             :          * iflag.  We already checked the iflag against the file mode when
     802             :          * we scrubbed the dinode.
     803             :          */
     804   136336130 :         if (S_ISREG(VFS_I(sc->ip)->i_mode))
     805    65214786 :                 xchk_inode_check_reflink_iflag(sc, sc->ip->i_ino);
     806             : 
     807   136441232 :         xchk_inode_check_unlinked(sc);
     808             : 
     809   136274556 :         xchk_inode_xref(sc, sc->ip->i_ino, &di);
     810             : out:
     811             :         return error;
     812             : }

Generated by: LCOV version 1.14