LCOV - code coverage report
Current view: top level - fs/xfs/scrub - parent.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsx @ Mon Jul 31 20:08:34 PDT 2023 Lines: 220 365 60.3 %
Date: 2023-07-31 20:08:34 Functions: 14 17 82.4 %

          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_log_format.h"
      13             : #include "xfs_trans.h"
      14             : #include "xfs_inode.h"
      15             : #include "xfs_icache.h"
      16             : #include "xfs_dir2.h"
      17             : #include "xfs_dir2_priv.h"
      18             : #include "xfs_attr.h"
      19             : #include "xfs_parent.h"
      20             : #include "scrub/scrub.h"
      21             : #include "scrub/common.h"
      22             : #include "scrub/readdir.h"
      23             : #include "scrub/tempfile.h"
      24             : #include "scrub/repair.h"
      25             : #include "scrub/listxattr.h"
      26             : #include "scrub/xfile.h"
      27             : #include "scrub/xfarray.h"
      28             : #include "scrub/xfblob.h"
      29             : #include "scrub/trace.h"
      30             : 
      31             : /* Set us up to scrub parents. */
      32             : int
      33   135755556 : xchk_setup_parent(
      34             :         struct xfs_scrub        *sc)
      35             : {
      36   135755556 :         int                     error;
      37             : 
      38   135755556 :         if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) {
      39     6083393 :                 error = xrep_setup_parent(sc);
      40     6093681 :                 if (error)
      41             :                         return error;
      42             :         }
      43             : 
      44   134302782 :         return xchk_setup_inode_contents(sc, 0);
      45             : }
      46             : 
      47             : /* Parent pointers */
      48             : 
      49             : /* Look for an entry in a parent pointing to this inode. */
      50             : 
      51             : struct xchk_parent_ctx {
      52             :         struct xfs_scrub        *sc;
      53             :         xfs_nlink_t             nlink;
      54             : };
      55             : 
      56             : /* Look for a single entry in a directory pointing to an inode. */
      57             : STATIC int
      58    47053137 : xchk_parent_actor(
      59             :         struct xfs_scrub        *sc,
      60             :         struct xfs_inode        *dp,
      61             :         xfs_dir2_dataptr_t      dapos,
      62             :         const struct xfs_name   *name,
      63             :         xfs_ino_t               ino,
      64             :         void                    *priv)
      65             : {
      66    47053137 :         struct xchk_parent_ctx  *spc = priv;
      67    47053137 :         int                     error = 0;
      68             : 
      69             :         /* Does this name make sense? */
      70    47053137 :         if (!xfs_dir2_namecheck(name->name, name->len))
      71           0 :                 error = -EFSCORRUPTED;
      72    47932843 :         if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
      73           0 :                 return error;
      74             : 
      75    47590220 :         if (sc->ip->i_ino == ino)
      76      746494 :                 spc->nlink++;
      77             : 
      78    47590220 :         if (xchk_should_terminate(spc->sc, &error))
      79           1 :                 return error;
      80             : 
      81             :         return 0;
      82             : }
      83             : 
      84             : /*
      85             :  * Try to lock a parent directory for checking dirents.  Returns the inode
      86             :  * flags for the locks we now hold, or zero if we failed.
      87             :  */
      88             : STATIC unsigned int
      89     2524990 : xchk_parent_ilock_dir(
      90             :         struct xfs_inode        *dp)
      91             : {
      92     2524990 :         if (!xfs_ilock_nowait(dp, XFS_ILOCK_SHARED))
      93             :                 return 0;
      94             : 
      95      745813 :         if (!xfs_need_iread_extents(&dp->i_df))
      96             :                 return XFS_ILOCK_SHARED;
      97             : 
      98           1 :         xfs_iunlock(dp, XFS_ILOCK_SHARED);
      99             : 
     100           1 :         if (!xfs_ilock_nowait(dp, XFS_ILOCK_EXCL))
     101           0 :                 return 0;
     102             : 
     103             :         return XFS_ILOCK_EXCL;
     104             : }
     105             : 
     106             : /*
     107             :  * Given the inode number of the alleged parent of the inode being scrubbed,
     108             :  * try to validate that the parent has exactly one directory entry pointing
     109             :  * back to the inode being scrubbed.  Returns -EAGAIN if we need to revalidate
     110             :  * the dotdot entry.
     111             :  */
     112             : STATIC int
     113     2491221 : xchk_parent_validate(
     114             :         struct xfs_scrub        *sc,
     115             :         xfs_ino_t               parent_ino)
     116             : {
     117     2491221 :         struct xchk_parent_ctx  spc = {
     118             :                 .sc             = sc,
     119             :                 .nlink          = 0,
     120             :         };
     121     2491221 :         struct xfs_mount        *mp = sc->mp;
     122     2491221 :         struct xfs_inode        *dp = NULL;
     123     2491221 :         xfs_nlink_t             expected_nlink;
     124     2491221 :         unsigned int            lock_mode;
     125     2491221 :         int                     error = 0;
     126             : 
     127             :         /* Is this the root dir?  Then '..' must point to itself. */
     128     2491221 :         if (sc->ip == mp->m_rootip) {
     129        3473 :                 if (sc->ip->i_ino != mp->m_sb.sb_rootino ||
     130             :                     sc->ip->i_ino != parent_ino)
     131           0 :                         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
     132        3473 :                 return 0;
     133             :         }
     134             : 
     135             :         /* Is this the metadata root dir?  Then '..' must point to itself. */
     136     2487748 :         if (sc->ip == mp->m_metadirip) {
     137           0 :                 if (sc->ip->i_ino != mp->m_sb.sb_metadirino ||
     138             :                     sc->ip->i_ino != parent_ino)
     139           0 :                         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
     140           0 :                 return 0;
     141             :         }
     142             : 
     143             :         /* '..' must not point to ourselves. */
     144     2487748 :         if (sc->ip->i_ino == parent_ino) {
     145           0 :                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
     146           0 :                 return 0;
     147             :         }
     148             : 
     149             :         /*
     150             :          * If we're an unlinked directory, the parent /won't/ have a link
     151             :          * to us.  Otherwise, it should have one link.
     152             :          */
     153     2487748 :         expected_nlink = VFS_I(sc->ip)->i_nlink == 0 ? 0 : 1;
     154             : 
     155             :         /*
     156             :          * Grab the parent directory inode.  This must be released before we
     157             :          * cancel the scrub transaction.
     158             :          *
     159             :          * If _iget returns -EINVAL or -ENOENT then the parent inode number is
     160             :          * garbage and the directory is corrupt.  If the _iget returns
     161             :          * -EFSCORRUPTED or -EFSBADCRC then the parent is corrupt which is a
     162             :          *  cross referencing error.  Any other error is an operational error.
     163             :          */
     164     2487748 :         error = xchk_iget(sc, parent_ino, &dp);
     165     2527867 :         if (error == -EINVAL || error == -ENOENT) {
     166           0 :                 error = -EFSCORRUPTED;
     167           0 :                 xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error);
     168           0 :                 return error;
     169             :         }
     170     2527867 :         if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
     171           0 :                 return error;
     172     2524604 :         if (dp == sc->ip || xrep_is_tempfile(dp) ||
     173     2524294 :             !S_ISDIR(VFS_I(dp)->i_mode)) {
     174           2 :                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
     175           1 :                 goto out_rele;
     176             :         }
     177             : 
     178     2524695 :         lock_mode = xchk_parent_ilock_dir(dp);
     179     2517367 :         if (!lock_mode) {
     180     1771466 :                 xchk_iunlock(sc, XFS_ILOCK_EXCL);
     181     1761125 :                 xchk_ilock(sc, XFS_ILOCK_EXCL);
     182     1761029 :                 error = -EAGAIN;
     183     1761029 :                 goto out_rele;
     184             :         }
     185             : 
     186             :         /*
     187             :          * We cannot yet validate this parent pointer if the directory looks as
     188             :          * though it has been zapped by the inode record repair code.
     189             :          */
     190      745901 :         if (xchk_dir_looks_zapped(dp)) {
     191           0 :                 error = -EFSCORRUPTED;
     192           0 :                 xchk_set_incomplete(sc);
     193           0 :                 goto out_unlock;
     194             :         }
     195             : 
     196             :         /* Metadata and regular inodes cannot cross trees. */
     197      745783 :         if (xfs_is_metadir_inode(dp) != xfs_is_metadir_inode(sc->ip)) {
     198           0 :                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
     199           0 :                 goto out_unlock;
     200             :         }
     201             : 
     202             :         /* Look for a directory entry in the parent pointing to the child. */
     203      745783 :         error = xchk_dir_walk(sc, dp, xchk_parent_actor, &spc);
     204      746505 :         if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
     205           1 :                 goto out_unlock;
     206             : 
     207             :         /*
     208             :          * Ensure that the parent has as many links to the child as the child
     209             :          * thinks it has to the parent.
     210             :          */
     211      746446 :         if (spc.nlink != expected_nlink)
     212           0 :                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
     213             : 
     214      746446 : out_unlock:
     215      746447 :         xfs_iunlock(dp, lock_mode);
     216     2507312 : out_rele:
     217     2507312 :         xchk_irele(sc, dp);
     218     2522839 :         return error;
     219             : }
     220             : 
     221             : /*
     222             :  * Checking of Parent Pointers
     223             :  * ===========================
     224             :  *
     225             :  * On filesystems with directory parent pointers, we check the referential
     226             :  * integrity by visiting each parent pointer of a child file and checking that
     227             :  * the directory referenced by the pointer actually has a dirent pointing
     228             :  * forward to the child file.
     229             :  */
     230             : 
     231             : /* Deferred parent pointer entry that we saved for later. */
     232             : struct xchk_pptr {
     233             :         /* Cookie for retrieval of the pptr name. */
     234             :         xfblob_cookie                   name_cookie;
     235             : 
     236             :         /* Parent pointer attr key. */
     237             :         xfs_ino_t                       p_ino;
     238             :         uint32_t                        p_gen;
     239             : 
     240             :         /* Length of the pptr name. */
     241             :         uint8_t                         namelen;
     242             : };
     243             : 
     244             : struct xchk_pptrs {
     245             :         struct xfs_scrub        *sc;
     246             : 
     247             :         /* Scratch buffer for scanning pptr xattrs */
     248             :         struct xfs_parent_name_irec pptr;
     249             : 
     250             :         /* Fixed-size array of xchk_pptr structures. */
     251             :         struct xfarray          *pptr_entries;
     252             : 
     253             :         /* Blobs containing parent pointer names. */
     254             :         struct xfblob           *pptr_names;
     255             : 
     256             :         /* How many parent pointers did we find at the end? */
     257             :         unsigned long long      pptrs_found;
     258             : 
     259             :         /* Parent of this directory. */
     260             :         xfs_ino_t               parent_ino;
     261             : 
     262             :         /* If we've cycled the ILOCK, we must revalidate all deferred pptrs. */
     263             :         bool                    need_revalidate;
     264             : 
     265             :         /* xattr key and da args for parent pointer revalidation. */
     266             :         struct xfs_parent_scratch pptr_scratch;
     267             : };
     268             : 
     269             : /*
     270             :  * Walk an xattr of a file.  If this xattr is a parent pointer, follow it up
     271             :  * to a parent directory and check that the parent has a dirent pointing back
     272             :  * to us.
     273             :  */
     274             : STATIC int
     275    20121721 : xchk_parent_scan_dotdot(
     276             :         struct xfs_scrub        *sc,
     277             :         struct xfs_inode        *ip,
     278             :         unsigned int            attr_flags,
     279             :         const unsigned char     *name,
     280             :         unsigned int            namelen,
     281             :         const void              *value,
     282             :         unsigned int            valuelen,
     283             :         void                    *priv)
     284             : {
     285    20121721 :         struct xchk_pptrs       *pp = priv;
     286    20121721 :         const struct xfs_parent_name_rec *rec = (const void *)name;
     287             : 
     288             :         /* Ignore anything that isn't a parent pointer. */
     289    20121721 :         if (!(attr_flags & XFS_ATTR_PARENT))
     290             :                 return 0;
     291             : 
     292             :         /* Does the ondisk parent pointer structure make sense? */
     293    18588197 :         if (!xfs_parent_namecheck(sc->mp, rec, namelen, attr_flags)) {
     294           0 :                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
     295           0 :                 return -ECANCELED;
     296             :         }
     297             : 
     298    18622781 :         if (!xfs_parent_valuecheck(sc->mp, value, valuelen)) {
     299           0 :                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
     300           0 :                 return -ECANCELED;
     301             :         }
     302             : 
     303    18634426 :         xfs_parent_irec_from_disk(&pp->pptr, rec, value, valuelen);
     304             : 
     305    18619660 :         if (pp->parent_ino == pp->pptr.p_ino)
     306    18622498 :                 return -ECANCELED;
     307             : 
     308             :         return 0;
     309             : }
     310             : 
     311             : /* Look up the dotdot entry so that we can check it as we walk the pptrs. */
     312             : STATIC int
     313    18717778 : xchk_parent_pptr_and_dotdot(
     314             :         struct xchk_pptrs       *pp)
     315             : {
     316    18717778 :         struct xfs_scrub        *sc = pp->sc;
     317    18717778 :         int                     error;
     318             : 
     319             :         /* Look up '..' */
     320    18717778 :         error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &pp->parent_ino);
     321    18705886 :         if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
     322           0 :                 return error;
     323    18699031 :         if (!xfs_verify_dir_ino(sc->mp, pp->parent_ino)) {
     324           0 :                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
     325           0 :                 return 0;
     326             :         }
     327             : 
     328             :         /* Is this the root dir?  Then '..' must point to itself. */
     329    18689927 :         if (sc->ip == sc->mp->m_rootip || sc->ip == sc->mp->m_metadirip) {
     330       60757 :                 if (sc->ip->i_ino != pp->parent_ino)
     331           0 :                         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
     332       60757 :                 return 0;
     333             :         }
     334             : 
     335             :         /*
     336             :          * If this is now an unlinked directory, the dotdot value is
     337             :          * meaningless as long as it points to a valid inode.
     338             :          */
     339    18629170 :         if (VFS_I(sc->ip)->i_nlink == 0)
     340             :                 return 0;
     341             : 
     342    18629168 :         if (pp->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     343             :                 return 0;
     344             : 
     345             :         /* Otherwise, walk the pptrs again, and check. */
     346    18629234 :         error = xchk_xattr_walk(sc, sc->ip, xchk_parent_scan_dotdot, NULL, pp);
     347    18589942 :         if (error == -ECANCELED)
     348             :                 return 0;
     349           0 :         if (error == 0) {
     350             :                 /* Didn't find a matching parent pointer. */
     351           0 :                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
     352             :         }
     353           0 :         return error;
     354             : }
     355             : 
     356             : /*
     357             :  * Try to lock a parent directory for checking dirents.  Returns the inode
     358             :  * flags for the locks we now hold, or zero if we failed.
     359             :  */
     360             : STATIC unsigned int
     361   138870575 : xchk_parent_lock_dir(
     362             :         struct xfs_scrub        *sc,
     363             :         struct xfs_inode        *dp)
     364             : {
     365   138870575 :         if (!xfs_ilock_nowait(dp, XFS_IOLOCK_SHARED))
     366             :                 return 0;
     367             : 
     368    96600312 :         if (!xfs_ilock_nowait(dp, XFS_ILOCK_SHARED)) {
     369      177270 :                 xfs_iunlock(dp, XFS_IOLOCK_SHARED);
     370      177270 :                 return 0;
     371             :         }
     372             : 
     373    96530255 :         if (!xfs_need_iread_extents(&dp->i_df))
     374             :                 return XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED;
     375             : 
     376        1060 :         xfs_iunlock(dp, XFS_ILOCK_SHARED);
     377             : 
     378        1060 :         if (!xfs_ilock_nowait(dp, XFS_ILOCK_EXCL)) {
     379           0 :                 xfs_iunlock(dp, XFS_IOLOCK_SHARED);
     380           0 :                 return 0;
     381             :         }
     382             : 
     383             :         return XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL;
     384             : }
     385             : 
     386             : /* Check the forward link (dirent) associated with this parent pointer. */
     387             : STATIC int
     388    96394912 : xchk_parent_dirent(
     389             :         struct xchk_pptrs       *pp,
     390             :         struct xfs_inode        *dp)
     391             : {
     392    96394912 :         struct xfs_name         xname = {
     393    96394912 :                 .name           = pp->pptr.p_name,
     394    96394912 :                 .len            = pp->pptr.p_namelen,
     395             :         };
     396    96394912 :         struct xfs_scrub        *sc = pp->sc;
     397    96394912 :         xfs_ino_t               child_ino;
     398    96394912 :         int                     error;
     399             : 
     400             :         /*
     401             :          * Use the name attached to this parent pointer to look up the
     402             :          * directory entry in the alleged parent.
     403             :          */
     404    96394912 :         error = xchk_dir_lookup(sc, dp, &xname, &child_ino);
     405    96570186 :         if (error == -ENOENT) {
     406           0 :                 xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
     407           0 :                 return 0;
     408             :         }
     409    96570186 :         if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error))
     410           0 :                 return error;
     411             : 
     412             :         /* Does the inode number match? */
     413    96555143 :         if (child_ino != sc->ip->i_ino) {
     414           0 :                 xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
     415           0 :                 return 0;
     416             :         }
     417             : 
     418             :         return 0;
     419             : }
     420             : 
     421             : /* Try to grab a parent directory. */
     422             : STATIC int
     423   138704095 : xchk_parent_iget(
     424             :         struct xchk_pptrs               *pp,
     425             :         struct xfs_inode                **dpp)
     426             : {
     427   138704095 :         struct xfs_scrub                *sc = pp->sc;
     428   138704095 :         struct xfs_inode                *ip;
     429   138704095 :         int                             error;
     430             : 
     431             :         /* Validate inode number. */
     432   138704095 :         error = xfs_dir_ino_validate(sc->mp, pp->pptr.p_ino);
     433   138656051 :         if (error) {
     434           0 :                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
     435           0 :                 return -ECANCELED;
     436             :         }
     437             : 
     438   138656051 :         error = xchk_iget(sc, pp->pptr.p_ino, &ip);
     439   138958099 :         if (error == -EINVAL || error == -ENOENT) {
     440           0 :                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
     441           0 :                 return -ECANCELED;
     442             :         }
     443   138958099 :         if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error))
     444           0 :                 return error;
     445             : 
     446             :         /* The parent must be a directory. */
     447   138864206 :         if (!S_ISDIR(VFS_I(ip)->i_mode)) {
     448          10 :                 xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
     449          10 :                 goto out_rele;
     450             :         }
     451             : 
     452             :         /* Validate generation number. */
     453   138864196 :         if (VFS_I(ip)->i_generation != pp->pptr.p_gen) {
     454           0 :                 xchk_fblock_xref_set_corrupt(sc, XFS_ATTR_FORK, 0);
     455           0 :                 goto out_rele;
     456             :         }
     457             : 
     458   138864196 :         *dpp = ip;
     459   138864196 :         return 0;
     460          10 : out_rele:
     461          10 :         xchk_irele(sc, ip);
     462          10 :         return 0;
     463             : }
     464             : 
     465             : /*
     466             :  * Walk an xattr of a file.  If this xattr is a parent pointer, follow it up
     467             :  * to a parent directory and check that the parent has a dirent pointing back
     468             :  * to us.
     469             :  */
     470             : STATIC int
     471   179600238 : xchk_parent_scan_attr(
     472             :         struct xfs_scrub        *sc,
     473             :         struct xfs_inode        *ip,
     474             :         unsigned int            attr_flags,
     475             :         const unsigned char     *name,
     476             :         unsigned int            namelen,
     477             :         const void              *value,
     478             :         unsigned int            valuelen,
     479             :         void                    *priv)
     480             : {
     481   179600238 :         struct xfs_name         dname = {
     482             :                 .name           = value,
     483             :                 .len            = valuelen,
     484             :         };
     485   179600238 :         struct xchk_pptrs       *pp = priv;
     486   179600238 :         struct xfs_inode        *dp = NULL;
     487   179600238 :         const struct xfs_parent_name_rec *rec = (const void *)name;
     488   179600238 :         unsigned int            lockmode;
     489   179600238 :         xfs_dahash_t            computed_hash;
     490   179600238 :         int                     error;
     491             : 
     492             :         /* Ignore anything that isn't a parent pointer. */
     493   179600238 :         if (!(attr_flags & XFS_ATTR_PARENT))
     494             :                 return 0;
     495             : 
     496             :         /* Does the ondisk parent pointer structure make sense? */
     497   138775448 :         if (!xfs_parent_namecheck(sc->mp, rec, namelen, attr_flags)) {
     498           0 :                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
     499           0 :                 return -ECANCELED;
     500             :         }
     501             : 
     502   138816085 :         if (!xfs_parent_valuecheck(sc->mp, value, valuelen)) {
     503           0 :                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
     504           0 :                 return -ECANCELED;
     505             :         }
     506             : 
     507   138620784 :         xfs_parent_irec_from_disk(&pp->pptr, rec, value, valuelen);
     508             : 
     509             :         /*
     510             :          * If the namehash of the dirent name encoded in the parent pointer
     511             :          * attr value doesn't match the namehash in the parent pointer key,
     512             :          * the parent pointer is corrupt.
     513             :          */
     514   138594162 :         computed_hash = xfs_dir2_hashname(ip->i_mount, &dname);
     515   138633002 :         if (pp->pptr.p_namehash != computed_hash) {
     516           0 :                 xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
     517           0 :                 return -ECANCELED;
     518             :         }
     519   138633002 :         pp->pptrs_found++;
     520             : 
     521   138633002 :         error = xchk_parent_iget(pp, &dp);
     522   138867214 :         if (error)
     523             :                 return error;
     524   138867214 :         if (!dp)
     525             :                 return 0;
     526             : 
     527             :         /* Try to lock the inode. */
     528   138867204 :         lockmode = xchk_parent_lock_dir(sc, dp);
     529   138797601 :         if (!lockmode) {
     530    42320893 :                 struct xchk_pptr        save_pp = {
     531    42320893 :                         .p_ino          = pp->pptr.p_ino,
     532    42320893 :                         .p_gen          = pp->pptr.p_gen,
     533    42320893 :                         .namelen        = pp->pptr.p_namelen,
     534             :                 };
     535             : 
     536             :                 /* Couldn't lock the inode, so save the pptr for later. */
     537    42320893 :                 trace_xchk_parent_defer(sc->ip, pp->pptr.p_name,
     538    42320893 :                                 pp->pptr.p_namelen, dp->i_ino);
     539             : 
     540    84730666 :                 error = xfblob_store(pp->pptr_names, &save_pp.name_cookie,
     541    42310662 :                                 pp->pptr.p_name, pp->pptr.p_namelen);
     542    42420004 :                 if (xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0,
     543             :                                         &error))
     544    42330178 :                         goto out_rele;
     545             : 
     546           0 :                 error = xfarray_append(pp->pptr_entries, &save_pp);
     547           0 :                 if (xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0,
     548             :                                         &error))
     549             :                         goto out_rele;
     550             : 
     551           0 :                 goto out_rele;
     552             :         }
     553             : 
     554    96476708 :         error = xchk_parent_dirent(pp, dp);
     555    96591389 :         if (error)
     556             :                 goto out_unlock;
     557             : 
     558             : out_unlock:
     559    96591389 :         xfs_iunlock(dp, lockmode);
     560   138802766 : out_rele:
     561   138802766 :         xchk_irele(sc, dp);
     562   138888364 :         return error;
     563             : }
     564             : 
     565             : /*
     566             :  * Revalidate a parent pointer that we collected in the past but couldn't check
     567             :  * because of lock contention.  Returns 0 if the parent pointer is still valid,
     568             :  * -ENOENT if it has gone away on us, or a negative errno.
     569             :  */
     570             : STATIC int
     571           0 : xchk_parent_revalidate_pptr(
     572             :         struct xchk_pptrs       *pp)
     573             : {
     574           0 :         struct xfs_scrub        *sc = pp->sc;
     575           0 :         int                     error;
     576             : 
     577           0 :         error = xfs_parent_lookup(sc->tp, sc->ip, &pp->pptr,
     578             :                         &pp->pptr_scratch);
     579           0 :         if (error == -ENOATTR) {
     580             :                 /* Parent pointer went away, nothing to revalidate. */
     581           0 :                 return -ENOENT;
     582             :         }
     583             : 
     584             :         return error;
     585             : }
     586             : 
     587             : /*
     588             :  * Check a parent pointer the slow way, which means we cycle locks a bunch
     589             :  * and put up with revalidation until we get it done.
     590             :  */
     591             : STATIC int
     592           0 : xchk_parent_slow_pptr(
     593             :         struct xchk_pptrs       *pp,
     594             :         struct xchk_pptr        *pptr)
     595             : {
     596           0 :         struct xfs_scrub        *sc = pp->sc;
     597           0 :         struct xfs_inode        *dp = NULL;
     598           0 :         unsigned int            lockmode;
     599           0 :         int                     error;
     600             : 
     601             :         /* Restore the saved parent pointer into the irec. */
     602           0 :         pp->pptr.p_ino = pptr->p_ino;
     603           0 :         pp->pptr.p_gen = pptr->p_gen;
     604             : 
     605           0 :         error = xfblob_load(pp->pptr_names, pptr->name_cookie, pp->pptr.p_name,
     606           0 :                         pptr->namelen);
     607           0 :         if (error)
     608             :                 return error;
     609           0 :         pp->pptr.p_name[MAXNAMELEN - 1] = 0;
     610           0 :         pp->pptr.p_namelen = pptr->namelen;
     611           0 :         xfs_parent_irec_hashname(sc->mp, &pp->pptr);
     612             : 
     613             :         /* Check that the deferred parent pointer still exists. */
     614           0 :         if (pp->need_revalidate) {
     615           0 :                 error = xchk_parent_revalidate_pptr(pp);
     616           0 :                 if (error == -ENOENT)
     617             :                         return 0;
     618           0 :                 if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0,
     619             :                                         &error))
     620           0 :                         return error;
     621             :         }
     622             : 
     623           0 :         error = xchk_parent_iget(pp, &dp);
     624           0 :         if (error)
     625             :                 return error;
     626           0 :         if (!dp)
     627             :                 return 0;
     628             : 
     629             :         /*
     630             :          * If we can grab both IOLOCK and ILOCK of the alleged parent, we
     631             :          * can proceed with the validation.
     632             :          */
     633           0 :         lockmode = xchk_parent_lock_dir(sc, dp);
     634           0 :         if (lockmode)
     635           0 :                 goto check_dirent;
     636             : 
     637             :         /*
     638             :          * We couldn't lock the parent dir.  Drop all the locks and try to
     639             :          * get them again, one at a time.
     640             :          */
     641           0 :         xchk_iunlock(sc, sc->ilock_flags);
     642           0 :         pp->need_revalidate = true;
     643             : 
     644           0 :         trace_xchk_parent_slowpath(sc->ip, pp->pptr.p_name, pptr->namelen,
     645           0 :                         dp->i_ino);
     646             : 
     647           0 :         while (true) {
     648           0 :                 xchk_ilock(sc, XFS_IOLOCK_EXCL);
     649           0 :                 if (xfs_ilock_nowait(dp, XFS_IOLOCK_SHARED)) {
     650           0 :                         xchk_ilock(sc, XFS_ILOCK_EXCL);
     651           0 :                         if (xfs_ilock_nowait(dp, XFS_ILOCK_EXCL)) {
     652             :                                 break;
     653             :                         }
     654           0 :                         xchk_iunlock(sc, XFS_ILOCK_EXCL);
     655             :                 }
     656           0 :                 xchk_iunlock(sc, XFS_IOLOCK_EXCL);
     657             : 
     658           0 :                 if (xchk_should_terminate(sc, &error))
     659           0 :                         goto out_rele;
     660             : 
     661           0 :                 delay(1);
     662             :         }
     663           0 :         lockmode = XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL;
     664             : 
     665             :         /* Revalidate the parent pointer now that we cycled locks. */
     666           0 :         error = xchk_parent_revalidate_pptr(pp);
     667           0 :         if (error == -ENOENT)
     668           0 :                 goto out_unlock;
     669           0 :         if (!xchk_fblock_xref_process_error(sc, XFS_ATTR_FORK, 0, &error))
     670           0 :                 goto out_unlock;
     671             : 
     672           0 : check_dirent:
     673           0 :         error = xchk_parent_dirent(pp, dp);
     674           0 : out_unlock:
     675           0 :         xfs_iunlock(dp, lockmode);
     676           0 : out_rele:
     677           0 :         xchk_irele(sc, dp);
     678           0 :         return error;
     679             : }
     680             : 
     681             : /* Check all the parent pointers that we deferred the first time around. */
     682             : STATIC int
     683   128703497 : xchk_parent_finish_slow_pptrs(
     684             :         struct xchk_pptrs       *pp)
     685             : {
     686   128703497 :         xfarray_idx_t           array_cur;
     687   128703497 :         int                     error;
     688             : 
     689   128703497 :         foreach_xfarray_idx(pp->pptr_entries, array_cur) {
     690           0 :                 struct xchk_pptr        pptr;
     691             : 
     692           0 :                 if (pp->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     693           0 :                         return 0;
     694             : 
     695           0 :                 error = xfarray_load(pp->pptr_entries, array_cur, &pptr);
     696           0 :                 if (error)
     697           0 :                         return error;
     698             : 
     699           0 :                 error = xchk_parent_slow_pptr(pp, &pptr);
     700           0 :                 if (error)
     701           0 :                         return error;
     702             :         }
     703             : 
     704             :         /* Empty out both xfiles now that we've checked everything. */
     705   128271236 :         xfarray_truncate(pp->pptr_entries);
     706   129021943 :         xfblob_truncate(pp->pptr_names);
     707   129021943 :         return 0;
     708             : }
     709             : 
     710             : /* Count the number of parent pointers. */
     711             : STATIC int
     712           0 : xchk_parent_count_pptr(
     713             :         struct xfs_scrub        *sc,
     714             :         struct xfs_inode        *ip,
     715             :         unsigned int            attr_flags,
     716             :         const unsigned char     *name,
     717             :         unsigned int            namelen,
     718             :         const void              *value,
     719             :         unsigned int            valuelen,
     720             :         void                    *priv)
     721             : {
     722           0 :         struct xchk_pptrs       *pp = priv;
     723             : 
     724           0 :         if (attr_flags & XFS_ATTR_PARENT)
     725           0 :                 pp->pptrs_found++;
     726           0 :         return 0;
     727             : }
     728             : 
     729             : /*
     730             :  * Compare the number of parent pointers to the link count.  For
     731             :  * non-directories these should be the same.  For unlinked directories the
     732             :  * count should be zero; for linked directories, it should be nonzero.
     733             :  */
     734             : STATIC int
     735   128763323 : xchk_parent_count_pptrs(
     736             :         struct xchk_pptrs       *pp)
     737             : {
     738   128763323 :         struct xfs_scrub        *sc = pp->sc;
     739   128763323 :         int                     error;
     740             : 
     741             :         /*
     742             :          * If we cycled the ILOCK while cross-checking parent pointers with
     743             :          * dirents, then we need to recalculate the number of parent pointers.
     744             :          */
     745   128763323 :         if (pp->need_revalidate) {
     746           0 :                 pp->pptrs_found = 0;
     747           0 :                 error = xchk_xattr_walk(sc, sc->ip, xchk_parent_count_pptr,
     748             :                                 NULL, pp);
     749           0 :                 if (error == -ECANCELED)
     750             :                         return 0;
     751           0 :                 if (error)
     752             :                         return error;
     753             :         }
     754             : 
     755   128763323 :         if (S_ISDIR(VFS_I(sc->ip)->i_mode)) {
     756    18645930 :                 if (sc->ip == sc->mp->m_rootip ||
     757    18585173 :                     sc->ip == sc->mp->m_metadirip)
     758       60757 :                         pp->pptrs_found++;
     759             : 
     760    18645930 :                 if (VFS_I(sc->ip)->i_nlink == 0 && pp->pptrs_found > 0)
     761           0 :                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
     762    18645930 :                 else if (VFS_I(sc->ip)->i_nlink > 0 &&
     763    18621009 :                          pp->pptrs_found == 0)
     764           0 :                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
     765             :         } else {
     766   110117393 :                 if (VFS_I(sc->ip)->i_nlink != pp->pptrs_found)
     767           0 :                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
     768             :         }
     769             : 
     770             :         return 0;
     771             : }
     772             : 
     773             : /* Check parent pointers of a file. */
     774             : STATIC int
     775   128721370 : xchk_parent_pptr(
     776             :         struct xfs_scrub        *sc)
     777             : {
     778   128721370 :         struct xchk_pptrs       *pp;
     779   128721370 :         char                    *descr;
     780   128721370 :         int                     error;
     781             : 
     782   128721370 :         pp = kvzalloc(sizeof(struct xchk_pptrs), XCHK_GFP_FLAGS);
     783   128807940 :         if (!pp)
     784             :                 return -ENOMEM;
     785   128807940 :         pp->sc = sc;
     786             : 
     787             :         /*
     788             :          * Set up some staging memory for parent pointers that we can't check
     789             :          * due to locking contention.
     790             :          */
     791   128807940 :         descr = xchk_xfile_ino_descr(sc, "slow parent pointer entries");
     792   128549249 :         error = xfarray_create(descr, 0, sizeof(struct xchk_pptr),
     793             :                         &pp->pptr_entries);
     794   128241445 :         kfree(descr);
     795   128507632 :         if (error)
     796           0 :                 goto out_pp;
     797             : 
     798   128507632 :         descr = xchk_xfile_ino_descr(sc, "slow parent pointer names");
     799   128458460 :         error = xfblob_create(descr, &pp->pptr_names);
     800   129035256 :         kfree(descr);
     801   128918184 :         if (error)
     802           0 :                 goto out_entries;
     803             : 
     804   128918184 :         error = xchk_xattr_walk(sc, sc->ip, xchk_parent_scan_attr, NULL, pp);
     805   128777531 :         if (error == -ECANCELED) {
     806           0 :                 error = 0;
     807           0 :                 goto out_names;
     808             :         }
     809   128777531 :         if (error)
     810           0 :                 goto out_names;
     811             : 
     812   128777531 :         error = xchk_parent_finish_slow_pptrs(pp);
     813   128991474 :         if (error)
     814           0 :                 goto out_names;
     815             : 
     816   128991474 :         if (pp->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     817           0 :                 goto out_names;
     818             : 
     819             :         /*
     820             :          * For subdirectories, make sure the dotdot entry references the same
     821             :          * inode as the parent pointers.
     822             :          *
     823             :          * If we're scanning a /consistent/ directory, there should only be
     824             :          * one parent pointer, and it should point to the same directory as
     825             :          * the dotdot entry.
     826             :          *
     827             :          * However, a corrupt directory tree might feature a subdirectory with
     828             :          * multiple parents.  The directory loop scanner is responsible for
     829             :          * correcting that kind of problem, so for now we only validate that
     830             :          * the dotdot entry matches /one/ of the parents.
     831             :          */
     832   128991474 :         if (S_ISDIR(VFS_I(sc->ip)->i_mode)) {
     833    18738601 :                 error = xchk_parent_pptr_and_dotdot(pp);
     834    18634561 :                 if (error)
     835           0 :                         goto out_names;
     836             :         }
     837             : 
     838             :         if (pp->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     839             :                 goto out_pp;
     840             : 
     841             :         /*
     842   128887434 :          * Complain if the number of parent pointers doesn't match the link
     843   128417658 :          * count.  This could be a sign of missing parent pointers (or an
     844           0 :          * incorrect link count).
     845             :          */
     846   128417658 :         error = xchk_parent_count_pptrs(pp);
     847   128417658 :         if (error)
     848   128337160 :                 goto out_names;
     849   128337160 : 
     850   128676105 : out_names:
     851   128676105 :         xfblob_destroy(pp->pptr_names);
     852   128676105 : out_entries:
     853             :         xfarray_destroy(pp->pptr_entries);
     854             : out_pp:
     855             :         kvfree(pp);
     856             :         return error;
     857   133603900 : }
     858             : 
     859             : /* Scrub a parent pointer. */
     860   133603900 : int
     861   133603900 : xchk_parent(
     862   133603900 :         struct xfs_scrub        *sc)
     863             : {
     864   133603900 :         struct xfs_mount        *mp = sc->mp;
     865   128921483 :         xfs_ino_t               parent_ino;
     866             :         int                     error = 0;
     867             : 
     868             :         if (xfs_has_parent(mp))
     869             :                 return xchk_parent_pptr(sc);
     870             : 
     871     4682417 :         /*
     872             :          * If we're a directory, check that the '..' link points up to
     873             :          * a directory that has one entry pointing to us.
     874             :          */
     875      749682 :         if (!S_ISDIR(VFS_I(sc->ip)->i_mode))
     876           0 :                 return -ENOENT;
     877           0 : 
     878             :         /* We're not a special inode, are we? */
     879             :         if (!xfs_verify_dir_ino(mp, sc->ip->i_ino)) {
     880     2524796 :                 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
     881     2524796 :                 return 0;
     882             :         }
     883             : 
     884             :         do {
     885     2521426 :                 if (xchk_should_terminate(sc, &error))
     886             :                         break;
     887     2516972 : 
     888           0 :                 /* Look up '..' */
     889     2511341 :                 error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot,
     890           0 :                                 &parent_ino);
     891           0 :                 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
     892             :                         return error;
     893             :                 if (!xfs_verify_dir_ino(mp, parent_ino)) {
     894             :                         xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
     895             :                         return 0;
     896             :                 }
     897             : 
     898     2490294 :                 /*
     899     2525617 :                  * Check that the dotdot entry points to a parent directory
     900             :                  * containing a dirent pointing to this subdirectory.
     901      749862 :                  */
     902             :                 error = xchk_parent_validate(sc, parent_ino);
     903             :         } while (error == -EAGAIN);
     904             : 
     905             :         return error;
     906             : }

Generated by: LCOV version 1.14