LCOV - code coverage report
Current view: top level - fs/xfs - xfs_attr_inactive.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-achx @ Mon Jul 31 20:08:12 PDT 2023 Lines: 134 174 77.0 %
Date: 2023-07-31 20:08:12 Functions: 5 5 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
       4             :  * Copyright (c) 2013 Red Hat, Inc.
       5             :  * All Rights Reserved.
       6             :  */
       7             : #include "xfs.h"
       8             : #include "xfs_fs.h"
       9             : #include "xfs_shared.h"
      10             : #include "xfs_format.h"
      11             : #include "xfs_log_format.h"
      12             : #include "xfs_trans_resv.h"
      13             : #include "xfs_bit.h"
      14             : #include "xfs_mount.h"
      15             : #include "xfs_da_format.h"
      16             : #include "xfs_da_btree.h"
      17             : #include "xfs_inode.h"
      18             : #include "xfs_attr.h"
      19             : #include "xfs_attr_remote.h"
      20             : #include "xfs_trans.h"
      21             : #include "xfs_bmap.h"
      22             : #include "xfs_attr_leaf.h"
      23             : #include "xfs_quota.h"
      24             : #include "xfs_dir2.h"
      25             : #include "xfs_error.h"
      26             : #include "xfs_health.h"
      27             : 
      28             : /*
      29             :  * Invalidate any incore buffers associated with this remote attribute value
      30             :  * extent.   We never log remote attribute value buffers, which means that they
      31             :  * won't be attached to a transaction and are therefore safe to mark stale.
      32             :  * The actual bunmapi will be taken care of later.
      33             :  */
      34             : STATIC int
      35        2545 : xfs_attr3_rmt_stale(
      36             :         struct xfs_inode        *dp,
      37             :         xfs_dablk_t             blkno,
      38             :         int                     blkcnt)
      39             : {
      40        2545 :         struct xfs_bmbt_irec    map;
      41        2545 :         int                     nmap;
      42        2545 :         int                     error;
      43             : 
      44             :         /*
      45             :          * Roll through the "value", invalidating the attribute value's
      46             :          * blocks.
      47             :          */
      48        5090 :         while (blkcnt > 0) {
      49             :                 /*
      50             :                  * Try to remember where we decided to put the value.
      51             :                  */
      52        2545 :                 nmap = 1;
      53        2545 :                 error = xfs_bmapi_read(dp, (xfs_fileoff_t)blkno, blkcnt,
      54             :                                        &map, &nmap, XFS_BMAPI_ATTRFORK);
      55        2545 :                 if (error)
      56           0 :                         return error;
      57        2545 :                 if (XFS_IS_CORRUPT(dp->i_mount, nmap != 1))
      58           0 :                         return -EFSCORRUPTED;
      59             : 
      60             :                 /*
      61             :                  * Mark any incore buffers for the remote value as stale.  We
      62             :                  * never log remote attr value buffers, so the buffer should be
      63             :                  * easy to kill.
      64             :                  */
      65        2545 :                 error = xfs_attr_rmtval_stale(dp, &map, 0);
      66        2545 :                 if (error)
      67           0 :                         return error;
      68             : 
      69        2545 :                 blkno += map.br_blockcount;
      70        2545 :                 blkcnt -= map.br_blockcount;
      71             :         }
      72             : 
      73             :         return 0;
      74             : }
      75             : 
      76             : /*
      77             :  * Invalidate all of the "remote" value regions pointed to by a particular
      78             :  * leaf block.
      79             :  * Note that we must release the lock on the buffer so that we are not
      80             :  * caught holding something that the logging code wants to flush to disk.
      81             :  */
      82             : STATIC int
      83     1058070 : xfs_attr3_leaf_inactive(
      84             :         struct xfs_trans                **trans,
      85             :         struct xfs_inode                *dp,
      86             :         struct xfs_buf                  *bp)
      87             : {
      88     1058070 :         struct xfs_attr3_icleaf_hdr     ichdr;
      89     1058070 :         struct xfs_mount                *mp = bp->b_mount;
      90     1058070 :         struct xfs_attr_leafblock       *leaf = bp->b_addr;
      91     1058070 :         struct xfs_attr_leaf_entry      *entry;
      92     1058070 :         struct xfs_attr_leaf_name_remote *name_rmt;
      93     1058070 :         int                             error = 0;
      94     1058070 :         int                             i;
      95             : 
      96     1058070 :         xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
      97             : 
      98             :         /*
      99             :          * Find the remote value extents for this leaf and invalidate their
     100             :          * incore buffers.
     101             :          */
     102     1055372 :         entry = xfs_attr3_leaf_entryp(leaf);
     103    20175231 :         for (i = 0; i < ichdr.count; entry++, i++) {
     104    19114715 :                 int             blkcnt;
     105             : 
     106    19114715 :                 if (!entry->nameidx || (entry->flags & XFS_ATTR_LOCAL))
     107    19112170 :                         continue;
     108             : 
     109        2545 :                 name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
     110        2545 :                 if (!name_rmt->valueblk)
     111           0 :                         continue;
     112             : 
     113        2545 :                 blkcnt = xfs_attr3_rmt_blocks(dp->i_mount,
     114        2545 :                                 be32_to_cpu(name_rmt->valuelen));
     115        2545 :                 error = xfs_attr3_rmt_stale(dp,
     116        2545 :                                 be32_to_cpu(name_rmt->valueblk), blkcnt);
     117        7689 :                 if (error)
     118           0 :                         goto err;
     119             :         }
     120             : 
     121     1060516 :         xfs_trans_brelse(*trans, bp);
     122     1059708 : err:
     123     1059708 :         return error;
     124             : }
     125             : 
     126             : /*
     127             :  * Recurse (gasp!) through the attribute nodes until we find leaves.
     128             :  * We're doing a depth-first traversal in order to invalidate everything.
     129             :  */
     130             : STATIC int
     131       20772 : xfs_attr3_node_inactive(
     132             :         struct xfs_trans        **trans,
     133             :         struct xfs_inode        *dp,
     134             :         struct xfs_buf          *bp,
     135             :         int                     level)
     136             : {
     137       20772 :         struct xfs_mount        *mp = dp->i_mount;
     138       20772 :         struct xfs_da_blkinfo   *info;
     139       20772 :         xfs_dablk_t             child_fsb;
     140       20772 :         xfs_daddr_t             parent_blkno, child_blkno;
     141       20772 :         struct xfs_buf          *child_bp;
     142       20772 :         struct xfs_da3_icnode_hdr ichdr;
     143       20772 :         int                     error, i;
     144             : 
     145             :         /*
     146             :          * Since this code is recursive (gasp!) we must protect ourselves.
     147             :          */
     148       20772 :         if (level > XFS_DA_NODE_MAXDEPTH) {
     149           0 :                 xfs_buf_mark_corrupt(bp);
     150           0 :                 xfs_trans_brelse(*trans, bp);   /* no locks for later trans */
     151           0 :                 xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
     152           0 :                 return -EFSCORRUPTED;
     153             :         }
     154             : 
     155       20772 :         xfs_da3_node_hdr_from_disk(dp->i_mount, &ichdr, bp->b_addr);
     156       20774 :         parent_blkno = xfs_buf_daddr(bp);
     157       20774 :         if (!ichdr.count) {
     158           0 :                 xfs_trans_brelse(*trans, bp);
     159           0 :                 return 0;
     160             :         }
     161       20774 :         child_fsb = be32_to_cpu(ichdr.btree[0].before);
     162       20774 :         xfs_trans_brelse(*trans, bp);   /* no locks for later trans */
     163       20778 :         bp = NULL;
     164             : 
     165             :         /*
     166             :          * If this is the node level just above the leaves, simply loop
     167             :          * over the leaves removing all of them.  If this is higher up
     168             :          * in the tree, recurse downward.
     169             :          */
     170       65391 :         for (i = 0; i < ichdr.count; i++) {
     171             :                 /*
     172             :                  * Read the subsidiary block to see what we have to work with.
     173             :                  * Don't do this in a transaction.  This is a depth-first
     174             :                  * traversal of the tree so we may deal with many blocks
     175             :                  * before we come back to this one.
     176             :                  */
     177       44613 :                 error = xfs_da3_node_read(*trans, dp, child_fsb, &child_bp,
     178             :                                           XFS_ATTR_FORK);
     179       44613 :                 if (error)
     180           0 :                         return error;
     181             : 
     182             :                 /* save for re-read later */
     183       44613 :                 child_blkno = xfs_buf_daddr(child_bp);
     184             : 
     185             :                 /*
     186             :                  * Invalidate the subtree, however we have to.
     187             :                  */
     188       44613 :                 info = child_bp->b_addr;
     189       44613 :                 switch (info->magic) {
     190           0 :                 case cpu_to_be16(XFS_DA_NODE_MAGIC):
     191             :                 case cpu_to_be16(XFS_DA3_NODE_MAGIC):
     192           0 :                         error = xfs_attr3_node_inactive(trans, dp, child_bp,
     193             :                                                         level + 1);
     194           0 :                         break;
     195       44613 :                 case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):
     196             :                 case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
     197       44613 :                         error = xfs_attr3_leaf_inactive(trans, dp, child_bp);
     198       44613 :                         break;
     199             :                 default:
     200           0 :                         xfs_buf_mark_corrupt(child_bp);
     201           0 :                         xfs_trans_brelse(*trans, child_bp);
     202           0 :                         xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
     203           0 :                         error = -EFSCORRUPTED;
     204           0 :                         break;
     205             :                 }
     206       44617 :                 if (error)
     207           0 :                         return error;
     208             : 
     209             :                 /*
     210             :                  * Remove the subsidiary block from the cache and from the log.
     211             :                  */
     212       89234 :                 error = xfs_trans_get_buf(*trans, mp->m_ddev_targp,
     213             :                                 child_blkno,
     214       44617 :                                 XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0,
     215             :                                 &child_bp);
     216       44613 :                 if (error)
     217           0 :                         return error;
     218       44613 :                 xfs_trans_binval(*trans, child_bp);
     219       44617 :                 child_bp = NULL;
     220             : 
     221             :                 /*
     222             :                  * If we're not done, re-read the parent to get the next
     223             :                  * child block number.
     224             :                  */
     225       44617 :                 if (i + 1 < ichdr.count) {
     226       23839 :                         struct xfs_da3_icnode_hdr phdr;
     227             : 
     228       23839 :                         error = xfs_da3_node_read_mapped(*trans, dp,
     229             :                                         parent_blkno, &bp, XFS_ATTR_FORK);
     230       23838 :                         if (error)
     231           0 :                                 return error;
     232       23838 :                         xfs_da3_node_hdr_from_disk(dp->i_mount, &phdr,
     233       23838 :                                                   bp->b_addr);
     234       23835 :                         child_fsb = be32_to_cpu(phdr.btree[i + 1].before);
     235       23835 :                         xfs_trans_brelse(*trans, bp);
     236       23838 :                         bp = NULL;
     237             :                 }
     238             :                 /*
     239             :                  * Atomically commit the whole invalidate stuff.
     240             :                  */
     241       44616 :                 error = xfs_trans_roll_inode(trans, dp);
     242       44613 :                 if (error)
     243           0 :                         return  error;
     244             :         }
     245             : 
     246             :         return 0;
     247             : }
     248             : 
     249             : /*
     250             :  * Indiscriminately delete the entire attribute fork
     251             :  *
     252             :  * Recurse (gasp!) through the attribute nodes until we find leaves.
     253             :  * We're doing a depth-first traversal in order to invalidate everything.
     254             :  */
     255             : static int
     256     1035745 : xfs_attr3_root_inactive(
     257             :         struct xfs_trans        **trans,
     258             :         struct xfs_inode        *dp)
     259             : {
     260     1035745 :         struct xfs_mount        *mp = dp->i_mount;
     261     1035745 :         struct xfs_da_blkinfo   *info;
     262     1035745 :         struct xfs_buf          *bp;
     263     1035745 :         xfs_daddr_t             blkno;
     264     1035745 :         int                     error;
     265             : 
     266             :         /*
     267             :          * Read block 0 to see what we have to work with.
     268             :          * We only get here if we have extents, since we remove
     269             :          * the extents in reverse order the extent containing
     270             :          * block 0 must still be there.
     271             :          */
     272     1035745 :         error = xfs_da3_node_read(*trans, dp, 0, &bp, XFS_ATTR_FORK);
     273     1034481 :         if (error)
     274             :                 return error;
     275     1034481 :         blkno = xfs_buf_daddr(bp);
     276             : 
     277             :         /*
     278             :          * Invalidate the tree, even if the "tree" is only a single leaf block.
     279             :          * This is a depth-first traversal!
     280             :          */
     281     1034481 :         info = bp->b_addr;
     282     1034481 :         switch (info->magic) {
     283       20775 :         case cpu_to_be16(XFS_DA_NODE_MAGIC):
     284             :         case cpu_to_be16(XFS_DA3_NODE_MAGIC):
     285       20775 :                 error = xfs_attr3_node_inactive(trans, dp, bp, 1);
     286       20775 :                 break;
     287     1013706 :         case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):
     288             :         case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
     289     1013706 :                 error = xfs_attr3_leaf_inactive(trans, dp, bp);
     290     1013706 :                 break;
     291           0 :         default:
     292           0 :                 xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
     293           0 :                 error = -EFSCORRUPTED;
     294           0 :                 xfs_buf_mark_corrupt(bp);
     295           0 :                 xfs_trans_brelse(*trans, bp);
     296           0 :                 break;
     297             :         }
     298     1035773 :         if (error)
     299           0 :                 return error;
     300             : 
     301             :         /*
     302             :          * Invalidate the incore copy of the root block.
     303             :          */
     304     2070910 :         error = xfs_trans_get_buf(*trans, mp->m_ddev_targp, blkno,
     305     1035455 :                         XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0, &bp);
     306     1032791 :         if (error)
     307             :                 return error;
     308     1032791 :         error = bp->b_error;
     309     1032791 :         if (error) {
     310           0 :                 xfs_trans_brelse(*trans, bp);
     311           0 :                 return error;
     312             :         }
     313     1032791 :         xfs_trans_binval(*trans, bp);   /* remove from cache */
     314             :         /*
     315             :          * Commit the invalidate and start the next transaction.
     316             :          */
     317     1037216 :         error = xfs_trans_roll_inode(trans, dp);
     318             : 
     319     1037216 :         return error;
     320             : }
     321             : 
     322             : /*
     323             :  * xfs_attr_inactive kills all traces of an attribute fork on an inode. It
     324             :  * removes both the on-disk and in-memory inode fork. Note that this also has to
     325             :  * handle the condition of inodes without attributes but with an attribute fork
     326             :  * configured, so we can't use xfs_inode_hasattr() here.
     327             :  *
     328             :  * The in-memory attribute fork is removed even on error.
     329             :  */
     330             : int
     331    61730724 : xfs_attr_inactive(
     332             :         struct xfs_inode        *dp)
     333             : {
     334    61730724 :         struct xfs_trans        *trans;
     335    61730724 :         struct xfs_mount        *mp;
     336    61730724 :         int                     lock_mode = XFS_ILOCK_SHARED;
     337    61730724 :         int                     error = 0;
     338             : 
     339    61730724 :         mp = dp->i_mount;
     340    61730724 :         ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
     341             : 
     342    61730724 :         xfs_ilock(dp, lock_mode);
     343    61688091 :         if (!xfs_inode_has_attr_fork(dp))
     344           0 :                 goto out_destroy_fork;
     345    61688091 :         xfs_iunlock(dp, lock_mode);
     346             : 
     347    61658981 :         lock_mode = 0;
     348             : 
     349    61658981 :         error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrinval, 0, 0, 0, &trans);
     350    61663488 :         if (error)
     351         376 :                 goto out_destroy_fork;
     352             : 
     353    61663112 :         lock_mode = XFS_ILOCK_EXCL;
     354    61663112 :         xfs_ilock(dp, lock_mode);
     355             : 
     356    61646084 :         if (!xfs_inode_has_attr_fork(dp))
     357           0 :                 goto out_cancel;
     358             : 
     359             :         /*
     360             :          * No need to make quota reservations here. We expect to release some
     361             :          * blocks, not allocate, in the common case.
     362             :          */
     363    61646084 :         xfs_trans_ijoin(trans, dp, 0);
     364             : 
     365             :         /*
     366             :          * Invalidate and truncate the attribute fork extents. Make sure the
     367             :          * fork actually has xattr blocks as otherwise the invalidation has no
     368             :          * blocks to read and returns an error. In this case, just do the fork
     369             :          * removal below.
     370             :          */
     371    61694259 :         if (dp->i_af.if_nextents > 0) {
     372     1036271 :                 error = xfs_attr3_root_inactive(&trans, dp);
     373     1035697 :                 if (error)
     374           0 :                         goto out_cancel;
     375             : 
     376     1035697 :                 error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
     377     1037269 :                 if (error)
     378           0 :                         goto out_cancel;
     379             :         }
     380             : 
     381             :         /* Reset the attribute fork - this also destroys the in-core fork */
     382    61695257 :         xfs_attr_fork_remove(dp, trans);
     383             : 
     384    61764704 :         error = xfs_trans_commit(trans);
     385    61767261 :         xfs_iunlock(dp, lock_mode);
     386    61767261 :         return error;
     387             : 
     388           0 : out_cancel:
     389           0 :         xfs_trans_cancel(trans);
     390         376 : out_destroy_fork:
     391             :         /* kill the in-core attr fork before we drop the inode lock */
     392         376 :         xfs_ifork_zap_attr(dp);
     393         376 :         if (lock_mode)
     394           0 :                 xfs_iunlock(dp, lock_mode);
     395             :         return error;
     396             : }

Generated by: LCOV version 1.14