LCOV - code coverage report
Current view: top level - fs/xfs/scrub - nlinks_repair.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-acha @ Mon Jul 31 20:08:06 PDT 2023 Lines: 83 137 60.6 %
Date: 2023-07-31 20:08:07 Functions: 3 5 60.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 2021-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_bmap_util.h"
      17             : #include "xfs_iwalk.h"
      18             : #include "xfs_ialloc.h"
      19             : #include "xfs_sb.h"
      20             : #include "xfs_ag.h"
      21             : #include "xfs_dir2.h"
      22             : #include "xfs_parent.h"
      23             : #include "scrub/scrub.h"
      24             : #include "scrub/common.h"
      25             : #include "scrub/repair.h"
      26             : #include "scrub/xfile.h"
      27             : #include "scrub/xfarray.h"
      28             : #include "scrub/iscan.h"
      29             : #include "scrub/orphanage.h"
      30             : #include "scrub/nlinks.h"
      31             : #include "scrub/trace.h"
      32             : #include "scrub/tempfile.h"
      33             : 
      34             : /*
      35             :  * Live Inode Link Count Repair
      36             :  * ============================
      37             :  *
      38             :  * Use the live inode link count information that we collected to replace the
      39             :  * nlink values of the incore inodes.  A scrub->repair cycle should have left
      40             :  * the live data and hooks active, so this is safe so long as we make sure the
      41             :  * inode is locked.
      42             :  */
      43             : 
      44             : /* Set up to repair inode link counts. */
      45             : int
      46        2007 : xrep_setup_nlinks(
      47             :         struct xfs_scrub        *sc)
      48             : {
      49        2007 :         return xrep_orphanage_try_create(sc);
      50             : }
      51             : 
      52             : /*
      53             :  * Inodes that aren't the root directory or the orphanage, have a nonzero link
      54             :  * count, and no observed parents should be moved to the orphanage.
      55             :  */
      56             : static inline bool
      57             : xrep_nlinks_is_orphaned(
      58             :         struct xfs_scrub        *sc,
      59             :         struct xfs_inode        *ip,
      60             :         unsigned int            actual_nlink,
      61             :         const struct xchk_nlink *obs)
      62             : {
      63    91360506 :         struct xfs_mount        *mp = ip->i_mount;
      64             : 
      65    91360506 :         if (obs->parents != 0)
      66             :                 return false;
      67          32 :         if (ip == mp->m_rootip || ip == sc->orphanage)
      68             :                 return false;
      69          32 :         return actual_nlink != 0;
      70             : }
      71             : 
      72             : /*
      73             :  * Reattach this file to the directory tree by moving it to /lost+found per the
      74             :  * adoption parameters that we already computed.  Returns 0 for success,
      75             :  * -EMLINK if we cannot complete the adoption because doing so would cause a
      76             :  * link count overflow, or the usual negative errno.
      77             :  */
      78             : STATIC int
      79           0 : xrep_nlinks_adopt(
      80             :         struct xchk_nlink_ctrs  *xnc)
      81             : {
      82           0 :         int                     error;
      83             : 
      84             :         /* Figure out what name we're going to use here. */
      85           0 :         error = xrep_adoption_compute_name(&xnc->adoption, xnc->namebuf);
      86           0 :         if (error)
      87             :                 return error;
      88             : 
      89             :         /*
      90             :          * Create the new name in the orphanage, and bump the link
      91             :          * count of the orphanage if we just added a directory.  Then
      92             :          * we can set the correct nlink.
      93             :          */
      94           0 :         return xrep_adoption_commit(&xnc->adoption);
      95             : }
      96             : 
      97             : /* Remove an inode from the unlinked list. */
      98             : STATIC int
      99           0 : xrep_nlinks_iunlink_remove(
     100             :         struct xfs_scrub        *sc)
     101             : {
     102           0 :         struct xfs_perag        *pag;
     103           0 :         int                     error;
     104             : 
     105           0 :         pag = xfs_perag_get(sc->mp, XFS_INO_TO_AGNO(sc->mp, sc->ip->i_ino));
     106           0 :         error = xfs_iunlink_remove(sc->tp, pag, sc->ip);
     107           0 :         xfs_perag_put(pag);
     108           0 :         return error;
     109             : }
     110             : 
     111             : /*
     112             :  * Correct the link count of the given inode.  Because we have to grab locks
     113             :  * and resources in a certain order, it's possible that this will be a no-op.
     114             :  */
     115             : STATIC int
     116    91362510 : xrep_nlinks_repair_inode(
     117             :         struct xchk_nlink_ctrs  *xnc)
     118             : {
     119    91362510 :         struct xchk_nlink       obs;
     120    91362510 :         struct xfs_scrub        *sc = xnc->sc;
     121    91362510 :         struct xfs_mount        *mp = sc->mp;
     122    91362510 :         struct xfs_inode        *ip = sc->ip;
     123    91362510 :         uint64_t                total_links;
     124    91362510 :         uint64_t                actual_nlink;
     125    91362510 :         bool                    orphanage_available = false;
     126    91362510 :         bool                    adoption_performed = false;
     127    91362510 :         bool                    dirty = false;
     128    91362510 :         int                     error;
     129             : 
     130             :         /*
     131             :          * Ignore temporary files being used to stage repairs, since we assume
     132             :          * they're correct for non-directories, and the directory repair code
     133             :          * doesn't bump the link counts for the children.
     134             :          */
     135    91362510 :         if (xrep_is_tempfile(ip))
     136             :                 return 0;
     137             : 
     138    91362510 :         if (sc->orphanage && sc->ip != sc->orphanage) {
     139             :                 /*
     140             :                  * Allocate a transaction for the adoption.  We'll reserve
     141             :                  * space for the transaction in the adoption preparation step.
     142             :                  */
     143    91360506 :                 error = xrep_adoption_init(sc, &xnc->adoption);
     144    91360506 :                 if (!error) {
     145    91360506 :                         orphanage_available = true;
     146             : 
     147             :                         /* Take IOLOCK of the orphanage and the child. */
     148    91360506 :                         error = xrep_orphanage_iolock_two(sc);
     149    91360506 :                         if (error)
     150             :                                 return error;
     151             :                 }
     152             :         }
     153             :         if (!orphanage_available)
     154        2004 :                 xchk_ilock(sc, XFS_IOLOCK_EXCL);
     155             : 
     156    91362510 :         error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, 0, 0, 0, &sc->tp);
     157    91362510 :         if (error)
     158           0 :                 goto out_iolock;
     159             : 
     160    91362510 :         if (orphanage_available) {
     161    91360506 :                 error = xrep_adoption_prep(&xnc->adoption);
     162    91360506 :                 if (error) {
     163           0 :                         xchk_trans_cancel(sc);
     164           0 :                         goto out_iolock;
     165             :                 }
     166             :         } else {
     167        2004 :                 xchk_ilock(sc, XFS_ILOCK_EXCL);
     168        2004 :                 xfs_trans_ijoin(sc->tp, ip, 0);
     169             :         }
     170             : 
     171    91362510 :         mutex_lock(&xnc->lock);
     172             : 
     173    91362510 :         if (xchk_iscan_aborted(&xnc->collect_iscan)) {
     174           0 :                 error = -ECANCELED;
     175           0 :                 goto out_scanlock;
     176             :         }
     177             : 
     178    91362510 :         error = xfarray_load_sparse(xnc->nlinks, ip->i_ino, &obs);
     179    91362510 :         if (error)
     180           0 :                 goto out_scanlock;
     181             : 
     182             :         /*
     183             :          * We're done accessing the shared scan data, so we can drop the lock.
     184             :          * We still hold @ip's ILOCK, so its link count cannot change.
     185             :          */
     186    91362510 :         mutex_unlock(&xnc->lock);
     187             : 
     188    91362510 :         total_links = xchk_nlink_total(ip, &obs);
     189    91362510 :         actual_nlink = VFS_I(ip)->i_nlink;
     190             : 
     191             :         /*
     192             :          * Non-directories cannot have directories pointing up to them.
     193             :          *
     194             :          * We previously set error to zero, but set it again because one static
     195             :          * checker author fears that programmers will fail to maintain this
     196             :          * invariant and built their tool to flag this as a security risk.  A
     197             :          * different tool author made their bot complain about the redundant
     198             :          * store.  This is a never-ending and stupid battle; both tools missed
     199             :          * *actual bugs* elsewhere; and I no longer care.
     200             :          */
     201    91362510 :         if (!S_ISDIR(VFS_I(ip)->i_mode) && obs.children != 0) {
     202           0 :                 trace_xrep_nlinks_unfixable_inode(mp, ip, &obs);
     203           0 :                 error = 0;
     204           0 :                 goto out_trans;
     205             :         }
     206             : 
     207             :         /*
     208             :          * Decide if we're going to move this file to the orphanage, and fix
     209             :          * up the incore link counts if we are.
     210             :          */
     211    91362542 :         if (orphanage_available &&
     212             :             xrep_nlinks_is_orphaned(sc, ip, actual_nlink, &obs)) {
     213           0 :                 error = xrep_nlinks_adopt(xnc);
     214           0 :                 if (error)
     215           0 :                         goto out_trans;
     216           0 :                 adoption_performed = true;
     217             : 
     218             :                 /* Re-read the link counts. */
     219           0 :                 mutex_lock(&xnc->lock);
     220           0 :                 error = xfarray_load_sparse(xnc->nlinks, ip->i_ino, &obs);
     221           0 :                 mutex_unlock(&xnc->lock);
     222           0 :                 if (error)
     223           0 :                         goto out_trans;
     224             : 
     225           0 :                 total_links = xchk_nlink_total(ip, &obs);
     226           0 :                 actual_nlink = VFS_I(ip)->i_nlink;
     227           0 :                 dirty = true;
     228             :         }
     229             : 
     230             :         /*
     231             :          * If this inode is linked from the directory tree and on the unlinked
     232             :          * list, remove it from the unlinked list.
     233             :          */
     234    91362510 :         if (total_links > 0 && xfs_inode_on_unlinked_list(ip)) {
     235           0 :                 error = xrep_nlinks_iunlink_remove(sc);
     236           0 :                 if (error)
     237           0 :                         goto out_trans;
     238             :                 dirty = true;
     239             :         }
     240             : 
     241             :         /*
     242             :          * If this inode is not linked from the directory tree yet not on the
     243             :          * unlinked list, put it on the unlinked list.
     244             :          */
     245    91362510 :         if (total_links == 0 && !xfs_inode_on_unlinked_list(ip)) {
     246           0 :                 error = xfs_iunlink(sc->tp, ip);
     247           0 :                 if (error)
     248           0 :                         goto out_trans;
     249             :                 dirty = true;
     250             :         }
     251             : 
     252             :         /* Commit the new link count if it changed. */
     253    91362510 :         if (total_links != actual_nlink) {
     254           0 :                 bool    overflow = xrep_set_nlink(ip, total_links);
     255             : 
     256           0 :                 if (overflow)
     257           0 :                         trace_xrep_nlinks_unfixable_inode(mp, ip, &obs);
     258             :                 else
     259           0 :                         trace_xrep_nlinks_update_inode(mp, ip, &obs);
     260             :                 dirty = true;
     261             :         }
     262             : 
     263    91362510 :         if (!dirty) {
     264    91362510 :                 error = 0;
     265    91362510 :                 goto out_trans;
     266             :         }
     267             : 
     268           0 :         xfs_trans_log_inode(sc->tp, ip, XFS_ILOG_CORE);
     269             : 
     270           0 :         error = xrep_trans_commit(sc);
     271           0 :         if (error)
     272           0 :                 goto out_ilock;
     273             : 
     274           0 :         xchk_iunlock(sc, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
     275           0 :         if (orphanage_available) {
     276           0 :                 xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
     277           0 :                 if (!adoption_performed)
     278           0 :                         xrep_adoption_cancel(&xnc->adoption, 0);
     279             :         }
     280             :         return 0;
     281             : 
     282           0 : out_scanlock:
     283           0 :         mutex_unlock(&xnc->lock);
     284    91362510 : out_trans:
     285    91362510 :         xchk_trans_cancel(sc);
     286    91362510 : out_ilock:
     287    91362510 :         xchk_iunlock(sc, XFS_ILOCK_EXCL);
     288    91362510 :         if (orphanage_available && (sc->orphanage_ilock_flags & XFS_ILOCK_EXCL))
     289    91360506 :                 xrep_orphanage_iunlock(sc, XFS_ILOCK_EXCL);
     290        2004 : out_iolock:
     291    91362510 :         xchk_iunlock(sc, XFS_IOLOCK_EXCL);
     292    91362510 :         if (orphanage_available) {
     293    91360506 :                 xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
     294    91360506 :                 if (!adoption_performed)
     295    91360506 :                         xrep_adoption_cancel(&xnc->adoption, error);
     296             :         }
     297             :         return error;
     298             : }
     299             : 
     300             : /*
     301             :  * Try to visit every inode in the filesystem for repairs.  Move on if we can't
     302             :  * grab an inode, since we're still making forward progress.
     303             :  */
     304             : static int
     305             : xrep_nlinks_iter(
     306             :         struct xchk_nlink_ctrs  *xnc,
     307             :         struct xfs_inode        **ipp)
     308             : {
     309    91364514 :         int                     error;
     310             : 
     311    91364514 :         do {
     312    91364514 :                 error = xchk_iscan_iter(&xnc->compare_iscan, ipp);
     313    91364514 :         } while (error == -EBUSY);
     314             : 
     315    91364514 :         return error;
     316             : }
     317             : 
     318             : /* Commit the new inode link counters. */
     319             : int
     320        2004 : xrep_nlinks(
     321             :         struct xfs_scrub        *sc)
     322             : {
     323        2004 :         struct xchk_nlink_ctrs  *xnc = sc->buf;
     324        2004 :         int                     error;
     325             : 
     326             :         /*
     327             :          * We need ftype for an accurate count of the number of child
     328             :          * subdirectory links.  Child subdirectories with a back link (dotdot
     329             :          * entry) but no forward link are moved to the orphanage, so we cannot
     330             :          * repair the link count of the parent directory based on the back link
     331             :          * count alone.  Filesystems without ftype support are rare (old V4) so
     332             :          * we just skip out here.
     333             :          */
     334        2004 :         if (!xfs_has_ftype(sc->mp))
     335             :                 return -EOPNOTSUPP;
     336             : 
     337             :         /*
     338             :          * Use the inobt to walk all allocated inodes to compare and fix the
     339             :          * link counts.  Retry iget every tenth of a second for up to 30
     340             :          * seconds -- even if repair misses a few inodes, we still try to fix
     341             :          * as many of them as we can.
     342             :          */
     343        2004 :         xchk_iscan_start(sc, 30000, 100, &xnc->compare_iscan);
     344        2004 :         ASSERT(sc->ip == NULL);
     345             : 
     346   182729028 :         while ((error = xrep_nlinks_iter(xnc, &sc->ip)) == 1) {
     347             :                 /*
     348             :                  * Commit the scrub transaction so that we can create repair
     349             :                  * transactions with the correct reservations.
     350             :                  */
     351    91362510 :                 xchk_trans_cancel(sc);
     352             : 
     353    91362510 :                 error = xrep_nlinks_repair_inode(xnc);
     354    91362510 :                 xchk_iscan_mark_visited(&xnc->compare_iscan, sc->ip);
     355    91362510 :                 xchk_irele(sc, sc->ip);
     356    91362510 :                 sc->ip = NULL;
     357    91362510 :                 if (error)
     358             :                         break;
     359             : 
     360    91362510 :                 if (xchk_should_terminate(sc, &error))
     361             :                         break;
     362             : 
     363             :                 /*
     364             :                  * Create a new empty transaction so that we can advance the
     365             :                  * iscan cursor without deadlocking if the inobt has a cycle.
     366             :                  * We can only push the inactivation workqueues with an empty
     367             :                  * transaction.
     368             :                  */
     369    91362510 :                 error = xchk_trans_alloc_empty(sc);
     370    91362510 :                 if (error)
     371             :                         break;
     372             :         }
     373        2004 :         xchk_iscan_iter_finish(&xnc->compare_iscan);
     374        2004 :         xchk_iscan_teardown(&xnc->compare_iscan);
     375             : 
     376        2004 :         return error;
     377             : }

Generated by: LCOV version 1.14