~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/xfs/xfs_iunlink_item.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 xfs_iunlink_item_release(
 30         struct xfs_log_item     *lip)
 31 {
 32         struct xfs_iunlink_item *iup = IUL_ITEM(lip);
 33 
 34         xfs_perag_put(iup->pag);
 35         kmem_cache_free(xfs_iunlink_cache, IUL_ITEM(lip));
 36 }
 37 
 38 
 39 static uint64_t
 40 xfs_iunlink_item_sort(
 41         struct xfs_log_item     *lip)
 42 {
 43         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 xfs_iunlink_log_dinode(
 52         struct xfs_trans        *tp,
 53         struct xfs_iunlink_item *iup)
 54 {
 55         struct xfs_mount        *mp = tp->t_mountp;
 56         struct xfs_inode        *ip = iup->ip;
 57         struct xfs_dinode       *dip;
 58         struct xfs_buf          *ibp;
 59         int                     offset;
 60         int                     error;
 61 
 62         error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp);
 63         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         if (ibp->b_flags & XBF_STALE)
 71                 goto out;
 72 
 73         dip = xfs_buf_offset(ibp, ip->i_imap.im_boffset);
 74 
 75         /* Make sure the old pointer isn't garbage. */
 76         if (be32_to_cpu(dip->di_next_unlinked) != iup->old_agino) {
 77                 xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
 78                                 sizeof(*dip), __this_address);
 79                 error = -EFSCORRUPTED;
 80                 goto out;
 81         }
 82 
 83         trace_xfs_iunlink_update_dinode(mp, iup->pag->pag_agno,
 84                         XFS_INO_TO_AGINO(mp, ip->i_ino),
 85                         be32_to_cpu(dip->di_next_unlinked), iup->next_agino);
 86 
 87         dip->di_next_unlinked = cpu_to_be32(iup->next_agino);
 88         offset = ip->i_imap.im_boffset +
 89                         offsetof(struct xfs_dinode, di_next_unlinked);
 90 
 91         xfs_dinode_calc_crc(mp, dip);
 92         xfs_trans_inode_buf(tp, ibp);
 93         xfs_trans_log_buf(tp, ibp, offset, offset + sizeof(xfs_agino_t) - 1);
 94         return 0;
 95 out:
 96         xfs_trans_brelse(tp, ibp);
 97         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 xfs_iunlink_item_precommit(
110         struct xfs_trans        *tp,
111         struct xfs_log_item     *lip)
112 {
113         struct xfs_iunlink_item *iup = IUL_ITEM(lip);
114         int                     error;
115 
116         error = xfs_iunlink_log_dinode(tp, iup);
117         list_del(&lip->li_trans);
118         xfs_iunlink_item_release(lip);
119         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 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         struct xfs_mount        *mp = tp->t_mountp;
148         struct xfs_iunlink_item *iup;
149 
150         ASSERT(xfs_verify_agino_or_null(pag, next_agino));
151         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         if (ip->i_next_unlinked == next_agino) {
159                 if (next_agino != NULLAGINO)
160                         return -EFSCORRUPTED;
161                 return 0;
162         }
163 
164         iup = kmem_cache_zalloc(xfs_iunlink_cache, GFP_KERNEL | __GFP_NOFAIL);
165         xfs_log_item_init(mp, &iup->item, XFS_LI_IUNLINK,
166                           &xfs_iunlink_item_ops);
167 
168         iup->ip = ip;
169         iup->next_agino = next_agino;
170         iup->old_agino = ip->i_next_unlinked;
171         iup->pag = xfs_perag_hold(pag);
172 
173         xfs_trans_add_item(tp, &iup->item);
174         tp->t_flags |= XFS_TRANS_DIRTY;
175         set_bit(XFS_LI_DIRTY, &iup->item.li_flags);
176         return 0;
177 }
178 
179 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php