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-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 246 348 70.7 %
Date: 2023-07-31 20:08:27 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    77619823 : xchk_prepare_iscrub(
      33             :         struct xfs_scrub        *sc)
      34             : {
      35    77619823 :         int                     error;
      36             : 
      37    77619823 :         xchk_ilock(sc, XFS_IOLOCK_EXCL);
      38             : 
      39    77621881 :         error = xchk_trans_alloc(sc, 0);
      40    77623303 :         if (error)
      41             :                 return error;
      42             : 
      43    77623460 :         error = xchk_ino_dqattach(sc);
      44    77623714 :         if (error)
      45             :                 return error;
      46             : 
      47    77623712 :         xchk_ilock(sc, XFS_ILOCK_EXCL);
      48    77623712 :         return 0;
      49             : }
      50             : 
      51             : /* Install this scrub-by-handle inode and prepare it for scrubbing. */
      52             : static inline int
      53    55535093 : xchk_install_handle_iscrub(
      54             :         struct xfs_scrub        *sc,
      55             :         struct xfs_inode        *ip)
      56             : {
      57    55535093 :         int                     error;
      58             : 
      59    55535093 :         error = xchk_install_handle_inode(sc, ip);
      60    55536114 :         if (error)
      61             :                 return error;
      62             : 
      63    55452396 :         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    78137650 : xchk_setup_inode(
      74             :         struct xfs_scrub        *sc)
      75             : {
      76    78137650 :         struct xfs_imap         imap;
      77    78137650 :         struct xfs_inode        *ip;
      78    78137650 :         struct xfs_mount        *mp = sc->mp;
      79    78137650 :         struct xfs_inode        *ip_in = XFS_I(file_inode(sc->file));
      80    78137650 :         struct xfs_buf          *agi_bp;
      81    78137650 :         struct xfs_perag        *pag;
      82    78137650 :         xfs_agnumber_t          agno = XFS_INO_TO_AGNO(mp, sc->sm->sm_ino);
      83    78137650 :         int                     error;
      84             : 
      85    78137650 :         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    78137650 :         if (sc->sm->sm_ino == 0 || sc->sm->sm_ino == ip_in->i_ino) {
      90    22171178 :                 error = xchk_install_live_inode(sc, ip_in);
      91    22172670 :                 if (error)
      92             :                         return error;
      93             : 
      94    22172416 :                 return xchk_prepare_iscrub(sc);
      95             :         }
      96             : 
      97             :         /* Reject internal metadata files and obviously bad inode numbers. */
      98    55966472 :         if (xfs_internal_inum(mp, sc->sm->sm_ino))
      99             :                 return -ENOENT;
     100    55911454 :         if (!xfs_verify_ino(sc->mp, sc->sm->sm_ino))
     101             :                 return -ENOENT;
     102             : 
     103             :         /* Try a regular untrusted iget. */
     104    55911470 :         error = xchk_iget(sc, sc->sm->sm_ino, &ip);
     105    55910251 :         if (!error)
     106    55534714 :                 return xchk_install_handle_iscrub(sc, ip);
     107      375537 :         if (error == -ENOENT)
     108             :                 return error;
     109        1458 :         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        1458 :         error = xchk_trans_alloc(sc, 0);
     135        1458 :         if (error)
     136           0 :                 goto out_error;
     137             : 
     138        1458 :         error = xchk_iget_agi(sc, sc->sm->sm_ino, &agi_bp, &ip);
     139        1458 :         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        1458 :         if (error == -ENOENT)
     145           0 :                 goto out_gone;
     146        1458 :         if (error != -EFSCORRUPTED && error != -EFSBADCRC && error != -EINVAL)
     147           0 :                 goto out_cancel;
     148             : 
     149             :         /* Ensure that we have protected against inode allocation/freeing. */
     150        1458 :         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        1458 :         pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, sc->sm->sm_ino));
     168        1458 :         if (!pag) {
     169           0 :                 error = -EFSCORRUPTED;
     170           0 :                 goto out_cancel;
     171             :         }
     172             : 
     173        1458 :         error = xfs_imap(pag, sc->tp, sc->sm->sm_ino, &imap,
     174             :                         XFS_IGET_UNTRUSTED);
     175        1458 :         xfs_perag_put(pag);
     176        1458 :         if (error == -EINVAL || error == -ENOENT)
     177        1458 :                 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        1458 : out_gone:
     207             :         /* The file is gone, so there's nothing to check. */
     208        1458 :         xchk_trans_cancel(sc);
     209        1458 :         return -ENOENT;
     210             : }
     211             : 
     212             : /* Inode core */
     213             : 
     214             : /* Validate di_extsize hint. */
     215             : STATIC void
     216    78135765 : 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    78135765 :         xfs_failaddr_t          fa;
     224    78135765 :         uint32_t                value = be32_to_cpu(dip->di_extsize);
     225             : 
     226    78135765 :         fa = xfs_inode_validate_extsize(sc->mp, value, mode, flags);
     227    78136218 :         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    78136218 :         if ((flags & XFS_DIFLAG_RTINHERIT) &&
     240           0 :             (flags & XFS_DIFLAG_EXTSZINHERIT) &&
     241           0 :             xfs_extlen_to_rtxmod(sc->mp, value) > 0)
     242           0 :                 xchk_ino_set_warning(sc, ino);
     243    78136218 : }
     244             : 
     245             : /* Validate di_cowextsize hint. */
     246             : STATIC void
     247    78136347 : 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    78136347 :         xfs_failaddr_t          fa;
     256    78136347 :         uint32_t                value = be32_to_cpu(dip->di_cowextsize);
     257             : 
     258    78136347 :         fa = xfs_inode_validate_cowextsize(sc->mp, value, mode, flags, flags2);
     259    78136940 :         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    78137324 :         if ((flags & XFS_DIFLAG_RTINHERIT) &&
     272     4515373 :             (flags2 & XFS_DIFLAG2_COWEXTSIZE) &&
     273           0 :             value % sc->mp->m_sb.sb_rextsize > 0)
     274           0 :                 xchk_ino_set_warning(sc, ino);
     275    78137324 : }
     276             : 
     277             : /* Make sure the di_flags make sense for the inode. */
     278             : STATIC void
     279    78136945 : 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    78136945 :         struct xfs_mount        *mp = sc->mp;
     287             : 
     288             :         /* di_flags are all taken, last bit cannot be used */
     289    78136945 :         if (flags & ~XFS_DIFLAG_ANY)
     290           0 :                 goto bad;
     291             : 
     292             :         /* rt flags require rt device */
     293    78136945 :         if ((flags & XFS_DIFLAG_REALTIME) && !mp->m_rtdev_targp)
     294           0 :                 goto bad;
     295             : 
     296             :         /* new rt bitmap flag only valid for rbmino */
     297    78136945 :         if ((flags & XFS_DIFLAG_NEWRTBM) && ino != mp->m_sb.sb_rbmino)
     298           0 :                 goto bad;
     299             : 
     300             :         /* directory-only flags */
     301    78136945 :         if ((flags & (XFS_DIFLAG_RTINHERIT |
     302             :                      XFS_DIFLAG_EXTSZINHERIT |
     303             :                      XFS_DIFLAG_PROJINHERIT |
     304     4529679 :                      XFS_DIFLAG_NOSYMLINKS)) &&
     305             :             !S_ISDIR(mode))
     306           0 :                 goto bad;
     307             : 
     308             :         /* file-only flags */
     309    78136945 :         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    78136945 :         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    78135292 : 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    78135292 :         struct xfs_mount        *mp = sc->mp;
     333             : 
     334             :         /* Unknown di_flags2 could be from a future kernel */
     335    78135292 :         if (flags2 & ~XFS_DIFLAG2_ANY)
     336           0 :                 xchk_ino_set_warning(sc, ino);
     337             : 
     338             :         /* reflink flag requires reflink feature */
     339    78135292 :         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    78135292 :         if ((flags2 & XFS_DIFLAG2_DAX) && !(S_ISREG(mode) || S_ISDIR(mode)))
     347           0 :                 goto bad;
     348             : 
     349             :         /* file-only flags */
     350    78135292 :         if ((flags2 & XFS_DIFLAG2_REFLINK) && !S_ISREG(mode))
     351           0 :                 goto bad;
     352             : 
     353             :         /* realtime and reflink don't always go together */
     354    78135292 :         if ((flags & XFS_DIFLAG_REALTIME) && (flags2 & XFS_DIFLAG2_REFLINK) &&
     355     1256786 :             !xfs_has_rtreflink(mp))
     356           0 :                 goto bad;
     357             : 
     358             :         /* no bigtime iflag without the bigtime feature */
     359   156270584 :         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    78135292 :         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   312529530 : 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   312529530 :         struct timespec64       tv;
     379             : 
     380   312529530 :         tv = xfs_inode_from_disk_ts(dip, ts);
     381   312528075 :         if (tv.tv_nsec < 0 || tv.tv_nsec >= NSEC_PER_SEC)
     382           0 :                 xchk_ino_set_corrupt(sc, ino);
     383   312528075 : }
     384             : 
     385             : /* Scrub all the ondisk inode fields. */
     386             : STATIC void
     387    78137200 : xchk_dinode(
     388             :         struct xfs_scrub        *sc,
     389             :         struct xfs_dinode       *dip,
     390             :         xfs_ino_t               ino)
     391             : {
     392    78137200 :         struct xfs_mount        *mp = sc->mp;
     393    78137200 :         size_t                  fork_recs;
     394    78137200 :         unsigned long long      isize;
     395    78137200 :         uint64_t                flags2;
     396    78137200 :         xfs_extnum_t            nextents;
     397    78137200 :         xfs_extnum_t            naextents;
     398    78137200 :         prid_t                  prid;
     399    78137200 :         uint16_t                flags;
     400    78137200 :         uint16_t                mode;
     401             : 
     402    78137200 :         flags = be16_to_cpu(dip->di_flags);
     403    78137200 :         if (dip->di_version >= 3)
     404    78137147 :                 flags2 = be64_to_cpu(dip->di_flags2);
     405             :         else
     406             :                 flags2 = 0;
     407             : 
     408             :         /* di_mode */
     409    78137200 :         mode = be16_to_cpu(dip->di_mode);
     410    78137200 :         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    78137200 :         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    78137200 :         case 2:
     436             :         case 3:
     437    78137200 :                 if (dip->di_onlink != 0)
     438           0 :                         xchk_ino_set_corrupt(sc, ino);
     439             : 
     440    78137200 :                 if (dip->di_mode == 0 && sc->ip)
     441           0 :                         xchk_ino_set_corrupt(sc, ino);
     442             : 
     443    78137200 :                 if (dip->di_projid_hi != 0 &&
     444             :                     !xfs_has_projid32(mp))
     445           0 :                         xchk_ino_set_corrupt(sc, ino);
     446             : 
     447    78137200 :                 prid = be16_to_cpu(dip->di_projid_lo);
     448             :                 break;
     449           0 :         default:
     450           0 :                 xchk_ino_set_corrupt(sc, ino);
     451           0 :                 return;
     452             :         }
     453             : 
     454    78137200 :         if (xfs_has_projid32(mp))
     455    78137729 :                 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    78137200 :         if (dip->di_uid == cpu_to_be32(-1U) ||
     462    78137200 :             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    78138665 :         if (prid == -1U)
     470           0 :                 xchk_ino_set_warning(sc, ino);
     471             : 
     472             :         /* di_format */
     473    78138665 :         switch (dip->di_format) {
     474    32877479 :         case XFS_DINODE_FMT_DEV:
     475    32877479 :                 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    13202436 :         case XFS_DINODE_FMT_LOCAL:
     480    13202436 :                 if (!S_ISDIR(mode) && !S_ISLNK(mode))
     481           0 :                         xchk_ino_set_corrupt(sc, ino);
     482             :                 break;
     483    30482042 :         case XFS_DINODE_FMT_EXTENTS:
     484    30482042 :                 if (!S_ISREG(mode) && !S_ISDIR(mode) && !S_ISLNK(mode))
     485           0 :                         xchk_ino_set_corrupt(sc, ino);
     486             :                 break;
     487     1415344 :         case XFS_DINODE_FMT_BTREE:
     488     1415344 :                 if (!S_ISREG(mode) && !S_ISDIR(mode))
     489           0 :                         xchk_ino_set_corrupt(sc, ino);
     490             :                 break;
     491      161364 :         case XFS_DINODE_FMT_RMAP:
     492             :         case XFS_DINODE_FMT_REFCOUNT:
     493      161364 :                 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    78138665 :         xchk_dinode_nsec(sc, ino, dip, dip->di_atime);
     504    78137269 :         xchk_dinode_nsec(sc, ino, dip, dip->di_mtime);
     505    78137792 :         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    78137587 :         isize = be64_to_cpu(dip->di_size);
     513    78137587 :         if (isize & (1ULL << 63))
     514           0 :                 xchk_ino_set_corrupt(sc, ino);
     515             : 
     516             :         /* Devices, fifos, and sockets must have zero size */
     517    78137587 :         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    78137587 :         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    78137587 :         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    78137587 :         if (isize > mp->m_super->s_maxbytes)
     535           0 :                 xchk_ino_set_warning(sc, ino);
     536             : 
     537             :         /* di_nblocks */
     538    78137587 :         if (flags2 & XFS_DIFLAG2_REFLINK) {
     539             :                 ; /* nblocks can exceed dblocks */
     540    73571399 :         } 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     5226970 :                 if (be64_to_cpu(dip->di_nblocks) >=
     549     5226970 :                     mp->m_sb.sb_dblocks + mp->m_sb.sb_rblocks)
     550           0 :                         xchk_ino_set_corrupt(sc, ino);
     551             :         } else {
     552    68344429 :                 if (be64_to_cpu(dip->di_nblocks) >= mp->m_sb.sb_dblocks)
     553           0 :                         xchk_ino_set_corrupt(sc, ino);
     554             :         }
     555             : 
     556    78137587 :         xchk_inode_flags(sc, dip, ino, mode, flags);
     557             : 
     558    78136984 :         xchk_inode_extsize(sc, dip, ino, mode, flags);
     559             : 
     560    78137972 :         nextents = xfs_dfork_data_extents(dip);
     561    78137972 :         naextents = xfs_dfork_attr_extents(dip);
     562             : 
     563             :         /* di_nextents */
     564    78137986 :         fork_recs =  XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
     565    78137972 :         switch (dip->di_format) {
     566    30481648 :         case XFS_DINODE_FMT_EXTENTS:
     567    30481648 :                 if (nextents > fork_recs)
     568           0 :                         xchk_ino_set_corrupt(sc, ino);
     569             :                 break;
     570     1415332 :         case XFS_DINODE_FMT_BTREE:
     571     1415332 :                 if (nextents <= fork_recs)
     572           0 :                         xchk_ino_set_corrupt(sc, ino);
     573             :                 break;
     574    46240992 :         default:
     575    46240992 :                 if (nextents != 0)
     576           0 :                         xchk_ino_set_corrupt(sc, ino);
     577             :                 break;
     578             :         }
     579             : 
     580             :         /* di_forkoff */
     581   156274775 :         if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
     582           0 :                 xchk_ino_set_corrupt(sc, ino);
     583    78137972 :         if (naextents != 0 && dip->di_forkoff == 0)
     584           0 :                 xchk_ino_set_corrupt(sc, ino);
     585    78137972 :         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    78137972 :         if (dip->di_aformat != XFS_DINODE_FMT_LOCAL &&
     590    78137972 :             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    78136851 :         fork_recs =  XFS_DFORK_ASIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
     596    78136849 :         switch (dip->di_aformat) {
     597     2088594 :         case XFS_DINODE_FMT_EXTENTS:
     598     2088594 :                 if (naextents > fork_recs)
     599           0 :                         xchk_ino_set_corrupt(sc, ino);
     600             :                 break;
     601          41 :         case XFS_DINODE_FMT_BTREE:
     602          41 :                 if (naextents <= fork_recs)
     603           0 :                         xchk_ino_set_corrupt(sc, ino);
     604             :                 break;
     605    76048214 :         default:
     606    76048214 :                 if (naextents != 0)
     607           0 :                         xchk_ino_set_corrupt(sc, ino);
     608             :         }
     609             : 
     610    78136849 :         if (dip->di_version >= 3) {
     611    78134704 :                 xchk_dinode_nsec(sc, ino, dip, dip->di_crtime);
     612    78135621 :                 xchk_inode_flags2(sc, dip, ino, mode, flags, flags2);
     613    78136656 :                 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    78139436 : xchk_inode_xref_finobt(
     625             :         struct xfs_scrub                *sc,
     626             :         xfs_ino_t                       ino)
     627             : {
     628    78139436 :         struct xfs_inobt_rec_incore     rec;
     629    78139436 :         xfs_agino_t                     agino;
     630    78139436 :         int                             has_record;
     631    78139436 :         int                             error;
     632             : 
     633    78139436 :         if (!sc->sa.fino_cur || xchk_skip_xref(sc->sm))
     634    74236991 :                 return;
     635             : 
     636    78139456 :         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    78139456 :         error = xfs_inobt_lookup(sc->sa.fino_cur, agino, XFS_LOOKUP_LE,
     643             :                         &has_record);
     644    78139810 :         if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
     645    78139861 :             !has_record)
     646             :                 return;
     647             : 
     648    16905620 :         error = xfs_inobt_get_rec(sc->sa.fino_cur, &rec, &has_record);
     649    16905603 :         if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur) ||
     650    16905607 :             !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    16905607 :         if (rec.ir_startino > agino ||
     658    16905607 :             rec.ir_startino + XFS_INODES_PER_CHUNK <= agino)
     659             :                 return;
     660             : 
     661     3902837 :         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    78139777 : xchk_inode_xref_bmap(
     668             :         struct xfs_scrub        *sc,
     669             :         struct xfs_dinode       *dip)
     670             : {
     671    78139777 :         xfs_extnum_t            nextents;
     672    78139777 :         xfs_filblks_t           count;
     673    78139777 :         xfs_filblks_t           acount;
     674    78139777 :         int                     error;
     675             : 
     676    78139777 :         if (xchk_skip_xref(sc->sm))
     677           0 :                 return;
     678             : 
     679             :         /* Walk all the extents to check nextents/naextents/nblocks. */
     680    78139777 :         error = xchk_inode_count_blocks(sc, XFS_DATA_FORK, &nextents, &count);
     681    78139624 :         if (!xchk_should_check_xref(sc, &error, NULL))
     682             :                 return;
     683    78139683 :         if (nextents < xfs_dfork_data_extents(dip))
     684           0 :                 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
     685             : 
     686    78139683 :         error = xchk_inode_count_blocks(sc, XFS_ATTR_FORK, &nextents, &acount);
     687    78139617 :         if (!xchk_should_check_xref(sc, &error, NULL))
     688             :                 return;
     689    78139671 :         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    78139671 :         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    78133494 : xchk_inode_xref(
     700             :         struct xfs_scrub        *sc,
     701             :         xfs_ino_t               ino,
     702             :         struct xfs_dinode       *dip)
     703             : {
     704    78133494 :         xfs_agnumber_t          agno;
     705    78133494 :         xfs_agblock_t           agbno;
     706    78133494 :         int                     error;
     707             : 
     708    78133494 :         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     709           0 :                 return;
     710             : 
     711    78133494 :         agno = XFS_INO_TO_AGNO(sc->mp, ino);
     712    78133494 :         agbno = XFS_INO_TO_AGBNO(sc->mp, ino);
     713             : 
     714    78133494 :         error = xchk_ag_init_existing(sc, agno, &sc->sa);
     715    78139666 :         if (!xchk_xref_process_error(sc, agno, agbno, &error))
     716           1 :                 goto out_free;
     717             : 
     718    78139691 :         xchk_xref_is_used_space(sc, agbno, 1);
     719    78139351 :         xchk_inode_xref_finobt(sc, ino);
     720    78139451 :         xchk_xref_is_only_owned_by(sc, agbno, 1, &XFS_RMAP_OINFO_INODES);
     721    78139518 :         xchk_xref_is_not_shared(sc, agbno, 1);
     722    78139826 :         xchk_xref_is_not_cow_staging(sc, agbno, 1);
     723    78139917 :         xchk_inode_xref_bmap(sc, dip);
     724             : 
     725    78139619 : out_free:
     726    78139619 :         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    22755165 : xchk_inode_check_reflink_iflag(
     737             :         struct xfs_scrub        *sc,
     738             :         xfs_ino_t               ino)
     739             : {
     740    22755165 :         struct xfs_mount        *mp = sc->mp;
     741    22755165 :         bool                    has_shared;
     742    22755165 :         int                     error;
     743             : 
     744    22755165 :         if (!xfs_has_reflink(mp))
     745        1488 :                 return;
     746             : 
     747    22753677 :         error = xfs_reflink_inode_has_shared_extents(sc->tp, sc->ip,
     748             :                         &has_shared);
     749    22754039 :         if (!xchk_xref_process_error(sc, XFS_INO_TO_AGNO(mp, ino),
     750    22753807 :                         XFS_INO_TO_AGBNO(mp, ino), &error))
     751             :                 return;
     752    22754039 :         if (xfs_is_reflink_inode(sc->ip) && !has_shared)
     753     3005283 :                 xchk_ino_set_preen(sc, ino);
     754    19748756 :         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    78134086 : xchk_inode_check_unlinked(
     764             :         struct xfs_scrub        *sc)
     765             : {
     766    78134086 :         if (VFS_I(sc->ip)->i_nlink == 0) {
     767        1128 :                 if (!xfs_inode_on_unlinked_list(sc->ip))
     768           0 :                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
     769             :         } else {
     770    78132958 :                 if (xfs_inode_on_unlinked_list(sc->ip))
     771           0 :                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
     772             :         }
     773    78134086 : }
     774             : 
     775             : /* Scrub an inode. */
     776             : int
     777    78138478 : xchk_inode(
     778             :         struct xfs_scrub        *sc)
     779             : {
     780    78138478 :         struct xfs_dinode       di;
     781    78138478 :         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    78138478 :         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    78138478 :         xfs_inode_to_disk(sc->ip, &di, 0);
     795    78134905 :         xchk_dinode(sc, &di, sc->ip->i_ino);
     796    78136054 :         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    78136054 :         if (S_ISREG(VFS_I(sc->ip)->i_mode))
     805    22755205 :                 xchk_inode_check_reflink_iflag(sc, sc->ip->i_ino);
     806             : 
     807    78136064 :         xchk_inode_check_unlinked(sc);
     808             : 
     809    78133923 :         xchk_inode_xref(sc, sc->ip->i_ino, &di);
     810             : out:
     811             :         return error;
     812             : }

Generated by: LCOV version 1.14