LCOV - code coverage report
Current view: top level - fs/xfs - xfs_iunlink_item.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-achx @ Mon Jul 31 20:08:12 PDT 2023 Lines: 56 60 93.3 %
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) 2020-2022, Red Hat, Inc.
       4             :  * All Rights Reserved.
       5             :  */
       6             : #include "xfs.h"
       7             : #include "xfs_fs.h"
       8             : #include "xfs_shared.h"
       9             : #include "xfs_format.h"
      10             : #include "xfs_log_format.h"
      11             : #include "xfs_trans_resv.h"
      12             : #include "xfs_mount.h"
      13             : #include "xfs_inode.h"
      14             : #include "xfs_trans.h"
      15             : #include "xfs_trans_priv.h"
      16             : #include "xfs_ag.h"
      17             : #include "xfs_iunlink_item.h"
      18             : #include "xfs_trace.h"
      19             : #include "xfs_error.h"
      20             : 
      21             : struct kmem_cache       *xfs_iunlink_cache;
      22             : 
      23             : static inline struct xfs_iunlink_item *IUL_ITEM(struct xfs_log_item *lip)
      24             : {
      25             :         return container_of(lip, struct xfs_iunlink_item, item);
      26             : }
      27             : 
      28             : static void
      29    72954963 : xfs_iunlink_item_release(
      30             :         struct xfs_log_item     *lip)
      31             : {
      32    72954963 :         struct xfs_iunlink_item *iup = IUL_ITEM(lip);
      33             : 
      34    72954963 :         xfs_perag_put(iup->pag);
      35    73322317 :         kmem_cache_free(xfs_iunlink_cache, IUL_ITEM(lip));
      36    73331343 : }
      37             : 
      38             : 
      39             : static uint64_t
      40   103189679 : xfs_iunlink_item_sort(
      41             :         struct xfs_log_item     *lip)
      42             : {
      43   103189679 :         return IUL_ITEM(lip)->ip->i_ino;
      44             : }
      45             : 
      46             : /*
      47             :  * Look up the inode cluster buffer and log the on-disk unlinked inode change
      48             :  * we need to make.
      49             :  */
      50             : static int
      51    72861372 : xfs_iunlink_log_dinode(
      52             :         struct xfs_trans        *tp,
      53             :         struct xfs_iunlink_item *iup)
      54             : {
      55    72861372 :         struct xfs_mount        *mp = tp->t_mountp;
      56    72861372 :         struct xfs_inode        *ip = iup->ip;
      57    72861372 :         struct xfs_dinode       *dip;
      58    72861372 :         struct xfs_buf          *ibp;
      59    72861372 :         int                     offset;
      60    72861372 :         int                     error;
      61             : 
      62    72861372 :         error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp);
      63    73261668 :         if (error)
      64             :                 return error;
      65             :         /*
      66             :          * Don't log the unlinked field on stale buffers as this may be the
      67             :          * transaction that frees the inode cluster and relogging the buffer
      68             :          * here will incorrectly remove the stale state.
      69             :          */
      70    73261668 :         if (ibp->b_flags & XBF_STALE)
      71      148079 :                 goto out;
      72             : 
      73    73113589 :         dip = xfs_buf_offset(ibp, ip->i_imap.im_boffset);
      74             : 
      75             :         /* Make sure the old pointer isn't garbage. */
      76    72904202 :         if (be32_to_cpu(dip->di_next_unlinked) != iup->old_agino) {
      77           0 :                 xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
      78           0 :                                 sizeof(*dip), __this_address);
      79           0 :                 error = -EFSCORRUPTED;
      80           0 :                 goto out;
      81             :         }
      82             : 
      83   145808404 :         trace_xfs_iunlink_update_dinode(mp, iup->pag->pag_agno,
      84    72904202 :                         XFS_INO_TO_AGINO(mp, ip->i_ino),
      85             :                         be32_to_cpu(dip->di_next_unlinked), iup->next_agino);
      86             : 
      87    72930756 :         dip->di_next_unlinked = cpu_to_be32(iup->next_agino);
      88    72930756 :         offset = ip->i_imap.im_boffset +
      89             :                         offsetof(struct xfs_dinode, di_next_unlinked);
      90             : 
      91    72930756 :         xfs_dinode_calc_crc(mp, dip);
      92    72547459 :         xfs_trans_inode_buf(tp, ibp);
      93    72747019 :         xfs_trans_log_buf(tp, ibp, offset, offset + sizeof(xfs_agino_t) - 1);
      94    72747019 :         return 0;
      95      148079 : out:
      96      148079 :         xfs_trans_brelse(tp, ibp);
      97      148079 :         return error;
      98             : }
      99             : 
     100             : /*
     101             :  * On precommit, we grab the inode cluster buffer for the inode number we were
     102             :  * passed, then update the next unlinked field for that inode in the buffer and
     103             :  * log the buffer. This ensures that the inode cluster buffer was logged in the
     104             :  * correct order w.r.t. other inode cluster buffers. We can then remove the
     105             :  * iunlink item from the transaction and release it as it is has now served it's
     106             :  * purpose.
     107             :  */
     108             : static int
     109    73397557 : xfs_iunlink_item_precommit(
     110             :         struct xfs_trans        *tp,
     111             :         struct xfs_log_item     *lip)
     112             : {
     113    73397557 :         struct xfs_iunlink_item *iup = IUL_ITEM(lip);
     114    73397557 :         int                     error;
     115             : 
     116    73397557 :         error = xfs_iunlink_log_dinode(tp, iup);
     117    73264543 :         list_del(&lip->li_trans);
     118    72874156 :         xfs_iunlink_item_release(lip);
     119    73257077 :         return error;
     120             : }
     121             : 
     122             : static const struct xfs_item_ops xfs_iunlink_item_ops = {
     123             :         .iop_release    = xfs_iunlink_item_release,
     124             :         .iop_sort       = xfs_iunlink_item_sort,
     125             :         .iop_precommit  = xfs_iunlink_item_precommit,
     126             : };
     127             : 
     128             : 
     129             : /*
     130             :  * Initialize the inode log item for a newly allocated (in-core) inode.
     131             :  *
     132             :  * Inode extents can only reside within an AG. Hence specify the starting
     133             :  * block for the inode chunk by offset within an AG as well as the
     134             :  * length of the allocated extent.
     135             :  *
     136             :  * This joins the item to the transaction and marks it dirty so
     137             :  * that we don't need a separate call to do this, nor does the
     138             :  * caller need to know anything about the iunlink item.
     139             :  */
     140             : int
     141   137232467 : xfs_iunlink_log_inode(
     142             :         struct xfs_trans        *tp,
     143             :         struct xfs_inode        *ip,
     144             :         struct xfs_perag        *pag,
     145             :         xfs_agino_t             next_agino)
     146             : {
     147   137232467 :         struct xfs_mount        *mp = tp->t_mountp;
     148   137232467 :         struct xfs_iunlink_item *iup;
     149             : 
     150   179466679 :         ASSERT(xfs_verify_agino_or_null(pag, next_agino));
     151   179880847 :         ASSERT(xfs_verify_agino_or_null(pag, ip->i_next_unlinked));
     152             : 
     153             :         /*
     154             :          * Since we're updating a linked list, we should never find that the
     155             :          * current pointer is the same as the new value, unless we're
     156             :          * terminating the list.
     157             :          */
     158   137232467 :         if (ip->i_next_unlinked == next_agino) {
     159    64297899 :                 if (next_agino != NULLAGINO)
     160             :                         return -EFSCORRUPTED;
     161    64297899 :                 return 0;
     162             :         }
     163             : 
     164    72934568 :         iup = kmem_cache_zalloc(xfs_iunlink_cache, GFP_KERNEL | __GFP_NOFAIL);
     165    73285957 :         xfs_log_item_init(mp, &iup->item, XFS_LI_IUNLINK,
     166             :                           &xfs_iunlink_item_ops);
     167             : 
     168    73092904 :         iup->ip = ip;
     169    73092904 :         iup->next_agino = next_agino;
     170    73092904 :         iup->old_agino = ip->i_next_unlinked;
     171    73092904 :         iup->pag = xfs_perag_hold(pag);
     172             : 
     173    73322760 :         xfs_trans_add_item(tp, &iup->item);
     174    73129270 :         tp->t_flags |= XFS_TRANS_DIRTY;
     175    73129270 :         set_bit(XFS_LI_DIRTY, &iup->item.li_flags);
     176    73129270 :         return 0;
     177             : }
     178             : 

Generated by: LCOV version 1.14