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

Generated by: LCOV version 1.14