Loading...
Note: File does not exist in v3.15.
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
21struct kmem_cache *xfs_iunlink_cache;
22
23static 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
28static void
29xfs_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
39static uint64_t
40xfs_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 */
50static int
51xfs_iunlink_log_dinode(
52 struct xfs_trans *tp,
53 struct xfs_iunlink_item *iup)
54{
55 struct xfs_inode *ip = iup->ip;
56 struct xfs_dinode *dip;
57 struct xfs_buf *ibp;
58 xfs_agino_t old_ptr;
59 int offset;
60 int error;
61
62 error = xfs_imap_to_bp(tp->t_mountp, 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 old_ptr = be32_to_cpu(dip->di_next_unlinked);
77 if (old_ptr != iup->old_agino) {
78 xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
79 sizeof(*dip), __this_address);
80 error = -EFSCORRUPTED;
81 goto out;
82 }
83
84 trace_xfs_iunlink_update_dinode(iup, old_ptr);
85
86 dip->di_next_unlinked = cpu_to_be32(iup->next_agino);
87 offset = ip->i_imap.im_boffset +
88 offsetof(struct xfs_dinode, di_next_unlinked);
89
90 xfs_dinode_calc_crc(tp->t_mountp, dip);
91 xfs_trans_inode_buf(tp, ibp);
92 xfs_trans_log_buf(tp, ibp, offset, offset + sizeof(xfs_agino_t) - 1);
93 return 0;
94out:
95 xfs_trans_brelse(tp, ibp);
96 return error;
97}
98
99/*
100 * On precommit, we grab the inode cluster buffer for the inode number we were
101 * passed, then update the next unlinked field for that inode in the buffer and
102 * log the buffer. This ensures that the inode cluster buffer was logged in the
103 * correct order w.r.t. other inode cluster buffers. We can then remove the
104 * iunlink item from the transaction and release it as it is has now served it's
105 * purpose.
106 */
107static int
108xfs_iunlink_item_precommit(
109 struct xfs_trans *tp,
110 struct xfs_log_item *lip)
111{
112 struct xfs_iunlink_item *iup = IUL_ITEM(lip);
113 int error;
114
115 error = xfs_iunlink_log_dinode(tp, iup);
116 list_del(&lip->li_trans);
117 xfs_iunlink_item_release(lip);
118 return error;
119}
120
121static const struct xfs_item_ops xfs_iunlink_item_ops = {
122 .iop_release = xfs_iunlink_item_release,
123 .iop_sort = xfs_iunlink_item_sort,
124 .iop_precommit = xfs_iunlink_item_precommit,
125};
126
127
128/*
129 * Initialize the inode log item for a newly allocated (in-core) inode.
130 *
131 * Inode extents can only reside within an AG. Hence specify the starting
132 * block for the inode chunk by offset within an AG as well as the
133 * length of the allocated extent.
134 *
135 * This joins the item to the transaction and marks it dirty so
136 * that we don't need a separate call to do this, nor does the
137 * caller need to know anything about the iunlink item.
138 */
139int
140xfs_iunlink_log_inode(
141 struct xfs_trans *tp,
142 struct xfs_inode *ip,
143 struct xfs_perag *pag,
144 xfs_agino_t next_agino)
145{
146 struct xfs_mount *mp = tp->t_mountp;
147 struct xfs_iunlink_item *iup;
148
149 ASSERT(xfs_verify_agino_or_null(pag, next_agino));
150 ASSERT(xfs_verify_agino_or_null(pag, ip->i_next_unlinked));
151
152 /*
153 * Since we're updating a linked list, we should never find that the
154 * current pointer is the same as the new value, unless we're
155 * terminating the list.
156 */
157 if (ip->i_next_unlinked == next_agino) {
158 if (next_agino != NULLAGINO)
159 return -EFSCORRUPTED;
160 return 0;
161 }
162
163 iup = kmem_cache_zalloc(xfs_iunlink_cache, GFP_KERNEL | __GFP_NOFAIL);
164 xfs_log_item_init(mp, &iup->item, XFS_LI_IUNLINK,
165 &xfs_iunlink_item_ops);
166
167 iup->ip = ip;
168 iup->next_agino = next_agino;
169 iup->old_agino = ip->i_next_unlinked;
170 iup->pag = xfs_perag_hold(pag);
171
172 xfs_trans_add_item(tp, &iup->item);
173 tp->t_flags |= XFS_TRANS_DIRTY;
174 set_bit(XFS_LI_DIRTY, &iup->item.li_flags);
175 return 0;
176}
177