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

Generated by: LCOV version 1.14