LCOV - code coverage report
Current view: top level - fs/xfs/scrub - dirtree.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-achx @ Mon Jul 31 20:08:12 PDT 2023 Lines: 293 408 71.8 %
Date: 2023-07-31 20:08:12 Functions: 15 20 75.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 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/bitmap.h"
      23             : #include "scrub/xfile.h"
      24             : #include "scrub/xfarray.h"
      25             : #include "scrub/xfblob.h"
      26             : #include "scrub/listxattr.h"
      27             : #include "scrub/trace.h"
      28             : #include "scrub/repair.h"
      29             : #include "scrub/orphanage.h"
      30             : #include "scrub/dirtree.h"
      31             : 
      32             : #include "scrub/readdir.h"
      33             : 
      34             : /*
      35             :  * Directory Tree Structure Validation
      36             :  * ===================================
      37             :  *
      38             :  * Validating the tree qualities of the directory tree structure can be
      39             :  * difficult.  If the tree is frozen, running a depth (or breadth) first search
      40             :  * and marking a bitmap suffices to determine if there is a cycle.  XORing the
      41             :  * mark bitmap with the inode bitmap afterwards tells us if there are
      42             :  * disconnected cycles.  If the tree is not frozen, directory updates can move
      43             :  * subtrees across the scanner wavefront, which complicates the design greatly.
      44             :  *
      45             :  * Directory parent pointers change that by enabling an incremental approach to
      46             :  * validation of the tree structure.  Instead of using one thread to scan the
      47             :  * entire filesystem, we instead can have multiple threads walking individual
      48             :  * subdirectories upwards to the root.  Each scanner thread must be able to
      49             :  * take the IOLOCK of the directory that it is examining to prevent that
      50             :  * directory from being moved within the tree.  This was not possible prior to
      51             :  * Linux 6.5 because the VFS did not take i_rwsem when moving subdirectories.
      52             :  *
      53             :  * If the walk terminates without reaching the root, we know the path is
      54             :  * disconnected and ought to be attached to the lost and found.  If on the walk
      55             :  * we find the same subdir that we're scanning, we know this is a cycle and
      56             :  * should delete an incoming edge.  If we find multiple paths to the root, we
      57             :  * know to delete an incoming edge.
      58             :  *
      59             :  * There are two big hitches with this approach: first, all file link counts
      60             :  * must be correct to prevent other writers from doing the wrong thing with the
      61             :  * directory tree structure.  Second, because we're walking upwards in a tree
      62             :  * of arbitrary depth, we cannot hold all the ILOCKs.  Instead, we will use a
      63             :  * directory update hook to invalidate the scan results if one of the paths
      64             :  * we've scanned has changed.
      65             :  */
      66             : 
      67             : /* Clean up the dirtree checking resources. */
      68             : STATIC void
      69    21591647 : xchk_dirtree_buf_cleanup(
      70             :         void                    *buf)
      71             : {
      72    21591647 :         struct xchk_dirtree     *dl = buf;
      73    21591647 :         struct xchk_dirpath     *path, *n;
      74             : 
      75    21591647 :         if (dl->scan_ino != NULLFSINO)
      76    21582257 :                 xfs_dir_hook_del(dl->sc->mp, &dl->hooks);
      77             : 
      78    43194903 :         xchk_dirtree_for_each_path_safe(dl, path, n) {
      79    21610302 :                 list_del_init(&path->list);
      80    21603177 :                 xino_bitmap_destroy(&path->seen_inodes);
      81    21572769 :                 kfree(path);
      82             :         }
      83             : 
      84    21584601 :         xfblob_destroy(dl->path_names);
      85    21581769 :         xfarray_destroy(dl->path_steps);
      86    21609270 :         mutex_destroy(&dl->lock);
      87    21504823 : }
      88             : 
      89             : /* Set us up to look for directory loops. */
      90             : int
      91    21585444 : xchk_setup_dirtree(
      92             :         struct xfs_scrub        *sc)
      93             : {
      94    21585444 :         struct xchk_dirtree     *dl;
      95    21585444 :         char                    *descr;
      96    21585444 :         int                     error;
      97             : 
      98    21585444 :         xchk_fsgates_enable(sc, XCHK_FSGATES_DIRENTS);
      99             : 
     100    43209102 :         if (xchk_could_repair(sc)) {
     101      530526 :                 error = xrep_setup_dirtree(sc);
     102      530771 :                 if (error)
     103             :                         return error;
     104             :         }
     105             : 
     106    21604796 :         dl = kvzalloc(sizeof(struct xchk_dirtree), XCHK_GFP_FLAGS);
     107    21555320 :         if (!dl)
     108             :                 return -ENOMEM;
     109    21555320 :         dl->sc = sc;
     110    21555320 :         INIT_LIST_HEAD(&dl->path_list);
     111    21555320 :         dl->root_ino = NULLFSINO;
     112    21555320 :         dl->scan_ino = NULLFSINO;
     113    21555320 :         dl->parent_ino = NULLFSINO;
     114             : 
     115    21555320 :         mutex_init(&dl->lock);
     116             : 
     117    21379570 :         descr = xchk_xfile_ino_descr(sc, "dirtree path steps");
     118    21322980 :         error = xfarray_create(descr, 0, sizeof(struct xchk_dirpath_step),
     119             :                         &dl->path_steps);
     120    21307323 :         kfree(descr);
     121    21321406 :         if (error)
     122           0 :                 goto out_dl;
     123             : 
     124    21321406 :         descr = xchk_xfile_ino_descr(sc, "dirtree path names");
     125    21342628 :         error = xfblob_create(descr, &dl->path_names);
     126    21611167 :         kfree(descr);
     127    21551860 :         if (error)
     128           0 :                 goto out_steps;
     129             : 
     130    21551860 :         error = xchk_setup_inode_contents(sc, 0);
     131    21455299 :         if (error)
     132          23 :                 goto out_names;
     133             : 
     134    21455276 :         sc->buf = dl;
     135    21455276 :         sc->buf_cleanup = xchk_dirtree_buf_cleanup;
     136    21455276 :         return 0;
     137             : 
     138             : out_names:
     139          23 :         xfblob_destroy(dl->path_names);
     140          23 : out_steps:
     141          23 :         xfarray_destroy(dl->path_steps);
     142          23 : out_dl:
     143          23 :         mutex_destroy(&dl->lock);
     144          23 :         kvfree(dl);
     145          23 :         return error;
     146             : }
     147             : 
     148             : /*
     149             :  * Add the parent pointer described by @dl->pptr to the given path as a new
     150             :  * step.  Returns -ELNRNG if the path is too deep.
     151             :  */
     152             : int
     153  1698819557 : xchk_dirpath_append(
     154             :         struct xchk_dirtree             *dl,
     155             :         struct xfs_inode                *ip,
     156             :         struct xchk_dirpath             *path,
     157             :         const struct xfs_parent_name_irec *pptr)
     158             : {
     159  1698819557 :         struct xchk_dirpath_step        step = {
     160  1698819557 :                 .parent_ino             = pptr->p_ino,
     161  1698819557 :                 .parent_gen             = pptr->p_gen,
     162  1698819557 :                 .name_len               = pptr->p_namelen,
     163             :         };
     164  1698819557 :         int                             error;
     165             : 
     166             :         /*
     167             :          * If this path is more than 2 billion steps long, this directory tree
     168             :          * is too far gone to fix.
     169             :          */
     170  1698819557 :         if (path->nr_steps >= XFS_MAXLINK)
     171             :                 return -ELNRNG;
     172             : 
     173  1698819557 :         error = xfblob_store(dl->path_names, &step.name_cookie,
     174  1698819557 :                         dl->pptr.p_name, dl->pptr.p_namelen);
     175  1705040780 :         if (error)
     176             :                 return error;
     177             : 
     178  1705417908 :         error = xino_bitmap_set(&path->seen_inodes, ip->i_ino);
     179  1714264186 :         if (error)
     180             :                 return error;
     181             : 
     182  1714601665 :         error = xfarray_append(dl->path_steps, &step);
     183  1710950242 :         if (error)
     184             :                 return error;
     185             : 
     186  1710950242 :         path->nr_steps++;
     187  1710950242 :         return 0;
     188             : }
     189             : 
     190             : /*
     191             :  * Create an xchk_path for each parent pointer of the directory that we're
     192             :  * scanning.  For each path created, we will eventually try to walk towards the
     193             :  * root with the goal of deleting all parents except for one that leads to the
     194             :  * root.
     195             :  *
     196             :  * Returns -EFSCORRUPTED to signal that the inode being scanned has a corrupt
     197             :  * parent pointer and hence there's no point in continuing; or -ENOSR if there
     198             :  * are too many parent pointers for this directory.
     199             :  */
     200             : STATIC int
     201    21193197 : xchk_dirtree_create_path(
     202             :         struct xfs_scrub                *sc,
     203             :         struct xfs_inode                *ip,
     204             :         const struct xfs_parent_name_irec *pptr,
     205             :         void                            *priv)
     206             : {
     207    21193197 :         struct xchk_dirtree             *dl = priv;
     208    21193197 :         struct xchk_dirpath             *path;
     209    21193197 :         int                             error;
     210             : 
     211             :         /*
     212             :          * If there are more than 2 billion actual parent pointers for this
     213             :          * subdirectory, this fs is too far gone to fix.
     214             :          */
     215    21193197 :         if (dl->nr_paths >= XFS_MAXLINK)
     216             :                 return -ENOSR;
     217             : 
     218    21193197 :         trace_xchk_dirtree_create_path(sc, ip, dl->nr_paths, pptr);
     219             : 
     220             :         /*
     221             :          * Create a new xchk_path structure to remember this parent pointer
     222             :          * and record the first name step.
     223             :          */
     224    21073137 :         path = kmalloc(sizeof(struct xchk_dirpath), XCHK_GFP_FLAGS);
     225    21345294 :         if (!path)
     226             :                 return -ENOMEM;
     227             : 
     228    21345294 :         INIT_LIST_HEAD(&path->list);
     229    21345294 :         xino_bitmap_init(&path->seen_inodes);
     230    21252546 :         path->nr_steps = 0;
     231    21252546 :         path->outcome = XCHK_DIRPATH_SCANNING;
     232             : 
     233    21252546 :         error = xchk_dirpath_append(dl, sc->ip, path, pptr);
     234    21422901 :         if (error)
     235           0 :                 goto out_path;
     236             : 
     237    21422901 :         path->first_step = xfarray_length(dl->path_steps) - 1;
     238    21243177 :         path->second_step = XFARRAY_NULLIDX;
     239    21243177 :         path->path_nr = dl->nr_paths;
     240             : 
     241    21243177 :         list_add_tail(&path->list, &dl->path_list);
     242    21168221 :         dl->nr_paths++;
     243    21168221 :         return 0;
     244             : out_path:
     245           0 :         kfree(path);
     246           0 :         return error;
     247             : }
     248             : 
     249             : /*
     250             :  * Validate that the first step of this path still has a corresponding
     251             :  * parent pointer in @sc->ip.  We probably dropped @sc->ip's ILOCK while
     252             :  * walking towards the roots, which is why this is necessary.
     253             :  *
     254             :  * This function has a side effect of loading the first parent pointer of this
     255             :  * path into the parent pointer scratch pad.  This prepares us to walk up the
     256             :  * directory tree towards the root.  Returns -ESTALE if the scan data is now
     257             :  * out of date.
     258             :  */
     259             : STATIC int
     260    21109979 : xchk_dirpath_revalidate(
     261             :         struct xchk_dirtree             *dl,
     262             :         struct xchk_dirpath             *path)
     263             : {
     264    21109979 :         struct xchk_dirpath_step        step;
     265    21109979 :         struct xfs_scrub                *sc = dl->sc;
     266    21109979 :         int                             error;
     267             : 
     268    21109979 :         error = xfarray_load(dl->path_steps, path->first_step, &step);
     269    21345715 :         if (error)
     270             :                 return error;
     271             : 
     272             :         /*
     273             :          * Check that this parent pointer is still attached to the inode that
     274             :          * we're scanning/
     275             :          */
     276    21332571 :         dl->pptr.p_ino = step.parent_ino;
     277    21332571 :         dl->pptr.p_gen = step.parent_gen;
     278    21332571 :         dl->pptr.p_namelen = step.name_len;
     279             : 
     280    21332571 :         error = xfblob_load(dl->path_names, step.name_cookie, dl->pptr.p_name,
     281             :                         step.name_len);
     282    21473643 :         if (error)
     283             :                 return error;
     284    21436598 :         xfs_parent_irec_hashname(sc->mp, &dl->pptr);
     285             : 
     286             :         /*
     287             :          * Look up the parent pointer that corresponds to the start of this
     288             :          * path.  If the parent pointer has disappeared on us, dump all the
     289             :          * scan results and try again.
     290             :          */
     291    21278945 :         error = xfs_parent_lookup(sc->tp, sc->ip, &dl->pptr, &dl->scratch);
     292    21137984 :         if (error == -ENOATTR) {
     293           0 :                 trace_xchk_dirpath_disappeared(dl->sc, sc->ip, path->path_nr,
     294           0 :                                 path->first_step, &dl->pptr);
     295           0 :                 dl->stale = true;
     296           0 :                 return -ESTALE;
     297             :         }
     298             : 
     299             :         return error;
     300             : }
     301             : 
     302             : /*
     303             :  * Walk the parent pointers of a directory at the end of a path and record
     304             :  * the parent that we find.
     305             :  */
     306             : STATIC int
     307  1671606995 : xchk_dirpath_find_next_step(
     308             :         struct xfs_scrub                *sc,
     309             :         struct xfs_inode                *ip,
     310             :         const struct xfs_parent_name_irec *pptr,
     311             :         void                            *priv)
     312             : {
     313  1671606995 :         unsigned int                    *parents_found = priv;
     314             : 
     315             :         /*
     316             :          * If we've already set @dl->pptr.p_ino, then this directory has
     317             :          * multiple parents.  Signal this back to the caller via -EMLINK.
     318             :          */
     319  1671606995 :         if (*parents_found > 0)
     320             :                 return -EMLINK;
     321             : 
     322  1671606995 :         (*parents_found)++;
     323  1671606995 :         return 0;
     324             : }
     325             : 
     326             : /* Set and log the outcome of a path walk. */
     327             : static inline void
     328             : xchk_dirpath_set_outcome(
     329             :         struct xchk_dirtree             *dl,
     330             :         struct xchk_dirpath             *path,
     331             :         enum xchk_dirpath_outcome       outcome)
     332             : {
     333    21599131 :         trace_xchk_dirpath_set_outcome(dl->sc, path->path_nr, path->nr_steps,
     334             :                         outcome);
     335             : 
     336    21593755 :         path->outcome = outcome;
     337             : }
     338             : 
     339             : /*
     340             :  * Scan the directory at the end of this path for its parent directory link.
     341             :  * If we find one, extend the path.  Returns -ESTALE if the scan data out of
     342             :  * date.  Returns -EFSCORRUPTED if the parent pointer is bad; or -ELNRNG if
     343             :  * the path got too deep.
     344             :  */
     345             : STATIC int
     346  1715534054 : xchk_dirpath_step_up(
     347             :         struct xchk_dirtree     *dl,
     348             :         struct xchk_dirpath     *path)
     349             : {
     350  1715534054 :         struct xfs_scrub        *sc = dl->sc;
     351  1715534054 :         struct xfs_inode        *dp;
     352  1715534054 :         unsigned int            lock_mode;
     353  1715534054 :         unsigned int            parents_found = 0;
     354  1715534054 :         int                     error;
     355             : 
     356             :         /* Grab and lock the parent directory. */
     357  1715534054 :         error = xchk_iget(sc, dl->pptr.p_ino, &dp);
     358  1722779348 :         if (error)
     359             :                 return error;
     360             : 
     361  1723069508 :         lock_mode = xfs_ilock_attr_map_shared(dp);
     362  1710303113 :         mutex_lock(&dl->lock);
     363             : 
     364  1729778740 :         if (dl->stale) {
     365        3492 :                 error = -ESTALE;
     366        3492 :                 goto out_scanlock;
     367             :         }
     368             : 
     369             :         /* We've reached the root directory; the path is ok. */
     370  1729775248 :         if (dl->pptr.p_ino == dl->root_ino) {
     371    21599131 :                 xchk_dirpath_set_outcome(dl, path, XCHK_DIRPATH_OK);
     372    21593755 :                 error = 0;
     373    21593755 :                 goto out_scanlock;
     374             :         }
     375             : 
     376             :         /*
     377             :          * The inode being scanned is its own distant ancestor!  Get rid of
     378             :          * this path.
     379             :          */
     380  1708176117 :         if (dl->pptr.p_ino == sc->ip->i_ino) {
     381           0 :                 xchk_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
     382           0 :                 error = 0;
     383           0 :                 goto out_scanlock;
     384             :         }
     385             : 
     386             :         /*
     387             :          * We've seen this inode before during the path walk.  There's a loop
     388             :          * above us in the directory tree.  This probably means that we cannot
     389             :          * continue, but let's keep walking paths to get a full picture.
     390             :          */
     391  1708176117 :         if (xino_bitmap_test(&path->seen_inodes, dl->pptr.p_ino)) {
     392           0 :                 xchk_dirpath_set_outcome(dl, path, XCHK_DIRPATH_LOOP);
     393           0 :                 error = 0;
     394           0 :                 goto out_scanlock;
     395             :         }
     396             : 
     397             :         /* The handle encoded in the parent pointer must match. */
     398  1691735509 :         if (VFS_I(dp)->i_generation != dl->pptr.p_gen) {
     399           0 :                 trace_xchk_dirpath_badgen(dl->sc, dp, path->path_nr,
     400           0 :                                 path->nr_steps, &dl->pptr);
     401           0 :                 error = -EFSCORRUPTED;
     402           0 :                 goto out_scanlock;
     403             :         }
     404             : 
     405             :         /* Parent pointer must point up to a directory. */
     406  1691735509 :         if (!S_ISDIR(VFS_I(dp)->i_mode)) {
     407           0 :                 trace_xchk_dirpath_nondir_parent(dl->sc, dp, path->path_nr,
     408           0 :                                 path->nr_steps, &dl->pptr);
     409           0 :                 error = -EFSCORRUPTED;
     410           0 :                 goto out_scanlock;
     411             :         }
     412             : 
     413             :         /* Parent cannot be an unlinked directory. */
     414  1691735509 :         if (VFS_I(dp)->i_nlink == 0) {
     415           0 :                 trace_xchk_dirpath_unlinked_parent(dl->sc, dp, path->path_nr,
     416           0 :                                 path->nr_steps, &dl->pptr);
     417           0 :                 error = -EFSCORRUPTED;
     418           0 :                 goto out_scanlock;
     419             :         }
     420             : 
     421             :         /*
     422             :          * Walk the parent pointers of @dp to find the parent of this directory
     423             :          * to find the next step in our walk.  If we find that @dp has exactly
     424             :          * one parent, the parent pointer information will be in @dl->pptr.
     425             :          */
     426  1691735509 :         mutex_unlock(&dl->lock);
     427  1715597928 :         error = xchk_pptr_walk(sc, dp, xchk_dirpath_find_next_step, &dl->pptr,
     428             :                         &parents_found);
     429  1690492659 :         mutex_lock(&dl->lock);
     430  1706119640 :         if (error == -EFSCORRUPTED || error == -EMLINK ||
     431  1712357075 :             (!error && parents_found == 0)) {
     432             :                 /*
     433             :                  * Further up the directory tree from @sc->ip, we found a
     434             :                  * corrupt parent pointer, multiple parent pointers while
     435             :                  * finding this directory's parent, or zero parents despite
     436             :                  * having a nonzero link count.  Keep looking for other paths.
     437             :                  */
     438           0 :                 xchk_dirpath_set_outcome(dl, path, XCHK_DIRPATH_CORRUPT);
     439           0 :                 error = 0;
     440           0 :                 goto out_scanlock;
     441             :         }
     442  1706119640 :         if (error)
     443           0 :                 goto out_scanlock;
     444             : 
     445  1706119640 :         if (dl->stale) {
     446         622 :                 error = -ESTALE;
     447         622 :                 goto out_scanlock;
     448             :         }
     449             : 
     450  1706119018 :         trace_xchk_dirpath_found_next_step(sc, dp, path->path_nr,
     451             :                         path->nr_steps, &dl->pptr);
     452             : 
     453             :         /* Append to the path steps */
     454  1675668944 :         error = xchk_dirpath_append(dl, dp, path, &dl->pptr);
     455  1693471055 :         if (error)
     456           0 :                 goto out_scanlock;
     457             : 
     458  1693471055 :         if (path->second_step == XFARRAY_NULLIDX)
     459    21366008 :                 path->second_step = xfarray_length(dl->path_steps) - 1;
     460             : 
     461  1672105047 : out_scanlock:
     462  1714988701 :         mutex_unlock(&dl->lock);
     463  1732946445 :         xfs_iunlock(dp, lock_mode);
     464  1693935981 :         xchk_irele(sc, dp);
     465  1693935981 :         return error;
     466             : }
     467             : 
     468             : /*
     469             :  * Walk the directory tree upwards towards what is hopefully the root
     470             :  * directory, recording path steps as we go.  Returns -ESTALE if the scan data
     471             :  * are out of date.  Returns -EFSCORRUPTED only if the direct parent pointer of
     472             :  * @sc->ip associated with this path is corrupt.
     473             :  */
     474             : STATIC int
     475    21289713 : xchk_dirpath_walk_upwards(
     476             :         struct xchk_dirtree     *dl,
     477             :         struct xchk_dirpath     *path)
     478             : {
     479    21289713 :         struct xfs_scrub        *sc = dl->sc;
     480    21289713 :         int                     error;
     481             : 
     482    21289713 :         ASSERT(sc->ilock_flags & XFS_ILOCK_EXCL);
     483             : 
     484             :         /* Reload the start of this path and make sure it's still there. */
     485    21289713 :         error = xchk_dirpath_revalidate(dl, path);
     486    21150697 :         if (error)
     487             :                 return error;
     488             : 
     489    20996438 :         trace_xchk_dirpath_walk_upwards(sc, sc->ip, path->path_nr, &dl->pptr);
     490             : 
     491             :         /*
     492             :          * The inode being scanned is its own direct ancestor!
     493             :          * Get rid of this path.
     494             :          */
     495    20904543 :         if (dl->pptr.p_ino == sc->ip->i_ino) {
     496           0 :                 xchk_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
     497           0 :                 return 0;
     498             :         }
     499             : 
     500             :         /*
     501             :          * Drop ILOCK_EXCL on the inode being scanned.  We still hold
     502             :          * IOLOCK_EXCL on it, so it cannot move around or be renamed.
     503             :          *
     504             :          * Beyond this point we're walking up the directory tree, which means
     505             :          * that we can acquire and drop the ILOCK on an alias of sc->ip.  The
     506             :          * ILOCK state is no longer tracked in the scrub context.  Hence we
     507             :          * must drop @sc->ip's ILOCK during the walk.
     508             :          */
     509    20904543 :         mutex_unlock(&dl->lock);
     510    21453861 :         xchk_iunlock(sc, XFS_ILOCK_EXCL);
     511             : 
     512             :         /*
     513             :          * Take the first step in the walk towards the root by checking the
     514             :          * start of this path, which is a direct parent pointer of @sc->ip.
     515             :          * If we see any kind of error here (including corruptions), the parent
     516             :          * pointer of @sc->ip is corrupt.  Stop the whole scan.
     517             :          */
     518    21266745 :         error = xchk_dirpath_step_up(dl, path);
     519    21445168 :         if (error) {
     520           0 :                 xchk_ilock(sc, XFS_ILOCK_EXCL);
     521           0 :                 mutex_lock(&dl->lock);
     522           0 :                 return error;
     523             :         }
     524             : 
     525             :         /*
     526             :          * Take steps upward from the second step in this path towards the
     527             :          * root.  If we hit corruption errors here, there's a problem
     528             :          * *somewhere* in the path, but we don't need to stop scanning.
     529             :          */
     530  1721860895 :         while (!error && path->outcome == XCHK_DIRPATH_SCANNING)
     531  1700250788 :                 error = xchk_dirpath_step_up(dl, path);
     532             : 
     533             :         /* Retake the locks we had, mark paths, etc. */
     534    21610107 :         xchk_ilock(sc, XFS_ILOCK_EXCL);
     535    21596916 :         mutex_lock(&dl->lock);
     536    21604184 :         if (error == -EFSCORRUPTED) {
     537           0 :                 xchk_dirpath_set_outcome(dl, path, XCHK_DIRPATH_CORRUPT);
     538           0 :                 error = 0;
     539             :         }
     540    21604184 :         if (!error && dl->stale)
     541          50 :                 return -ESTALE;
     542             :         return error;
     543             : }
     544             : 
     545             : /*
     546             :  * Decide if this path step has been touched by this live update.  Returns
     547             :  * 1 for yes, 0 for no, or a negative errno.
     548             :  */
     549             : STATIC int
     550      205093 : xchk_dirpath_step_is_stale(
     551             :         struct xchk_dirtree             *dl,
     552             :         struct xchk_dirpath             *path,
     553             :         unsigned int                    step_nr,
     554             :         xfarray_idx_t                   step_idx,
     555             :         struct xfs_dir_update_params    *p,
     556             :         struct xchk_dirpath_step        *step)
     557             : {
     558      205093 :         xfs_ino_t                       child_ino = step->parent_ino;
     559      205093 :         int                             error;
     560             : 
     561      205093 :         error = xfarray_load(dl->path_steps, step_idx, step);
     562      205093 :         if (error)
     563             :                 return error;
     564             : 
     565             :         /*
     566             :          * If the parent and child being updated are not the ones mentioned in
     567             :          * this path step, the scan data is still ok.
     568             :          */
     569      205093 :         if (p->ip->i_ino != child_ino || p->dp->i_ino != step->parent_ino)
     570             :                 return 0;
     571             : 
     572             :         /*
     573             :          * If the dirent name lengths or byte sequences are different, the scan
     574             :          * data is still ok.
     575             :          */
     576        5830 :         if (p->name->len != step->name_len)
     577             :                 return 0;
     578             : 
     579        5830 :         error = xfblob_load(dl->path_names, step->name_cookie,
     580        5830 :                         dl->hook_namebuf, step->name_len);
     581        5830 :         if (error)
     582             :                 return error;
     583             : 
     584       11660 :         if (memcmp(dl->hook_namebuf, p->name->name, p->name->len) != 0)
     585             :                 return 0;
     586             : 
     587             :         /*
     588             :          * If the update comes from the repair code itself, walk the state
     589             :          * machine forward.
     590             :          */
     591        5830 :         if (p->ip->i_ino == dl->scan_ino &&
     592          41 :             path->outcome == XREP_DIRPATH_ADOPTING) {
     593           0 :                 xchk_dirpath_set_outcome(dl, path, XREP_DIRPATH_ADOPTED);
     594           0 :                 return 0;
     595             :         }
     596             : 
     597        5830 :         if (p->ip->i_ino == dl->scan_ino &&
     598          41 :             path->outcome == XREP_DIRPATH_DELETING) {
     599           0 :                 xchk_dirpath_set_outcome(dl, path, XREP_DIRPATH_DELETED);
     600           0 :                 return 0;
     601             :         }
     602             : 
     603             :         /* Exact match, scan data is out of date. */
     604        5830 :         trace_xchk_dirpath_changed(dl->sc, path->path_nr, step_nr, p->dp,
     605             :                         p->ip, p->name);
     606        5830 :         return 1;
     607             : }
     608             : 
     609             : /*
     610             :  * Decide if this path has been touched by this live update.  Returns 1 for
     611             :  * yes, 0 for no, or a negative errno.
     612             :  */
     613             : STATIC int
     614    16478697 : xchk_dirpath_is_stale(
     615             :         struct xchk_dirtree             *dl,
     616             :         struct xchk_dirpath             *path,
     617             :         struct xfs_dir_update_params    *p)
     618             : {
     619    16478697 :         struct xchk_dirpath_step        step = {
     620    16478697 :                 .parent_ino             = dl->scan_ino,
     621             :         };
     622    16478697 :         xfarray_idx_t                   idx = path->first_step;
     623    16478697 :         unsigned int                    i;
     624    16478697 :         int                             ret;
     625             : 
     626             :         /*
     627             :          * The child being updated has not been seen by this path at all; this
     628             :          * path cannot be stale.
     629             :          */
     630    16478697 :         if (!xino_bitmap_test(&path->seen_inodes, p->ip->i_ino))
     631             :                 return 0;
     632             : 
     633        5830 :         ret = xchk_dirpath_step_is_stale(dl, path, 0, idx, p, &step);
     634        5830 :         if (ret != 0)
     635             :                 return ret;
     636             : 
     637      199263 :         for (i = 1, idx = path->second_step; i < path->nr_steps; i++, idx++) {
     638      199263 :                 ret = xchk_dirpath_step_is_stale(dl, path, i, idx, p, &step);
     639      199263 :                 if (ret != 0)
     640        5789 :                         return ret;
     641             :         }
     642             : 
     643             :         return 0;
     644             : }
     645             : 
     646             : /*
     647             :  * Decide if a directory update from the regular filesystem touches any of the
     648             :  * paths we've scanned, and invalidate the scan data if true.
     649             :  */
     650             : STATIC int
     651    16787456 : xchk_dirtree_live_update(
     652             :         struct notifier_block           *nb,
     653             :         unsigned long                   action,
     654             :         void                            *data)
     655             : {
     656    16787456 :         struct xfs_dir_update_params    *p = data;
     657    16787456 :         struct xchk_dirtree             *dl;
     658    16787456 :         struct xchk_dirpath             *path;
     659    16787456 :         int                             ret;
     660             : 
     661    16787456 :         dl = container_of(nb, struct xchk_dirtree, hooks.dirent_hook.nb);
     662             : 
     663    16787456 :         trace_xchk_dirtree_live_update(dl->sc, p->dp, action, p->ip, p->delta,
     664             :                         p->name);
     665             : 
     666    16787430 :         mutex_lock(&dl->lock);
     667             : 
     668    16787489 :         if (dl->stale || dl->aborted)
     669      307468 :                 goto out_unlock;
     670             : 
     671    32952841 :         xchk_dirtree_for_each_path(dl, path) {
     672    16478704 :                 ret = xchk_dirpath_is_stale(dl, path, p);
     673    16478650 :                 if (ret < 0) {
     674           0 :                         dl->aborted = true;
     675           0 :                         break;
     676             :                 }
     677    16478650 :                 if (ret == 1) {
     678        5830 :                         dl->stale = true;
     679        5830 :                         break;
     680             :                 }
     681             :         }
     682             : 
     683    16474137 : out_unlock:
     684    16787435 :         mutex_unlock(&dl->lock);
     685    16787515 :         return NOTIFY_DONE;
     686             : }
     687             : 
     688             : /* Delete all the collected path information. */
     689             : STATIC void
     690    21615164 : xchk_dirtree_reset(
     691             :         void                    *buf)
     692             : {
     693    21615164 :         struct xchk_dirtree     *dl = buf;
     694    21615164 :         struct xchk_dirpath     *path, *n;
     695             : 
     696    21615164 :         ASSERT(dl->sc->ilock_flags & XFS_ILOCK_EXCL);
     697             : 
     698    21613362 :         xchk_dirtree_for_each_path_safe(dl, path, n) {
     699        4165 :                 list_del_init(&path->list);
     700        4165 :                 xino_bitmap_destroy(&path->seen_inodes);
     701        4165 :                 kfree(path);
     702             :         }
     703    21609197 :         dl->nr_paths = 0;
     704             : 
     705    21609197 :         xfarray_truncate(dl->path_steps);
     706    21594788 :         xfblob_truncate(dl->path_names);
     707             : 
     708    21601059 :         dl->stale = false;
     709    21601059 : }
     710             : 
     711             : /*
     712             :  * For each parent pointer of this subdir, trace a path upwards towards the
     713             :  * root directory and record what we find.  Returns 0 for success;
     714             :  * -EFSCORRUPTED if walking the parent pointers of @sc->ip failed, -ELNRNG if a
     715             :  * path was too deep; -ENOSR if there were too many parent pointers; or
     716             :  * a negative errno.
     717             :  */
     718             : int
     719    21630906 : xchk_dirtree_find_paths_to_root(
     720             :         struct xchk_dirtree     *dl)
     721             : {
     722    21630906 :         struct xfs_scrub        *sc = dl->sc;
     723    21630906 :         struct xchk_dirpath     *path;
     724    21630906 :         int                     error = 0;
     725             : 
     726    21641077 :         do {
     727    21641077 :                 if (xchk_should_terminate(sc, &error))
     728          15 :                         return error;
     729             : 
     730    21629499 :                 xchk_dirtree_reset(dl);
     731             : 
     732             :                 /*
     733             :                  * Create path walk contexts for each parent of the directory
     734             :                  * that is being scanned.  Directories are supposed to have
     735             :                  * only one parent, but this is how we detect multiple parents.
     736             :                  */
     737    21592021 :                 error = xchk_pptr_walk(sc, sc->ip, xchk_dirtree_create_path,
     738             :                                 &dl->pptr, dl);
     739    21228996 :                 if (error)
     740           0 :                         return error;
     741             : 
     742    42802761 :                 xchk_dirtree_for_each_path(dl, path) {
     743             :                         /*
     744             :                          * Try to walk up each path to the root.  This enables
     745             :                          * us to find directory loops in ancestors, and the
     746             :                          * like.
     747             :                          */
     748    21207377 :                         error = xchk_dirpath_walk_upwards(dl, path);
     749    21577929 :                         if (error == -EFSCORRUPTED) {
     750             :                                 /*
     751             :                                  * A parent pointer of @sc->ip is bad, don't
     752             :                                  * bother continuing.
     753             :                                  */
     754             :                                 break;
     755             :                         }
     756    21577929 :                         if (error == -ESTALE) {
     757             :                                 /* This had better be an invalidation. */
     758        4164 :                                 ASSERT(dl->stale);
     759             :                                 break;
     760             :                         }
     761    21573765 :                         if (error)
     762           0 :                                 return error;
     763    21573765 :                         if (dl->aborted)
     764             :                                 return 0;
     765             :                 }
     766    21599548 :         } while (dl->stale);
     767             : 
     768    21589377 :         return error;
     769             : }
     770             : 
     771             : /*
     772             :  * Figure out what to do with the paths we tried to find.  Do not call this
     773             :  * if the scan results are stale.
     774             :  */
     775             : void
     776    22090317 : xchk_dirtree_evaluate(
     777             :         struct xchk_dirtree             *dl,
     778             :         struct xchk_dirtree_outcomes    *oc)
     779             : {
     780    22090317 :         struct xchk_dirpath             *path;
     781             : 
     782    22090317 :         ASSERT(!dl->stale);
     783             : 
     784             :         /* Scan the paths we have to decide what to do. */
     785    22090317 :         memset(oc, 0, sizeof(struct xchk_dirtree_outcomes));
     786    44156978 :         xchk_dirtree_for_each_path(dl, path) {
     787    22062346 :                 trace_xchk_dirpath_evaluate_path(dl->sc, path->path_nr,
     788    22062346 :                                 path->nr_steps, path->outcome);
     789             : 
     790    22066661 :                 switch (path->outcome) {
     791           0 :                 case XCHK_DIRPATH_SCANNING:
     792             :                         /* shouldn't get here */
     793           0 :                         ASSERT(0);
     794           0 :                         break;
     795           0 :                 case XCHK_DIRPATH_DELETE:
     796             :                         /* This one is already going away. */
     797           0 :                         oc->bad++;
     798           0 :                         break;
     799           0 :                 case XCHK_DIRPATH_CORRUPT:
     800             :                 case XCHK_DIRPATH_LOOP:
     801             :                         /* Couldn't find the end of this path. */
     802           0 :                         oc->suspect++;
     803           0 :                         break;
     804           0 :                 case XCHK_DIRPATH_STALE:
     805             :                         /* shouldn't get here either */
     806           0 :                         ASSERT(0);
     807           0 :                         break;
     808    22066661 :                 case XCHK_DIRPATH_OK:
     809             :                         /* This path got all the way to the root. */
     810    22066661 :                         oc->good++;
     811    22066661 :                         break;
     812           0 :                 case XREP_DIRPATH_DELETING:
     813             :                 case XREP_DIRPATH_DELETED:
     814             :                 case XREP_DIRPATH_ADOPTING:
     815             :                 case XREP_DIRPATH_ADOPTED:
     816             :                         /* These should not be in progress! */
     817           0 :                         ASSERT(0);
     818           0 :                         break;
     819             :                 }
     820             :         }
     821             : 
     822    22094632 :         trace_xchk_dirtree_evaluate(dl, oc);
     823    22093005 : }
     824             : 
     825             : /* Dump a path step. */
     826             : STATIC void
     827           0 : xchk_dirpath_step_dump(
     828             :         struct xchk_dirtree             *dl,
     829             :         struct xchk_dirpath             *path,
     830             :         xfarray_idx_t                   idx,
     831             :         unsigned int                    step_nr)
     832             : {
     833           0 :         struct xchk_dirpath_step        step;
     834           0 :         struct xfs_scrub                *sc = dl->sc;
     835           0 :         int                             error;
     836             : 
     837           0 :         error = xfarray_load(dl->path_steps, idx, &step);
     838           0 :         if (error)
     839           0 :                 return;
     840             : 
     841           0 :         error = xfblob_load(dl->path_names, step.name_cookie, dl->pptr.p_name,
     842             :                         step.name_len);
     843           0 :         if (error)
     844             :                 return;
     845             : 
     846           0 :         xfs_err(sc->mp, "    scan_ino 0x%llx path %u step %u parent_ino 0x%llx parent_gen 0x%x name '%.*s'",
     847             :                         sc->ip->i_ino, path->path_nr, step_nr, step.parent_ino,
     848             :                         step.parent_gen, step.name_len, dl->pptr.p_name);
     849             : }
     850             : 
     851             : /* Dump a path. */
     852             : STATIC void
     853           0 : xchk_dirpath_dump(
     854             :         struct xchk_dirtree     *dl,
     855             :         struct xchk_dirpath     *path)
     856             : {
     857           0 :         struct xfs_scrub        *sc = dl->sc;
     858           0 :         xfarray_idx_t           idx;
     859           0 :         unsigned int            i;
     860             : 
     861           0 :         xfs_err(sc->mp, "  scan_ino 0x%llx path %u outcome %u",
     862             :                         dl->scan_ino, path->path_nr, path->outcome);
     863             : 
     864           0 :         if (path->nr_steps > 0)
     865           0 :                 xchk_dirpath_step_dump(dl, path, path->first_step, 0);
     866             : 
     867           0 :         for (i = 1, idx = path->second_step; i < path->nr_steps; i++, idx++)
     868           0 :                 xchk_dirpath_step_dump(dl, path, idx, i);
     869           0 : }
     870             : 
     871             : STATIC int
     872           0 : xchk_dirtree_dump_dirent(
     873             :         struct xfs_scrub        *sc,
     874             :         struct xfs_inode        *dp,
     875             :         xfs_dir2_dataptr_t      dapos,
     876             :         const struct xfs_name   *name,
     877             :         xfs_ino_t               ino,
     878             :         void                    *priv)
     879             : {
     880           0 :         unsigned int            *nrp = priv;
     881             : 
     882           0 :         if (name->type == XFS_DIR3_FT_UNKNOWN ||
     883             :             name->type == XFS_DIR3_FT_DIR)
     884           0 :                 xfs_err(sc->mp, "    scan_ino 0x%llx dirent %u ino 0x%llx name '%.*s' type %u",
     885             :                                 dp->i_ino, (*nrp)++, ino, name->len,
     886             :                                 name->name, name->type);
     887           0 :         return 0;
     888             : }
     889             : 
     890             : STATIC int
     891           0 : xchk_dirtree_dump_pptr(
     892             :         struct xfs_scrub                *sc,
     893             :         struct xfs_inode                *ip,
     894             :         const struct xfs_parent_name_irec *pptr,
     895             :         void                            *priv)
     896             : {
     897           0 :         unsigned int                    *nrp = priv;
     898             : 
     899           0 :         xfs_err(sc->mp, "    scan_ino 0x%llx pptr %u ino 0x%llx name '%.*s'",
     900             :                         ip->i_ino, (*nrp)++, pptr->p_ino, pptr->p_namelen,
     901             :                         pptr->p_name);
     902           0 :         return 0;
     903             : }
     904             : 
     905             : /* Dump all paths. */
     906             : STATIC void
     907           0 : xchk_dirtree_dump(
     908             :         struct xchk_dirtree     *dl,
     909             :         struct xchk_dirtree_outcomes *oc)
     910             : {
     911           0 :         struct xfs_scrub        *sc = dl->sc;
     912           0 :         struct xchk_dirpath     *path;
     913           0 :         unsigned int            nr;
     914             : 
     915           0 :         xfs_err(sc->mp, "scan_ino 0x%llx parentless? %d nlink %u root_ino 0x%llx paths %u stale? %d aborted? %d",
     916             :                         dl->scan_ino, xchk_dirtree_parentless(dl),
     917             :                         VFS_I(sc->ip)->i_nlink,
     918             :                         dl->root_ino, dl->nr_paths, dl->stale, dl->aborted);
     919           0 :         xfs_err(sc->mp, "  scan_ino 0x%llx good %u bad %u suspect %u",
     920             :                         dl->scan_ino, oc->good, oc->bad, oc->suspect);
     921             : 
     922           0 :         xchk_dirtree_for_each_path(dl, path) {
     923           0 :                 xchk_dirpath_dump(dl, path);
     924             :         }
     925             : 
     926           0 :         xfs_err(sc->mp, "  scan_ino 0x%llx dirents", sc->ip->i_ino);
     927           0 :         nr = 0;
     928           0 :         xchk_dir_walk(sc, sc->ip, xchk_dirtree_dump_dirent, &nr);
     929             : 
     930           0 :         xfs_err(sc->mp, "  scan_ino 0x%llx pptrs", sc->ip->i_ino);
     931           0 :         nr = 0;
     932           0 :         xchk_pptr_walk(sc, sc->ip, xchk_dirtree_dump_pptr, &dl->pptr, &nr);
     933           0 : }
     934             : 
     935             : /* Look for directory loops. */
     936             : int
     937    21426684 : xchk_dirtree(
     938             :         struct xfs_scrub                *sc)
     939             : {
     940    21426684 :         struct xchk_dirtree_outcomes    oc;
     941    21426684 :         struct xchk_dirtree             *dl = sc->buf;
     942    21426684 :         int                             error;
     943             : 
     944             :         /*
     945             :          * Nondirectories do not point downwards to other files, so they cannot
     946             :          * cause a cycle in the directory tree.
     947             :          */
     948    21426684 :         if (!S_ISDIR(VFS_I(sc->ip)->i_mode))
     949             :                 return -ENOENT;
     950             : 
     951    21426684 :         ASSERT(xfs_has_parent(sc->mp));
     952             : 
     953             :         /*
     954             :          * Find the root of the directory tree.  Remember which directory to
     955             :          * scan, because the hook doesn't detach until after sc->ip gets
     956             :          * released during teardown.
     957             :          */
     958    21426684 :         dl->root_ino = sc->mp->m_rootip->i_ino;
     959    21426684 :         dl->scan_ino = sc->ip->i_ino;
     960             : 
     961    21426684 :         trace_xchk_dirtree_start(sc->ip, sc->sm, 0);
     962             : 
     963    21304409 :         mutex_lock(&dl->lock);
     964             :         /*
     965             :          * Hook into the directory entry code so that we can capture updates to
     966             :          * paths that we have already scanned.  The scanner thread takes each
     967             :          * directory's ILOCK, which means that any in-progress directory update
     968             :          * will finish before we can scan the directory.
     969             :          */
     970    21561661 :         ASSERT(sc->flags & XCHK_FSGATES_DIRENTS);
     971    21561661 :         xfs_hook_setup(&dl->hooks.dirent_hook, xchk_dirtree_live_update);
     972    21561661 :         error = xfs_dir_hook_add(sc->mp, &dl->hooks);
     973    21637010 :         if (error)
     974           0 :                 goto out_scanlock;
     975             : 
     976             :         /* Trace each parent pointer's path to the root. */
     977    21637010 :         error = xchk_dirtree_find_paths_to_root(dl);
     978    21595923 :         if (error == -EFSCORRUPTED || error == -ELNRNG || error == -ENOSR) {
     979             :                 /*
     980             :                  * Don't bother walking the paths if the xattr structure or the
     981             :                  * parent pointers are corrupt; this scan cannot be completed
     982             :                  * without full information.
     983             :                  */
     984           0 :                 xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
     985           0 :                 error = 0;
     986           0 :                 goto out_scanlock;
     987             :         }
     988    21595923 :         if (error)
     989          15 :                 goto out_scanlock;
     990    21595908 :         if (dl->aborted) {
     991           0 :                 xchk_set_incomplete(sc);
     992           0 :                 goto out_scanlock;
     993             :         }
     994             : 
     995             :         /* Assess what we found in our path evaluation. */
     996    21595908 :         xchk_dirtree_evaluate(dl, &oc);
     997    21574618 :         if (xchk_dirtree_parentless(dl)) {
     998       26952 :                 if (oc.good || oc.bad || oc.suspect)
     999           0 :                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
    1000             : 
    1001       26952 :                 if (oc.good || oc.bad || oc.suspect)
    1002           0 :                         xchk_dirtree_dump(dl, &oc);
    1003             :         } else {
    1004    21547666 :                 if (oc.bad || oc.good + oc.suspect != 1)
    1005         103 :                         xchk_ino_set_corrupt(sc, sc->ip->i_ino);
    1006    21549353 :                 if (oc.suspect)
    1007           0 :                         xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
    1008             : 
    1009    21549353 :                 if (oc.bad || oc.good + oc.suspect != 1 || oc.suspect)
    1010        7137 :                         xchk_dirtree_dump(dl, &oc);
    1011             :         }
    1012             : 
    1013    21542216 : out_scanlock:
    1014    21569183 :         mutex_unlock(&dl->lock);
    1015    21607974 :         trace_xchk_dirtree_done(sc->ip, sc->sm, error);
    1016    21607974 :         return error;
    1017             : }

Generated by: LCOV version 1.14