LCOV - code coverage report
Current view: top level - fs/xfs/scrub - dirtree_repair.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 54 353 15.3 %
Date: 2023-07-31 20:08:27 Functions: 7 17 41.2 %

          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_trans_space.h"
      12             : #include "xfs_mount.h"
      13             : #include "xfs_log_format.h"
      14             : #include "xfs_trans.h"
      15             : #include "xfs_inode.h"
      16             : #include "xfs_icache.h"
      17             : #include "xfs_dir2.h"
      18             : #include "xfs_dir2_priv.h"
      19             : #include "xfs_attr.h"
      20             : #include "xfs_parent.h"
      21             : #include "scrub/scrub.h"
      22             : #include "scrub/common.h"
      23             : #include "scrub/bitmap.h"
      24             : #include "scrub/xfile.h"
      25             : #include "scrub/xfarray.h"
      26             : #include "scrub/xfblob.h"
      27             : #include "scrub/listxattr.h"
      28             : #include "scrub/trace.h"
      29             : #include "scrub/repair.h"
      30             : #include "scrub/orphanage.h"
      31             : #include "scrub/dirtree.h"
      32             : #include "scrub/readdir.h"
      33             : 
      34             : /*
      35             :  * Directory Tree Structure Repairs
      36             :  * ================================
      37             :  *
      38             :  * If we decide that the directory being scanned is participating in a
      39             :  * directory loop, the only change we can make is to remove directory entries
      40             :  * pointing down to @sc->ip.  If that leaves it with no parents, the directory
      41             :  * should be adopted by the orphanage.
      42             :  */
      43             : 
      44             : /* Set up to repair directory loops. */
      45             : int
      46       55833 : xrep_setup_dirtree(
      47             :         struct xfs_scrub        *sc)
      48             : {
      49       55833 :         return xrep_orphanage_try_create(sc);
      50             : }
      51             : 
      52             : /* Change the outcome of this path. */
      53             : static inline void
      54             : xrep_dirpath_set_outcome(
      55             :         struct xchk_dirtree             *dl,
      56             :         struct xchk_dirpath             *path,
      57             :         enum xchk_dirpath_outcome       outcome)
      58             : {
      59           0 :         trace_xrep_dirpath_set_outcome(dl->sc, path->path_nr, path->nr_steps,
      60             :                         outcome);
      61             : 
      62           0 :         path->outcome = outcome;
      63           0 : }
      64             : 
      65             : /* Delete all paths. */
      66             : STATIC void
      67        1405 : xrep_dirtree_delete_all_paths(
      68             :         struct xchk_dirtree             *dl,
      69             :         struct xchk_dirtree_outcomes    *oc)
      70             : {
      71        1405 :         struct xchk_dirpath             *path;
      72             : 
      73        1405 :         xchk_dirtree_for_each_path(dl, path) {
      74           0 :                 switch (path->outcome) {
      75           0 :                 case XCHK_DIRPATH_CORRUPT:
      76             :                 case XCHK_DIRPATH_LOOP:
      77           0 :                         oc->suspect--;
      78           0 :                         oc->bad++;
      79           0 :                         xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
      80             :                         break;
      81           0 :                 case XCHK_DIRPATH_OK:
      82           0 :                         oc->good--;
      83           0 :                         oc->bad++;
      84           0 :                         xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
      85             :                         break;
      86             :                 default:
      87             :                         break;
      88             :                 }
      89             :         }
      90             : 
      91        1405 :         ASSERT(oc->suspect == 0);
      92        1405 :         ASSERT(oc->good == 0);
      93        1405 : }
      94             : 
      95             : /* Since this is the surviving path, set the dotdot entry to this value. */
      96             : STATIC void
      97       54468 : xrep_dirpath_retain_parent(
      98             :         struct xchk_dirtree             *dl,
      99             :         struct xchk_dirpath             *path)
     100             : {
     101       54468 :         struct xchk_dirpath_step        step;
     102       54468 :         int                             error;
     103             : 
     104       54468 :         error = xfarray_load(dl->path_steps, path->first_step, &step);
     105       54471 :         if (error)
     106           0 :                 return;
     107             : 
     108       54471 :         dl->parent_ino = step.parent_ino;
     109             : }
     110             : 
     111             : /* Find the one surviving path so we know how to set dotdot. */
     112             : STATIC void
     113       54470 : xrep_dirtree_find_surviving_path(
     114             :         struct xchk_dirtree             *dl,
     115             :         struct xchk_dirtree_outcomes    *oc)
     116             : {
     117       54470 :         struct xchk_dirpath             *path;
     118       54470 :         bool                            foundit = false;
     119             : 
     120      108941 :         xchk_dirtree_for_each_path(dl, path) {
     121       54470 :                 switch (path->outcome) {
     122       54470 :                 case XCHK_DIRPATH_CORRUPT:
     123             :                 case XCHK_DIRPATH_LOOP:
     124             :                 case XCHK_DIRPATH_OK:
     125       54470 :                         if (!foundit) {
     126       54470 :                                 xrep_dirpath_retain_parent(dl, path);
     127       54471 :                                 foundit = true;
     128       54471 :                                 continue;
     129             :                         }
     130           0 :                         ASSERT(foundit == false);
     131             :                         break;
     132             :                 default:
     133             :                         break;
     134             :                 }
     135             :         }
     136             : 
     137       54471 :         ASSERT(oc->suspect + oc->good == 1);
     138       54471 : }
     139             : 
     140             : /* Delete all paths except for the one good one. */
     141             : STATIC void
     142           0 : xrep_dirtree_keep_one_good_path(
     143             :         struct xchk_dirtree             *dl,
     144             :         struct xchk_dirtree_outcomes    *oc)
     145             : {
     146           0 :         struct xchk_dirpath             *path;
     147           0 :         bool                            foundit = false;
     148             : 
     149           0 :         xchk_dirtree_for_each_path(dl, path) {
     150           0 :                 switch (path->outcome) {
     151           0 :                 case XCHK_DIRPATH_CORRUPT:
     152             :                 case XCHK_DIRPATH_LOOP:
     153           0 :                         oc->suspect--;
     154           0 :                         oc->bad++;
     155           0 :                         xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
     156             :                         break;
     157           0 :                 case XCHK_DIRPATH_OK:
     158           0 :                         if (!foundit) {
     159           0 :                                 xrep_dirpath_retain_parent(dl, path);
     160           0 :                                 foundit = true;
     161           0 :                                 continue;
     162             :                         }
     163           0 :                         oc->good--;
     164           0 :                         oc->bad++;
     165           0 :                         xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
     166             :                         break;
     167             :                 default:
     168             :                         break;
     169             :                 }
     170             :         }
     171             : 
     172           0 :         ASSERT(oc->suspect == 0);
     173           0 :         ASSERT(oc->good < 2);
     174           0 : }
     175             : 
     176             : /* Delete all paths except for one suspect one. */
     177             : STATIC void
     178           0 : xrep_dirtree_keep_one_suspect_path(
     179             :         struct xchk_dirtree             *dl,
     180             :         struct xchk_dirtree_outcomes    *oc)
     181             : {
     182           0 :         struct xchk_dirpath             *path;
     183           0 :         bool                            foundit = false;
     184             : 
     185           0 :         xchk_dirtree_for_each_path(dl, path) {
     186           0 :                 switch (path->outcome) {
     187           0 :                 case XCHK_DIRPATH_CORRUPT:
     188             :                 case XCHK_DIRPATH_LOOP:
     189           0 :                         if (!foundit) {
     190           0 :                                 xrep_dirpath_retain_parent(dl, path);
     191           0 :                                 foundit = true;
     192           0 :                                 continue;
     193             :                         }
     194           0 :                         oc->suspect--;
     195           0 :                         oc->bad++;
     196           0 :                         xrep_dirpath_set_outcome(dl, path, XCHK_DIRPATH_DELETE);
     197             :                         break;
     198           0 :                 case XCHK_DIRPATH_OK:
     199           0 :                         ASSERT(0);
     200           0 :                         break;
     201             :                 default:
     202             :                         break;
     203             :                 }
     204             :         }
     205             : 
     206           0 :         ASSERT(oc->suspect == 1);
     207           0 :         ASSERT(oc->good == 0);
     208           0 : }
     209             : 
     210             : /*
     211             :  * Figure out what to do with the paths we tried to find.  Returns -EDEADLOCK
     212             :  * if the scan results have become stale.
     213             :  */
     214             : STATIC void
     215       55876 : xrep_dirtree_decide_fate(
     216             :         struct xchk_dirtree             *dl,
     217             :         struct xchk_dirtree_outcomes    *oc)
     218             : {
     219       55876 :         xchk_dirtree_evaluate(dl, oc);
     220             : 
     221             :         /* Parentless directories should not have any paths at all. */
     222       55874 :         if (xchk_dirtree_parentless(dl)) {
     223        1405 :                 xrep_dirtree_delete_all_paths(dl, oc);
     224        1405 :                 return;
     225             :         }
     226             : 
     227             :         /* One path is exactly the number of paths we want. */
     228       54469 :         if (oc->good + oc->suspect == 1) {
     229       54469 :                 xrep_dirtree_find_surviving_path(dl, oc);
     230       54469 :                 return;
     231             :         }
     232             : 
     233             :         /* Zero paths means we should reattach the subdir to the orphanage. */
     234           0 :         if (oc->good + oc->suspect == 0) {
     235           0 :                 if (dl->sc->orphanage)
     236           0 :                         oc->needs_adoption = true;
     237           0 :                 return;
     238             :         }
     239             : 
     240             :         /*
     241             :          * Otherwise, this subdirectory has too many parents.  If there's at
     242             :          * least one good path, keep it and delete the others.
     243             :          */
     244           0 :         if (oc->good > 0) {
     245           0 :                 xrep_dirtree_keep_one_good_path(dl, oc);
     246           0 :                 return;
     247             :         }
     248             : 
     249             :         /*
     250             :          * There are no good paths and there are too many suspect paths.
     251             :          * Keep the first suspect path and delete the rest.
     252             :          */
     253           0 :         xrep_dirtree_keep_one_suspect_path(dl, oc);
     254             : }
     255             : 
     256             : /*
     257             :  * Load the first step of this path into @step and @dl->pptr
     258             :  * for later repair work.
     259             :  */
     260             : STATIC int
     261           0 : xrep_dirtree_prep_path(
     262             :         struct xchk_dirtree             *dl,
     263             :         struct xchk_dirpath             *path,
     264             :         struct xchk_dirpath_step        *step)
     265             : {
     266           0 :         int                             error;
     267             : 
     268           0 :         error = xfarray_load(dl->path_steps, path->first_step, step);
     269           0 :         if (error)
     270             :                 return error;
     271             : 
     272           0 :         dl->pptr.p_ino = step->parent_ino;
     273           0 :         dl->pptr.p_gen = step->parent_gen;
     274           0 :         dl->pptr.p_namelen = step->name_len;
     275             : 
     276           0 :         return xfblob_load(dl->path_names, step->name_cookie, dl->pptr.p_name,
     277             :                         step->name_len);
     278             : }
     279             : 
     280             : static inline int
     281           0 : xrep_dirtree_was_stale(
     282             :         struct xchk_dirtree     *dl)
     283             : {
     284           0 :         int                     error = 0;
     285             : 
     286           0 :         mutex_lock(&dl->lock);
     287           0 :         if (dl->stale)
     288           0 :                 error = -ESTALE;
     289           0 :         mutex_unlock(&dl->lock);
     290           0 :         return error;
     291             : }
     292             : 
     293             : /* Delete the VFS dentry for a removed child. */
     294             : STATIC int
     295           0 : xrep_dirtree_purge_dentry(
     296             :         struct xchk_dirtree     *dl,
     297             :         struct xfs_inode        *dp,
     298             :         const struct xfs_name   *name)
     299             : {
     300           0 :         struct qstr             qname = QSTR_INIT(name->name, name->len);
     301           0 :         struct dentry           *parent_dentry, *child_dentry;
     302           0 :         int                     error = 0;
     303             : 
     304             :         /*
     305             :          * Find the dentry for the parent directory.  If there isn't one, we're
     306             :          * done.  Caller already holds i_rwsem for parent and child.
     307             :          */
     308           0 :         parent_dentry = d_find_alias(VFS_I(dp));
     309           0 :         if (!parent_dentry)
     310             :                 return 0;
     311             : 
     312             :         /* The VFS thinks the parent is a directory, right? */
     313           0 :         if (!d_is_dir(parent_dentry)) {
     314           0 :                 ASSERT(d_is_dir(parent_dentry));
     315           0 :                 error = -EFSCORRUPTED;
     316           0 :                 goto out_dput_parent;
     317             :         }
     318             : 
     319             :         /*
     320             :          * Try to find the dirent pointing to the child.  If there isn't one,
     321             :          * we're done.
     322             :          */
     323           0 :         qname.hash = full_name_hash(parent_dentry, name->name, name->len);
     324           0 :         child_dentry = d_lookup(parent_dentry, &qname);
     325           0 :         if (!child_dentry) {
     326           0 :                 error = 0;
     327           0 :                 goto out_dput_parent;
     328             :         }
     329             : 
     330           0 :         trace_xrep_dirtree_delete_child(dp->i_mount, child_dentry);
     331             : 
     332             :         /* Child is not a directory?  We're screwed. */
     333           0 :         if (!d_is_dir(child_dentry)) {
     334           0 :                 ASSERT(d_is_dir(child_dentry));
     335           0 :                 error = -EFSCORRUPTED;
     336           0 :                 goto out_dput_child;
     337             :         }
     338             : 
     339             :         /* Replace the child dentry with a negative one. */
     340           0 :         d_delete(child_dentry);
     341             : 
     342           0 : out_dput_child:
     343           0 :         dput(child_dentry);
     344           0 : out_dput_parent:
     345           0 :         dput(parent_dentry);
     346           0 :         return error;
     347             : }
     348             : 
     349             : /*
     350             :  * Remove a link from the directory tree and update the dcache.  Returns
     351             :  * -ESTALE if the scan data are now out of date.
     352             :  */
     353             : STATIC int
     354           0 : xrep_dirtree_unlink(
     355             :         struct xchk_dirtree             *dl,
     356             :         struct xfs_inode                *dp,
     357             :         struct xchk_dirpath             *path,
     358             :         struct xchk_dirpath_step        *step)
     359             : {
     360           0 :         struct xfs_name                 name = {
     361           0 :                 .name                   = dl->pptr.p_name,
     362           0 :                 .len                    = step->name_len,
     363             :         };
     364           0 :         struct xfs_scrub                *sc = dl->sc;
     365           0 :         struct xfs_mount                *mp = sc->mp;
     366           0 :         struct xfs_parent_defer         *parent = NULL;
     367           0 :         xfs_ino_t                       dotdot_ino;
     368           0 :         xfs_ino_t                       parent_ino = dl->parent_ino;
     369           0 :         unsigned int                    resblks;
     370           0 :         int                             dontcare;
     371           0 :         int                             error = 0;
     372             : 
     373             :         /*
     374             :          * Try to take the IOLOCK on the parent before deleting the link.
     375             :          * We hold IOLOCK_EXCL on @sc->ip.
     376             :          */
     377           0 :         while (!xfs_ilock_nowait(dp, XFS_IOLOCK_EXCL)) {
     378           0 :                 xchk_iunlock(sc, XFS_IOLOCK_EXCL);
     379             : 
     380           0 :                 delay(1);
     381           0 :                 if (xchk_should_terminate(sc, &error))
     382           0 :                         return error;
     383             : 
     384           0 :                 xchk_ilock(sc, XFS_IOLOCK_EXCL);
     385           0 :                 error = xrep_dirtree_was_stale(dl);
     386           0 :                 if (error)
     387           0 :                         return error;
     388             :         }
     389             : 
     390             :         /* Set up parent pointer operation. */
     391           0 :         error = xfs_parent_start(mp, &parent);
     392           0 :         if (error)
     393           0 :                 goto out_iolock;
     394             : 
     395             :         /*
     396             :          * Create the transaction that we need to sever the path.  Ignore
     397             :          * EDQUOT and ENOSPC being returned via nospace_error because the
     398             :          * directory code can handle a reservationless update.
     399             :          */
     400           0 :         resblks = xfs_remove_space_res(mp, step->name_len);
     401           0 :         error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, sc->ip,
     402             :                         &resblks, &sc->tp, &dontcare);
     403           0 :         if (error)
     404           0 :                 goto out_parent;
     405             : 
     406             :         /* Cancel if someone invalidate the paths while we were unlocked */
     407           0 :         mutex_lock(&dl->lock);
     408           0 :         if (dl->stale) {
     409           0 :                 mutex_unlock(&dl->lock);
     410           0 :                 error = -ESTALE;
     411           0 :                 goto out_trans_cancel;
     412             :         }
     413           0 :         xrep_dirpath_set_outcome(dl, path, XREP_DIRPATH_DELETING);
     414           0 :         mutex_unlock(&dl->lock);
     415             : 
     416           0 :         trace_xrep_dirtree_delete_path(dl->sc, sc->ip, path->path_nr,
     417           0 :                         &dl->pptr);
     418             : 
     419             :         /*
     420             :          * Decide if we need to reset the dotdot entry.  Rules:
     421             :          *
     422             :          * - If there's a surviving parent, we want dotdot to point there.
     423             :          * - If we don't have any surviving parents, then point dotdot at the
     424             :          *   root dir.
     425             :          * - If dotdot is already set to the value we want, pass in NULLFSINO
     426             :          *   for no change necessary.
     427             :          *
     428             :          * Do this /before/ we dirty anything, in case the dotdot lookup
     429             :          * fails.
     430             :          */
     431           0 :         error = xchk_dir_lookup(sc, sc->ip, &xfs_name_dotdot, &dotdot_ino);
     432           0 :         if (error)
     433           0 :                 goto out_trans_cancel;
     434           0 :         if (parent_ino == NULLFSINO)
     435           0 :                 parent_ino = dl->root_ino;
     436           0 :         if (dotdot_ino == parent_ino)
     437           0 :                 parent_ino = NULLFSINO;
     438             : 
     439             :         /* Drop the link from sc->ip's dotdot entry.  */
     440           0 :         error = xfs_droplink(sc->tp, dp);
     441           0 :         if (error)
     442             :                 return error;
     443             : 
     444             :         /* Reset the dotdot entry to a surviving parent. */
     445           0 :         if (parent_ino != NULLFSINO) {
     446           0 :                 error = xfs_dir_replace(sc->tp, sc->ip, &xfs_name_dotdot,
     447             :                                 parent_ino, 0);
     448           0 :                 if (error)
     449             :                         return error;
     450             :         }
     451             : 
     452             :         /* Drop the link from dp to sc->ip. */
     453           0 :         error = xfs_droplink(sc->tp, sc->ip);
     454           0 :         if (error)
     455             :                 return error;
     456             : 
     457           0 :         error = xfs_dir_removename(sc->tp, dp, &name, sc->ip->i_ino, resblks);
     458           0 :         if (error) {
     459           0 :                 ASSERT(error != -ENOENT);
     460           0 :                 return error;
     461             :         }
     462             : 
     463           0 :         if (parent) {
     464           0 :                 error = xfs_parent_remove(sc->tp, parent, dp, &name, sc->ip);
     465           0 :                 if (error)
     466             :                         return error;
     467             :         }
     468             : 
     469             :         /*
     470             :          * Notify dirent hooks that we removed the bad link, invalidate the
     471             :          * dcache, and commit the repair.
     472             :          */
     473           0 :         xfs_dir_update_hook(dp, sc->ip, -1, &name);
     474           0 :         error = xrep_dirtree_purge_dentry(dl, dp, &name);
     475           0 :         if (error)
     476           0 :                 goto out_trans_cancel;
     477             : 
     478           0 :         error = xrep_trans_commit(sc);
     479           0 :         goto out_ilock;
     480             : 
     481           0 : out_trans_cancel:
     482           0 :         xchk_trans_cancel(sc);
     483           0 : out_ilock:
     484           0 :         xfs_iunlock(sc->ip, XFS_ILOCK_EXCL);
     485           0 :         xfs_iunlock(dp, XFS_ILOCK_EXCL);
     486           0 : out_parent:
     487           0 :         xfs_parent_finish(mp, parent);
     488           0 : out_iolock:
     489           0 :         xfs_iunlock(dp, XFS_IOLOCK_EXCL);
     490           0 :         return error;
     491             : }
     492             : 
     493             : /*
     494             :  * Delete a directory entry that points to this directory.  Returns -ESTALE
     495             :  * if the scan data are now out of date.
     496             :  */
     497             : STATIC int
     498           0 : xrep_dirtree_delete_path(
     499             :         struct xchk_dirtree             *dl,
     500             :         struct xchk_dirpath             *path)
     501             : {
     502           0 :         struct xchk_dirpath_step        step;
     503           0 :         struct xfs_scrub                *sc = dl->sc;
     504           0 :         struct xfs_inode                *dp;
     505           0 :         int                             error;
     506             : 
     507             :         /*
     508             :          * Load the parent pointer and directory inode for this path, then
     509             :          * drop the scan lock, the ILOCK, and the transaction so that
     510             :          * _delete_path can reserve the proper transaction.
     511             :          */
     512           0 :         error = xrep_dirtree_prep_path(dl, path, &step);
     513           0 :         if (error)
     514             :                 return error;
     515             : 
     516           0 :         error = xchk_iget(sc, step.parent_ino, &dp);
     517           0 :         if (error)
     518             :                 return error;
     519             : 
     520           0 :         mutex_unlock(&dl->lock);
     521           0 :         xchk_trans_cancel(sc);
     522           0 :         xchk_iunlock(sc, XFS_ILOCK_EXCL);
     523             : 
     524           0 :         error = xrep_dirtree_unlink(dl, dp, path, &step);
     525             : 
     526             :         /* Retake the resources we had at the start of this function. */
     527           0 :         xchk_irele(sc, dp);
     528           0 :         xchk_trans_alloc_empty(sc);
     529           0 :         xchk_ilock(sc, XFS_ILOCK_EXCL);
     530           0 :         mutex_lock(&dl->lock);
     531           0 :         if (!error && dl->stale)
     532           0 :                 return -ESTALE;
     533             :         return error;
     534             : }
     535             : 
     536             : /* Add a new path to represent our in-progress adoption. */
     537             : STATIC int
     538           0 : xrep_dirtree_create_adoption_path(
     539             :         struct xchk_dirtree             *dl)
     540             : {
     541           0 :         struct xfs_scrub                *sc = dl->sc;
     542           0 :         struct xchk_dirpath             *path;
     543           0 :         int                             error;
     544             : 
     545             :         /*
     546             :          * We should have capped the number of paths at XFS_MAXLINK-1 in the
     547             :          * scanner.
     548             :          */
     549           0 :         if (dl->nr_paths > XFS_MAXLINK) {
     550           0 :                 ASSERT(dl->nr_paths <= XFS_MAXLINK);
     551           0 :                 return -EFSCORRUPTED;
     552             :         }
     553             : 
     554             :         /*
     555             :          * Create a new xchk_path structure to remember this parent pointer
     556             :          * and record the first name step.
     557             :          */
     558           0 :         path = kmalloc(sizeof(struct xchk_dirpath), XCHK_GFP_FLAGS);
     559           0 :         if (!path)
     560             :                 return -ENOMEM;
     561             : 
     562           0 :         INIT_LIST_HEAD(&path->list);
     563           0 :         xino_bitmap_init(&path->seen_inodes);
     564           0 :         path->nr_steps = 0;
     565           0 :         path->outcome = XREP_DIRPATH_ADOPTING;
     566             : 
     567             :         /*
     568             :          * Record the new link that we just created in the orphanage.  Because
     569             :          * adoption is the last repair that we perform, we don't bother filling
     570             :          * in the path all the way back to the root.
     571             :          */
     572           0 :         dl->pptr.p_ino = sc->orphanage->i_ino;
     573           0 :         dl->pptr.p_gen = VFS_I(sc->orphanage)->i_generation;
     574           0 :         dl->pptr.p_namelen = dl->adoption.xname.len;
     575             : 
     576           0 :         error = xino_bitmap_set(&path->seen_inodes, sc->orphanage->i_ino);
     577           0 :         if (error)
     578           0 :                 goto out_path;
     579             : 
     580           0 :         trace_xrep_dirtree_create_adoption(sc, sc->ip, dl->nr_paths, &dl->pptr);
     581             : 
     582           0 :         error = xchk_dirpath_append(dl, sc->ip, path, &dl->pptr);
     583           0 :         if (error)
     584           0 :                 goto out_path;
     585             : 
     586           0 :         path->first_step = xfarray_length(dl->path_steps) - 1;
     587           0 :         path->second_step = XFARRAY_NULLIDX;
     588           0 :         path->path_nr = dl->nr_paths;
     589             : 
     590           0 :         list_add_tail(&path->list, &dl->path_list);
     591           0 :         dl->nr_paths++;
     592           0 :         return 0;
     593             : 
     594           0 : out_path:
     595           0 :         kfree(path);
     596           0 :         return error;
     597             : }
     598             : 
     599             : /*
     600             :  * Reattach this orphaned directory to the orphanage.  Do not call this with
     601             :  * any resources held.  Returns -ESTALE if the scan data have become out of
     602             :  * date.
     603             :  */
     604             : STATIC int
     605           0 : xrep_dirtree_adopt(
     606             :         struct xchk_dirtree             *dl)
     607             : {
     608           0 :         struct xfs_scrub                *sc = dl->sc;
     609           0 :         struct xfs_mount                *mp = sc->mp;
     610           0 :         int                             error;
     611             : 
     612           0 :         error = xrep_adoption_init(sc, &dl->adoption);
     613           0 :         if (error)
     614             :                 return error;
     615             : 
     616             :         /*
     617             :          * Try to take the IOLOCK of the the orphanage.  In theory, @sc->ip
     618             :          * isn't linked anywhere, so there should not be another thread holding
     619             :          * the orphanage's IOLOCK while trying to get @sc->ip's IOLOCK.  But
     620             :          * we'll be careful to check for stale scans.
     621             :          */
     622           0 :         while (!xrep_orphanage_ilock_nowait(sc, XFS_IOLOCK_EXCL)) {
     623           0 :                 if (xchk_should_terminate(sc, &error))
     624           0 :                         goto out_adoption;
     625           0 :                 error = xrep_dirtree_was_stale(dl);
     626           0 :                 if (error)
     627           0 :                         goto out_adoption;
     628             : 
     629           0 :                 delay(1);
     630             :         }
     631             : 
     632             :         /*
     633             :          * Allocate transaction, reserve disk space, and take the ILOCKs.
     634             :          * Check for stale scan data before we try the lengthly adoption name
     635             :          * computation.
     636             :          */
     637           0 :         error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, 0, 0, 0, &sc->tp);
     638           0 :         if (error)
     639           0 :                 goto out_iolock;
     640           0 :         error = xrep_adoption_prep(&dl->adoption);
     641           0 :         if (error)
     642           0 :                 goto out_ilock;
     643             : 
     644             :         /*
     645             :          * The directory tree fixer runs after the link counts have been
     646             :          * corrected.  Therefore, we must bump the child's link count since
     647             :          * there will be no further opportunity to fix errors.
     648             :          */
     649           0 :         dl->adoption.bump_child_nlink = true;
     650           0 : 
     651           0 :         /*
     652             :          * Abort the adoption if the scan data is out of date.  @sc->ip
     653             :          * might have picked up another path to the root directory while it was
     654           0 :          * unlocked.
     655           0 :          */
     656           0 :         error = xrep_dirtree_was_stale(dl);
     657             :         if (error)
     658             :                 goto out_ilock;
     659             : 
     660             :         /* Figure out what name we're going to use here. */
     661             :         error = xrep_adoption_compute_name(&dl->adoption, dl->pptr.p_name);
     662           0 :         if (error)
     663           0 :                 goto out_ilock;
     664           0 : 
     665           0 :         /*
     666           0 :          * Now that we have a proposed name for the orphanage entry, create
     667             :          * a faux path so that the live update hook will see it.
     668           0 :          */
     669           0 :         mutex_lock(&dl->lock);
     670           0 :         if (dl->stale) {
     671           0 :                 mutex_unlock(&dl->lock);
     672             :                 error = -ESTALE;
     673             :                 goto out_ilock;
     674             :         }
     675             :         error = xrep_dirtree_create_adoption_path(dl);
     676             :         mutex_unlock(&dl->lock);
     677           0 :         if (error)
     678           0 :                 goto out_ilock;
     679           0 : 
     680             :         /*
     681           0 :          * Create the new name in the orphanage and commit the transaction.
     682             :          * After this point the adoption structure is dead no matter what.
     683           0 :          */
     684           0 :         error = xrep_adoption_commit(&dl->adoption);
     685           0 :         if (error)
     686           0 :                 xchk_trans_cancel(sc);
     687             :         else
     688           0 :                 error = xrep_trans_commit(sc);
     689           0 : 
     690           0 :         xchk_iunlock(sc, XFS_ILOCK_EXCL);
     691           0 :         xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);
     692           0 :         xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
     693           0 :         return error;
     694           0 : 
     695           0 : out_ilock:
     696           0 :         if (sc->ilock_flags & XFS_ILOCK_EXCL)
     697           0 :                 xchk_iunlock(sc, XFS_ILOCK_EXCL);
     698           0 :         if (sc->orphanage_ilock_flags & XFS_ILOCK_EXCL)
     699             :                 xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);
     700             :         xchk_trans_cancel(sc);
     701             : out_iolock:
     702             :         xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
     703             : out_adoption:
     704             :         xrep_adoption_cancel(&dl->adoption, error);
     705             :         return error;
     706           0 : }
     707             : 
     708             : /*
     709           0 :  * This newly orphaned directory needs to be adopted by the orphanage.
     710           0 :  * Make this happen.
     711             :  */
     712             : STATIC int
     713             : xrep_dirtree_move_to_orphanage(
     714             :         struct xchk_dirtree             *dl)
     715             : {
     716           0 :         struct xfs_scrub                *sc = dl->sc;
     717           0 :         int                             error;
     718           0 : 
     719             :         /*
     720             :          * Start by dropping all the resources that we hold so that we can grab
     721           0 :          * all the resources that we need for the adoption.
     722             :          */
     723             :         mutex_unlock(&dl->lock);
     724           0 :         xchk_trans_cancel(sc);
     725           0 :         xchk_iunlock(sc, XFS_ILOCK_EXCL);
     726           0 : 
     727           0 :         /* Perform the adoption */
     728           0 :         error = xrep_dirtree_adopt(dl);
     729             : 
     730             :         /* Retake all the resources we had at the beginning. */
     731             :         xchk_trans_alloc_empty(sc);
     732             :         xchk_ilock(sc, XFS_ILOCK_EXCL);
     733             :         mutex_lock(&dl->lock);
     734             :         if (!error && dl->stale)
     735             :                 return -ESTALE;
     736             :         return error;
     737       55875 : }
     738             : 
     739             : /*
     740             :  * Try to fix all the problems.  Returns -ESTALE if the scan data have become
     741       55875 :  * out of date.
     742       55875 :  */
     743             : STATIC int
     744             : xrep_dirtree_fix_problems(
     745      110343 :         struct xchk_dirtree             *dl,
     746       54470 :         struct xchk_dirtree_outcomes    *oc)
     747       54470 : {
     748             :         struct xchk_dirpath             *path;
     749           0 :         int                             error;
     750           0 : 
     751           0 :         /* Delete all the paths we don't want. */
     752             :         xchk_dirtree_for_each_path(dl, path) {
     753             :                 if (path->outcome != XCHK_DIRPATH_DELETE)
     754             :                         continue;
     755       55873 : 
     756           0 :                 error = xrep_dirtree_delete_path(dl, path);
     757             :                 if (error)
     758             :                         return error;
     759             :         }
     760             : 
     761             :         /* Reparent this directory to the orphanage. */
     762             :         if (oc->needs_adoption) {
     763       55875 :                 if (xrep_orphanage_can_adopt(dl->sc))
     764             :                         return xrep_dirtree_move_to_orphanage(dl);
     765             :                 return -EFSCORRUPTED;
     766       55875 :         }
     767       55875 : 
     768       55875 :         return 0;
     769             : }
     770             : 
     771             : /* Fix directory loops involving this directory. */
     772             : int
     773             : xrep_dirtree(
     774             :         struct xfs_scrub                *sc)
     775       55875 : {
     776       55876 :         struct xchk_dirtree             *dl = sc->buf;
     777             :         struct xchk_dirtree_outcomes    oc;
     778             :         int                             error;
     779             : 
     780             :         /*
     781             :          * Prepare to fix the directory tree by retaking the scan lock.  The
     782       55876 :          * order of resource acquisition is still IOLOCK -> transaction ->
     783       55876 :          * ILOCK -> scan lock.
     784             :          */
     785       55876 :         mutex_lock(&dl->lock);
     786             :         do {
     787       55875 :                 /*
     788       55873 :                  * Decide what we're going to do, then do it.  An -ESTALE
     789             :                  * return here means the scan results are invalid and we have
     790             :                  * to walk again.
     791           0 :                  */
     792           0 :                 if (!dl->stale) {
     793             :                         xrep_dirtree_decide_fate(dl, &oc);
     794           0 : 
     795       55875 :                         trace_xrep_dirtree_decided_fate(dl, &oc);
     796             : 
     797       55873 :                         error = xrep_dirtree_fix_problems(dl, &oc);
     798             :                         if (!error || error != -ESTALE)
     799             :                                 break;
     800             :                 }
     801             :                 error = xchk_dirtree_find_paths_to_root(dl);
     802             :                 if (error == -ELNRNG || error == -ENOSR)
     803             :                         error = -EFSCORRUPTED;
     804             :         } while (!error);
     805             :         mutex_unlock(&dl->lock);
     806             : 
     807             :         return error;
     808             : }

Generated by: LCOV version 1.14