LCOV - code coverage report
Current view: top level - fs/xfs/scrub - orphanage.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 142 249 57.0 %
Date: 2023-07-31 20:08:27 Functions: 11 15 73.3 %

          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_ialloc.h"
      16             : #include "xfs_quota.h"
      17             : #include "xfs_trans_space.h"
      18             : #include "xfs_dir2.h"
      19             : #include "xfs_icache.h"
      20             : #include "xfs_bmap.h"
      21             : #include "xfs_bmap_btree.h"
      22             : #include "xfs_parent.h"
      23             : #include "xfs_da_format.h"
      24             : #include "xfs_da_btree.h"
      25             : #include "xfs_xattr.h"
      26             : #include "xfs_attr_sf.h"
      27             : #include "scrub/scrub.h"
      28             : #include "scrub/common.h"
      29             : #include "scrub/repair.h"
      30             : #include "scrub/trace.h"
      31             : #include "scrub/orphanage.h"
      32             : #include "scrub/readdir.h"
      33             : 
      34             : #include <linux/namei.h>
      35             : 
      36             : /* Make the orphanage owned by root. */
      37      363945 : STATIC int
      38             : xrep_chown_orphanage(
      39             :         struct xfs_scrub        *sc,
      40             :         struct xfs_inode        *dp)
      41      363945 : {
      42      363945 :         struct xfs_trans        *tp;
      43      363945 :         struct xfs_mount        *mp = sc->mp;
      44      363945 :         struct xfs_dquot        *udqp = NULL, *gdqp = NULL, *pdqp = NULL;
      45      363945 :         struct xfs_dquot        *oldu = NULL, *oldg = NULL, *oldp = NULL;
      46      363945 :         struct inode            *inode = VFS_I(dp);
      47             :         int                     error;
      48      363945 : 
      49             :         error = xfs_qm_vop_dqalloc(dp, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 0,
      50      363945 :                         XFS_QMOPT_QUOTALL, &udqp, &gdqp, &pdqp);
      51             :         if (error)
      52             :                 return error;
      53      363945 : 
      54      363945 :         error = xfs_trans_alloc_ichange(dp, udqp, gdqp, pdqp, true, &tp);
      55           0 :         if (error)
      56             :                 goto out_dqrele;
      57             : 
      58             :         /*
      59             :          * Always clear setuid/setgid on the orphanage since we don't normally
      60             :          * want that functionality on this directory and xfs_repair doesn't
      61             :          * create it this way either.  Leave the other access bits unchanged.
      62      363945 :          */
      63             :         inode->i_mode &= ~(S_ISUID | S_ISGID);
      64             : 
      65             :         /*
      66             :          * Change the ownerships and register quota modifications
      67             :          * in the transaction.
      68      363945 :          */
      69           0 :         if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID)) {
      70           0 :                 if (XFS_IS_UQUOTA_ON(mp))
      71           0 :                         oldu = xfs_qm_vop_chown(tp, dp, &dp->i_udquot, udqp);
      72             :                 inode->i_uid = GLOBAL_ROOT_UID;
      73      363945 :         }
      74           0 :         if (!gid_eq(inode->i_gid, GLOBAL_ROOT_GID)) {
      75           0 :                 if (XFS_IS_GQUOTA_ON(mp))
      76           0 :                         oldg = xfs_qm_vop_chown(tp, dp, &dp->i_gdquot, gdqp);
      77             :                 inode->i_gid = GLOBAL_ROOT_GID;
      78      363945 :         }
      79           0 :         if (dp->i_projid != 0) {
      80           0 :                 if (XFS_IS_PQUOTA_ON(mp))
      81           0 :                         oldp = xfs_qm_vop_chown(tp, dp, &dp->i_pdquot, pdqp);
      82             :                 dp->i_projid = 0;
      83             :         }
      84      363945 : 
      85      363945 :         dp->i_diflags &= ~(XFS_DIFLAG_REALTIME | XFS_DIFLAG_RTINHERIT);
      86             :         xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
      87      363945 : 
      88             :         XFS_STATS_INC(mp, xs_ig_attrchg);
      89      363945 : 
      90           0 :         if (xfs_has_wsync(mp))
      91      363945 :                 xfs_trans_set_sync(tp);
      92             :         error = xfs_trans_commit(tp);
      93      363945 : 
      94      363945 :         xfs_qm_dqrele(oldu);
      95      363945 :         xfs_qm_dqrele(oldg);
      96             :         xfs_qm_dqrele(oldp);
      97      363945 : 
      98      363945 : out_dqrele:
      99      363945 :         xfs_qm_dqrele(udqp);
     100      363945 :         xfs_qm_dqrele(gdqp);
     101      363945 :         xfs_qm_dqrele(pdqp);
     102             :         return error;
     103             : }
     104             : 
     105             : /*
     106             :  * Enable logged extended attributes for parent pointers.  This must get done
     107             :  * before we create transactions and start making changes.
     108             :  */
     109      363938 : STATIC int
     110             : xrep_adoption_grab_log_assist(
     111             :         struct xfs_scrub        *sc)
     112      363938 : {
     113             :         int                     error;
     114      363938 : 
     115             :         if (!xfs_has_parent(sc->mp))
     116             :                 return 0;
     117      363938 : 
     118             :         ASSERT(!(sc->flags & XREP_FSGATES_LARP));
     119      363938 : 
     120      363944 :         error = xfs_attr_grab_log_assist(sc->mp);
     121             :         if (error)
     122             :                 return error;
     123      363945 : 
     124             :         trace_xchk_fsgates_enable(sc, XREP_FSGATES_LARP);
     125      363945 : 
     126      363945 :         sc->flags |= XREP_FSGATES_LARP;
     127             :         return 0;
     128             : }
     129             : 
     130             : #define ORPHANAGE       "lost+found"
     131             : 
     132             : /* Create the orphanage directory, and set sc->orphanage to it. */
     133      363873 : int
     134             : xrep_orphanage_create(
     135             :         struct xfs_scrub        *sc)
     136      363873 : {
     137      363873 :         struct xfs_mount        *mp = sc->mp;
     138      363873 :         struct dentry           *root_dentry, *orphanage_dentry;
     139      363873 :         struct inode            *root_inode = VFS_I(sc->mp->m_rootip);
     140      363873 :         struct inode            *orphanage_inode;
     141             :         int                     error;
     142      727746 : 
     143             :         if (xfs_is_shutdown(mp))
     144      727746 :                 return -EIO;
     145           0 :         if (xfs_is_readonly(mp)) {
     146           0 :                 sc->orphanage = NULL;
     147             :                 return 0;
     148             :         }
     149      363873 : 
     150      363873 :         ASSERT(sc->tp == NULL);
     151             :         ASSERT(sc->orphanage == NULL);
     152             : 
     153      363873 :         /* Find the dentry for the root directory... */
     154      363945 :         root_dentry = d_find_alias(root_inode);
     155           0 :         if (!root_dentry) {
     156           0 :                 error = -EFSCORRUPTED;
     157             :                 goto out;
     158             :         }
     159             : 
     160      363945 :         /* ...which is a directory, right? */
     161           0 :         if (!d_is_dir(root_dentry)) {
     162           0 :                 error = -EFSCORRUPTED;
     163             :                 goto out_dput_root;
     164             :         }
     165             : 
     166      363945 :         /* Try to find the orphanage directory. */
     167      363945 :         inode_lock_nested(root_inode, I_MUTEX_PARENT);
     168             :         orphanage_dentry = lookup_one_len(ORPHANAGE, root_dentry,
     169      363945 :                         strlen(ORPHANAGE));
     170           0 :         if (IS_ERR(orphanage_dentry)) {
     171           0 :                 error = PTR_ERR(orphanage_dentry);
     172             :                 goto out_unlock_root;
     173             :         }
     174             : 
     175             :         /*
     176             :          * Nothing found?  Call mkdir to create the orphanage.  Create the
     177             :          * directory without group or other-user access because we're live and
     178             :          * someone could have been relying partly on minimal access to a parent
     179             :          * directory to control access to a file we put in here.
     180      363945 :          */
     181          48 :         if (d_really_is_negative(orphanage_dentry)) {
     182             :                 error = vfs_mkdir(&nop_mnt_idmap, root_inode, orphanage_dentry,
     183          48 :                                 0700);
     184           0 :                 if (error)
     185             :                         goto out_dput_orphanage;
     186             :         }
     187             : 
     188      363945 :         /* Not a directory? Bail out. */
     189           0 :         if (!d_is_dir(orphanage_dentry)) {
     190           0 :                 error = -ENOTDIR;
     191             :                 goto out_dput_orphanage;
     192             :         }
     193             : 
     194             :         /*
     195             :          * Grab a reference to the orphanage.  This /should/ succeed since
     196             :          * we hold the root directory locked and therefore nobody can delete
     197             :          * the orphanage.
     198      363945 :          */
     199      363945 :         orphanage_inode = igrab(d_inode(orphanage_dentry));
     200           0 :         if (!orphanage_inode) {
     201           0 :                 error = -ENOENT;
     202             :                 goto out_dput_orphanage;
     203             :         }
     204             : 
     205      363945 :         /* Make sure the orphanage is owned by root. */
     206      363945 :         error = xrep_chown_orphanage(sc, XFS_I(orphanage_inode));
     207           0 :         if (error)
     208             :                 goto out_dput_orphanage;
     209             : 
     210      363945 :         /* Stash the reference for later and bail out. */
     211      363945 :         sc->orphanage = XFS_I(orphanage_inode);
     212             :         sc->orphanage_ilock_flags = 0;
     213      363945 : 
     214      363945 : out_dput_orphanage:
     215      363945 :         dput(orphanage_dentry);
     216      363945 : out_unlock_root:
     217      363945 :         inode_unlock(VFS_I(sc->mp->m_rootip));
     218      363945 : out_dput_root:
     219             :         dput(root_dentry);
     220             : out:
     221             :         /*
     222             :          * Turn on whatever log features are required for an adoption to be
     223             :          * committed correctly.
     224      363945 :          */
     225      363945 :         if (!error)
     226             :                 error = xrep_adoption_grab_log_assist(sc);
     227             :         return error;
     228             : }
     229             : 
     230           0 : void
     231             : xrep_orphanage_ilock(
     232             :         struct xfs_scrub        *sc,
     233             :         unsigned int            ilock_flags)
     234           0 : {
     235           0 :         sc->orphanage_ilock_flags |= ilock_flags;
     236           0 :         xfs_ilock(sc->orphanage, ilock_flags);
     237             : }
     238             : 
     239    88500276 : bool
     240             : xrep_orphanage_ilock_nowait(
     241             :         struct xfs_scrub        *sc,
     242             :         unsigned int            ilock_flags)
     243    88500276 : {
     244    88500276 :         if (xfs_ilock_nowait(sc->orphanage, ilock_flags)) {
     245    88500276 :                 sc->orphanage_ilock_flags |= ilock_flags;
     246             :                 return true;
     247             :         }
     248             : 
     249             :         return false;
     250             : }
     251             : 
     252   176993428 : void
     253             : xrep_orphanage_iunlock(
     254             :         struct xfs_scrub        *sc,
     255             :         unsigned int            ilock_flags)
     256   176993428 : {
     257   176996985 :         xfs_iunlock(sc->orphanage, ilock_flags);
     258        3557 :         sc->orphanage_ilock_flags &= ~ilock_flags;
     259             : }
     260             : 
     261             : /* Grab the IOLOCK of the orphanage and sc->ip. */
     262    88496715 : int
     263             : xrep_orphanage_iolock_two(
     264             :         struct xfs_scrub        *sc)
     265    88496715 : {
     266             :         int                     error = 0;
     267    88500272 : 
     268    88500272 :         while (true) {
     269           1 :                 if (xchk_should_terminate(sc, &error))
     270             :                         return error;
     271             : 
     272             :                 /*
     273             :                  * Normal XFS takes the IOLOCK before grabbing a transaction.
     274             :                  * Scrub holds a transaction, which means that we can't block
     275             :                  * on either IOLOCK.
     276    88500271 :                  */
     277    88500271 :                 if (xrep_orphanage_ilock_nowait(sc, XFS_IOLOCK_EXCL)) {
     278             :                         if (xchk_ilock_nowait(sc, XFS_IOLOCK_EXCL))
     279        3557 :                                 break;
     280             :                         xrep_orphanage_iunlock(sc, XFS_IOLOCK_EXCL);
     281        3557 :                 }
     282             :                 delay(1);
     283             :         }
     284             : 
     285             :         return 0;
     286             : }
     287             : 
     288             : /*
     289             :  * Set up the adoption structure and compute the block reservations needed to
     290             :  * add sc->ip to the orphanage.
     291             :  */
     292    88496720 : int
     293             : xrep_adoption_init(
     294             :         struct xfs_scrub        *sc,
     295             :         struct xrep_adoption    *adopt)
     296    88496720 : {
     297    88496720 :         struct xfs_mount        *mp = sc->mp;
     298             :         unsigned int            child_blkres = 0;
     299    88496720 : 
     300    88496720 :         adopt->sc = sc;
     301    88496720 :         adopt->orphanage_blkres = xfs_link_space_res(mp, MAXNAMELEN);
     302    32239241 :         if (S_ISDIR(VFS_I(sc->ip)->i_mode))
     303    32239241 :                 child_blkres = xfs_rename_space_res(mp, 0, false,
     304    88496720 :                                                 xfs_name_dotdot.len, false);
     305             :         if (xfs_has_parent(sc->mp))
     306    88496720 :                 child_blkres += XFS_ADDAFORK_SPACE_RES(sc->mp);
     307    88496720 :         adopt->child_blkres = child_blkres;
     308    88496720 : 
     309             :         if (xfs_has_parent(mp)) {
     310           0 :                 ASSERT(sc->flags & XREP_FSGATES_LARP);
     311             :                 return xfs_parent_start_locked(mp, &adopt->parent);
     312             :         } else {
     313           0 :                 adopt->parent = NULL;
     314             :         }
     315             : 
     316             :         return 0;
     317             : }
     318             : 
     319             : /*
     320             :  * Compute the xfs_name for the directory entry that we're adding to the
     321             :  * orphanage.  Caller must hold ILOCKs of sc->ip and the orphanage and must not
     322           5 :  * reuse namebuf until the adoption completes or is cancelled.
     323             :  */
     324             : int
     325             : xrep_adoption_compute_name(
     326           5 :         struct xrep_adoption    *adopt,
     327           5 :         unsigned char           *namebuf)
     328           5 : {
     329           5 :         struct xfs_name         *xname = &adopt->xname;
     330           5 :         struct xfs_scrub        *sc = adopt->sc;
     331             :         xfs_ino_t               ino;
     332           5 :         unsigned int            incr = 0;
     333           5 :         int                     error = 0;
     334           5 : 
     335             :         xname->name = namebuf;
     336             :         xname->len = snprintf(namebuf, MAXNAMELEN, "%llu", sc->ip->i_ino);
     337           5 :         xname->type = xfs_mode_to_ftype(VFS_I(sc->ip)->i_mode);
     338           5 : 
     339           0 :         /* Make sure the filename is unique in the lost+found. */
     340           0 :         error = xchk_dir_lookup(sc, sc->orphanage, xname, &ino);
     341           0 :         while (error == 0 && incr < 10000) {
     342             :                 xname->len = snprintf(namebuf, MAXNAMELEN, "%llu.%u",
     343           5 :                                 sc->ip->i_ino, ++incr);
     344             :                 error = xchk_dir_lookup(sc, sc->orphanage, xname, &ino);
     345             :         }
     346             :         if (error == 0) {
     347             :                 /* We already have 10,000 entries in the orphanage? */
     348           5 :                 return -EFSCORRUPTED;
     349           0 :         }
     350             : 
     351             :         if (error != -ENOENT)
     352             :                 return error;
     353             :         return 0;
     354             : }
     355             : 
     356             : /*
     357             :  * Prepare to send a child to the orphanage.
     358             :  *
     359             :  * Reserve more space in the transaction, take the ILOCKs of the orphanage and
     360             :  * sc->ip, join them to the transaction, and reserve quota to reparent the
     361    88496719 :  * latter.  Caller must hold the IOLOCK of the orphanage and sc->ip.
     362             :  */
     363             : int
     364    88496719 : xrep_adoption_prep(
     365    88496719 :         struct xrep_adoption    *adopt)
     366             : {
     367             :         struct xfs_scrub        *sc = adopt->sc;
     368             :         int                     error;
     369             : 
     370             :         /*
     371    88496719 :          * Reserve space to the transaction to handle expansion of both the
     372    88496719 :          * orphanage and the child directory.
     373    88496719 :          */
     374             :         error = xfs_trans_reserve_more(sc->tp,
     375             :                         adopt->orphanage_blkres + adopt->child_blkres, 0);
     376    88496719 :         if (error)
     377             :                 return error;
     378    88496719 : 
     379    88496719 :         xfs_lock_two_inodes(sc->orphanage, XFS_ILOCK_EXCL,
     380             :                             sc->ip, XFS_ILOCK_EXCL);
     381    88496719 :         sc->ilock_flags |= XFS_ILOCK_EXCL;
     382    88496719 :         sc->orphanage_ilock_flags |= XFS_ILOCK_EXCL;
     383             : 
     384             :         xfs_trans_ijoin(sc->tp, sc->orphanage, 0);
     385             :         xfs_trans_ijoin(sc->tp, sc->ip, 0);
     386             : 
     387             :         /*
     388             :          * Reserve enough quota in the orphan directory to add the new name.
     389             :          * Normally the orphanage should have user/group/project ids of zero
     390    88496719 :          * and hence is not subject to quota enforcement, but we're allowed to
     391    88496719 :          * exceed quota to reattach disconnected parts of the directory tree.
     392    88496719 :          */
     393             :         error = xfs_trans_reserve_quota_nblks(sc->tp, sc->orphanage,
     394             :                         adopt->orphanage_blkres, 0, true);
     395             :         if (error)
     396             :                 return error;
     397             : 
     398             :         /*
     399             :          * Reserve enough quota in the child directory to change dotdot.
     400    88496719 :          * Here we're also allowed to exceed file quota to repair inconsistent
     401    32239240 :          * metadata.
     402             :          */
     403    32239240 :         if (adopt->child_blkres) {
     404           0 :                 error = xfs_trans_reserve_quota_nblks(sc->tp, sc->ip,
     405             :                                 adopt->child_blkres, 0, true);
     406             :                 if (error)
     407             :                         return error;
     408             :         }
     409             : 
     410             :         return 0;
     411             : }
     412             : 
     413             : /*
     414             :  * Make sure the dcache does not have a positive dentry for the name we've
     415             :  * chosen.  The caller should have checked with the ondisk directory, so any
     416           0 :  * discrepancy is a sign that something is seriously wrong.
     417             :  */
     418             : static int
     419           0 : xrep_orphanage_check_dcache(
     420             :         struct xrep_adoption    *adopt)
     421           0 : {
     422           0 :         struct qstr             qname = QSTR_INIT(adopt->xname.name,
     423             :                                                   adopt->xname.len);
     424           0 :         struct dentry           *d_orphanage, *d_child;
     425           0 :         int                     error = 0;
     426             : 
     427             :         d_orphanage = d_find_alias(VFS_I(adopt->sc->orphanage));
     428           0 :         if (!d_orphanage)
     429           0 :                 return 0;
     430           0 : 
     431             :         d_child = d_hash_and_lookup(d_orphanage, &qname);
     432           0 :         if (d_child) {
     433           0 :                 trace_xrep_orphanage_check_child(adopt->sc->mp, d_child);
     434           0 : 
     435             :                 if (d_is_positive(d_child)) {
     436             :                         ASSERT(d_is_negative(d_child));
     437           0 :                         error = -EFSCORRUPTED;
     438             :                 }
     439             : 
     440           0 :                 dput(d_child);
     441           0 :         }
     442             : 
     443             :         dput(d_orphanage);
     444             :         if (error)
     445             :                 return error;
     446             : 
     447             :         /*
     448             :          * Do we need to update d_parent of the dentry for the file being
     449           0 :          * repaired?  In theory there shouldn't be one since the file had
     450           0 :          * nonzero nlink but wasn't connected to any parent dir.
     451           0 :          */
     452           0 :         d_child = d_find_alias(VFS_I(adopt->sc->ip));
     453             :         if (d_child) {
     454           0 :                 trace_xrep_orphanage_check_alias(adopt->sc->mp, d_child);
     455           0 :                 ASSERT(d_child->d_parent == NULL);
     456             : 
     457             :                 dput(d_child);
     458             :                 return -EFSCORRUPTED;
     459             :         }
     460             : 
     461             :         return 0;
     462             : }
     463             : 
     464             : /*
     465             :  * Remove all negative dentries from the dcache.  There should not be any
     466             :  * positive entries, since we've maintained our lock on the orphanage
     467           0 :  * directory.
     468             :  */
     469             : static void
     470           0 : xrep_orphanage_zap_dcache(
     471             :         struct xrep_adoption    *adopt)
     472           0 : {
     473             :         struct qstr             qname = QSTR_INIT(adopt->xname.name,
     474           0 :                                                   adopt->xname.len);
     475           0 :         struct dentry           *d_orphanage, *d_child;
     476           0 : 
     477             :         d_orphanage = d_find_alias(VFS_I(adopt->sc->orphanage));
     478           0 :         if (!d_orphanage)
     479           0 :                 return;
     480           0 : 
     481             :         d_child = d_hash_and_lookup(d_orphanage, &qname);
     482           0 :         while (d_child != NULL) {
     483           0 :                 trace_xrep_orphanage_invalidate_child(adopt->sc->mp, d_child);
     484           0 : 
     485           0 :                 ASSERT(d_is_negative(d_child));
     486             :                 d_invalidate(d_child);
     487             :                 dput(d_child);
     488           0 :                 d_child = d_lookup(d_orphanage, &qname);
     489             :         }
     490             : 
     491             :         dput(d_orphanage);
     492             : }
     493             : 
     494             : static inline int
     495             : xrep_pptr_attr_sizeof(
     496             :         const struct xrep_adoption      *adopt)
     497             : {
     498             :         size_t                          res = sizeof(struct xfs_attr_sf_hdr);
     499             : 
     500           0 :         res += xfs_attr_sf_entsize_byname(sizeof(struct xfs_parent_name_rec),
     501             :                         adopt->xname.len);
     502             :         return res;
     503           0 : }
     504           0 : 
     505           0 : /*
     506           0 :  * Move the current file to the orphanage.
     507             :  *
     508           0 :  * The caller must hold the IOLOCKs and the ILOCKs for both sc->ip and the
     509             :  * orphanage.  The directory entry name must have been computed, and quota
     510           0 :  * reserved.  The function returns with both inodes joined and ILOCKed to the
     511           0 :  * transaction.
     512           0 :  */
     513             : int
     514             : xrep_adoption_commit(
     515           0 :         struct xrep_adoption    *adopt)
     516             : {
     517           0 :         struct xfs_scrub        *sc = adopt->sc;
     518           0 :         struct xfs_name         *xname = &adopt->xname;
     519             :         bool                    isdir = S_ISDIR(VFS_I(sc->ip)->i_mode);
     520             :         int                     error;
     521             : 
     522             :         trace_xrep_adoption_commit(sc->orphanage, &adopt->xname, sc->ip->i_ino);
     523             : 
     524           0 :         error = xrep_orphanage_check_dcache(adopt);
     525             :         if (error)
     526           0 :                 goto out_parent;
     527           0 : 
     528           0 :         /*
     529             :          * If this filesystem has parent pointers, ensure that the file being
     530             :          * moved to the orphanage has an attribute fork.  This is required
     531           0 :          * because the parent pointer code does not itself add attr forks.
     532           0 :          */
     533             :         if (!xfs_inode_has_attr_fork(sc->ip) && xfs_has_parent(sc->mp)) {
     534             :                 int sf_size = xrep_pptr_attr_sizeof(adopt);
     535           0 : 
     536           0 :                 error = xfs_bmap_add_attrfork(sc->tp, sc->ip, sf_size, true);
     537           0 :                 if (error)
     538           0 :                         goto out_parent;
     539           0 :         }
     540             : 
     541             :         /* Create the new name in the orphanage. */
     542             :         error = xfs_dir_createname(sc->tp, sc->orphanage, xname, sc->ip->i_ino,
     543           0 :                         adopt->orphanage_blkres);
     544           0 :         if (error)
     545             :                 goto out_parent;
     546           0 : 
     547           0 :         /*
     548             :          * Bump the link count of the orphanage if we just added a
     549             :          * subdirectory, and update its timestamps.
     550             :          */
     551             :         xfs_trans_ichgtime(sc->tp, sc->orphanage,
     552             :                         XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
     553             :         if (isdir)
     554             :                 xfs_bumplink(sc->tp, sc->orphanage);
     555           0 :         xfs_trans_log_inode(sc->tp, sc->orphanage, XFS_ILOG_CORE);
     556           0 : 
     557           0 :         /* Bump the link count of the child. */
     558           0 :         if (adopt->bump_child_nlink) {
     559             :                 xfs_bumplink(sc->tp, sc->ip);
     560             :                 xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);
     561           0 :         }
     562           0 : 
     563           0 :         /* Replace the dotdot entry if the child is a subdirectory. */
     564           0 :         if (isdir) {
     565           0 :                 error = xfs_dir_replace(sc->tp, sc->ip, &xfs_name_dotdot,
     566             :                                 sc->orphanage->i_ino, adopt->child_blkres);
     567             :                 if (error)
     568             :                         goto out_parent;
     569             :         }
     570    88496719 : 
     571             :         /* Add a parent pointer from the file back to the lost+found. */
     572             :         if (adopt->parent) {
     573             :                 error = xfs_parent_add(sc->tp, adopt->parent, sc->orphanage,
     574    88496719 :                                 xname, sc->ip);
     575             :                 if (error)
     576             :                         goto out_parent;
     577             :         }
     578             : 
     579             :         /*
     580             :          * Notify dirent hooks that we moved the file to /lost+found, and
     581             :          * finish all the deferred work so that we know the adoption is fully
     582    88496719 :          * recorded in the log.
     583    88496719 :          */
     584    88496719 :         xfs_dir_update_hook(sc->orphanage, sc->ip, 1, xname);
     585    88496719 :         error = xrep_defer_finish(sc);
     586             :         if (error)
     587             :                 goto out_parent;
     588             : 
     589   506439802 :         /* Remove negative dentries from the lost+found's dcache */
     590             :         xrep_orphanage_zap_dcache(adopt);
     591             : out_parent:
     592   506439802 :         xfs_parent_finish(sc->mp, adopt->parent);
     593             :         adopt->parent = NULL;
     594             :         return error;
     595      363903 : }
     596           5 : 
     597             : /* Cancel a proposed relocation of a file to the orphanage. */
     598      363903 : void
     599      363909 : xrep_adoption_cancel(
     600             :         struct xrep_adoption    *adopt,
     601             :         int                     error)
     602             : {
     603             :         struct xfs_scrub        *sc = adopt->sc;
     604             : 
     605             :         /*
     606             :          * Setting up (and hence cancelling) an adoption is the last thing that
     607             :          * repair code does.  Hence we don't bother giving back the quota or
     608             :          * space reservations or unlock the inodes.  Later when we have incore
     609             :          * state to manage, we'll need to give that back.
     610             :          */
     611             :         trace_xrep_adoption_cancel(sc->orphanage, sc->ip, error);
     612             :         xfs_parent_finish(sc->mp, adopt->parent);
     613             :         adopt->parent = NULL;
     614             : }
     615             : 
     616             : /* Release the orphanage. */
     617             : void
     618             : xrep_orphanage_rele(
     619             :         struct xfs_scrub        *sc)
     620             : {
     621             :         if (!sc->orphanage)
     622             :                 return;
     623             : 
     624             :         if (sc->orphanage_ilock_flags)
     625             :                 xfs_iunlock(sc->orphanage, sc->orphanage_ilock_flags);
     626             : 
     627             :         xchk_irele(sc, sc->orphanage);
     628             :         sc->orphanage = NULL;
     629             : }
     630             : 
     631             : /* Can the orphanage adopt this file? */
     632             : bool
     633             : xrep_orphanage_can_adopt(
     634             :         struct xfs_scrub        *sc)
     635             : {
     636             :         ASSERT(sc->ip != NULL);
     637             : 
     638             :         if (!sc->orphanage)
     639             :                 return false;
     640             :         if (sc->ip == sc->orphanage)
     641             :                 return false;
     642             :         if (xfs_internal_inum(sc->mp, sc->ip->i_ino))
     643             :                 return false;
     644             :         if (xfs_is_metadata_inode(sc->ip))
     645             :                 return false;
     646             :         return true;
     647             : }

Generated by: LCOV version 1.14