1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <djwong@kernel.org>
5 */
6 #include "xfs_platform.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_trans.h"
14 #include "xfs_btree.h"
15 #include "xfs_error.h"
16 #include "xfs_buf_mem.h"
17 #include "xfs_btree_mem.h"
18 #include "xfs_ag.h"
19 #include "xfs_buf_item.h"
20 #include "xfs_trace.h"
21 #include "xfs_rtgroup.h"
22
23 /* Set the root of an in-memory btree. */
24 void
xfbtree_set_root(struct xfs_btree_cur * cur,const union xfs_btree_ptr * ptr,int inc)25 xfbtree_set_root(
26 struct xfs_btree_cur *cur,
27 const union xfs_btree_ptr *ptr,
28 int inc)
29 {
30 ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
31
32 cur->bc_mem.xfbtree->root = *ptr;
33 cur->bc_mem.xfbtree->nlevels += inc;
34 }
35
36 /* Initialize a pointer from the in-memory btree header. */
37 void
xfbtree_init_ptr_from_cur(struct xfs_btree_cur * cur,union xfs_btree_ptr * ptr)38 xfbtree_init_ptr_from_cur(
39 struct xfs_btree_cur *cur,
40 union xfs_btree_ptr *ptr)
41 {
42 ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
43
44 *ptr = cur->bc_mem.xfbtree->root;
45 }
46
47 /* Duplicate an in-memory btree cursor. */
48 struct xfs_btree_cur *
xfbtree_dup_cursor(struct xfs_btree_cur * cur)49 xfbtree_dup_cursor(
50 struct xfs_btree_cur *cur)
51 {
52 struct xfs_btree_cur *ncur;
53
54 ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
55
56 ncur = xfs_btree_alloc_cursor(cur->bc_mp, cur->bc_tp, cur->bc_ops,
57 cur->bc_maxlevels, cur->bc_cache);
58 ncur->bc_flags = cur->bc_flags;
59 ncur->bc_nlevels = cur->bc_nlevels;
60 ncur->bc_mem.xfbtree = cur->bc_mem.xfbtree;
61 if (cur->bc_group)
62 ncur->bc_group = xfs_group_hold(cur->bc_group);
63 return ncur;
64 }
65
66 /* Close the btree xfile and release all resources. */
67 void
xfbtree_destroy(struct xfbtree * xfbt)68 xfbtree_destroy(
69 struct xfbtree *xfbt)
70 {
71 xfs_buftarg_drain(xfbt->target);
72 }
73
74 /* Compute the number of bytes available for records. */
75 static inline unsigned int
xfbtree_rec_bytes(struct xfs_mount * mp,const struct xfs_btree_ops * ops)76 xfbtree_rec_bytes(
77 struct xfs_mount *mp,
78 const struct xfs_btree_ops *ops)
79 {
80 return XMBUF_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;
81 }
82
83 /* Initialize an empty leaf block as the btree root. */
84 STATIC int
xfbtree_init_leaf_block(struct xfs_mount * mp,struct xfbtree * xfbt,const struct xfs_btree_ops * ops)85 xfbtree_init_leaf_block(
86 struct xfs_mount *mp,
87 struct xfbtree *xfbt,
88 const struct xfs_btree_ops *ops)
89 {
90 struct xfs_buf *bp;
91 xfbno_t bno = xfbt->highest_bno++;
92 int error;
93
94 error = xfs_buf_get(xfbt->target, xfbno_to_daddr(bno), XFBNO_BBSIZE,
95 &bp);
96 if (error)
97 return error;
98
99 trace_xfbtree_create_root_buf(xfbt, bp);
100
101 bp->b_ops = ops->buf_ops;
102 xfs_btree_init_buf(mp, bp, ops, 0, 0, xfbt->owner);
103 xfs_buf_relse(bp);
104
105 xfbt->root.l = cpu_to_be64(bno);
106 return 0;
107 }
108
109 /*
110 * Create an in-memory btree root that can be used with the given xmbuf.
111 * Callers must set xfbt->owner.
112 */
113 int
xfbtree_init(struct xfs_mount * mp,struct xfbtree * xfbt,struct xfs_buftarg * btp,const struct xfs_btree_ops * ops)114 xfbtree_init(
115 struct xfs_mount *mp,
116 struct xfbtree *xfbt,
117 struct xfs_buftarg *btp,
118 const struct xfs_btree_ops *ops)
119 {
120 unsigned long long owner = xfbt->owner;
121 unsigned int blocklen = xfbtree_rec_bytes(mp, ops);
122 unsigned int keyptr_len;
123 int error;
124
125 /* Requires a long-format CRC-format btree */
126 if (!xfs_has_crc(mp)) {
127 ASSERT(xfs_has_crc(mp));
128 return -EINVAL;
129 }
130 if (ops->ptr_len != XFS_BTREE_LONG_PTR_LEN) {
131 ASSERT(ops->ptr_len == XFS_BTREE_LONG_PTR_LEN);
132 return -EINVAL;
133 }
134
135 memset(xfbt, 0, sizeof(*xfbt));
136 xfbt->target = btp;
137 xfbt->owner = owner;
138
139 /* Set up min/maxrecs for this btree. */
140 keyptr_len = ops->key_len + sizeof(__be64);
141 xfbt->maxrecs[0] = blocklen / ops->rec_len;
142 xfbt->maxrecs[1] = blocklen / keyptr_len;
143 xfbt->minrecs[0] = xfbt->maxrecs[0] / 2;
144 xfbt->minrecs[1] = xfbt->maxrecs[1] / 2;
145 xfbt->highest_bno = 0;
146 xfbt->nlevels = 1;
147
148 /* Initialize the empty btree. */
149 error = xfbtree_init_leaf_block(mp, xfbt, ops);
150 if (error)
151 goto err_freesp;
152
153 trace_xfbtree_init(mp, xfbt, ops);
154
155 return 0;
156
157 err_freesp:
158 xfs_buftarg_drain(xfbt->target);
159 return error;
160 }
161
162 /* Allocate a block to our in-memory btree. */
163 int
xfbtree_alloc_block(struct xfs_btree_cur * cur,const union xfs_btree_ptr * start,union xfs_btree_ptr * new,int * stat)164 xfbtree_alloc_block(
165 struct xfs_btree_cur *cur,
166 const union xfs_btree_ptr *start,
167 union xfs_btree_ptr *new,
168 int *stat)
169 {
170 struct xfbtree *xfbt = cur->bc_mem.xfbtree;
171 xfbno_t bno = xfbt->highest_bno++;
172
173 ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
174
175 trace_xfbtree_alloc_block(xfbt, cur, bno);
176
177 /* Fail if the block address exceeds the maximum for the buftarg. */
178 if (!xfbtree_verify_bno(xfbt, bno)) {
179 ASSERT(xfbtree_verify_bno(xfbt, bno));
180 *stat = 0;
181 return 0;
182 }
183
184 new->l = cpu_to_be64(bno);
185 *stat = 1;
186 return 0;
187 }
188
189 /* Free a block from our in-memory btree. */
190 int
xfbtree_free_block(struct xfs_btree_cur * cur,struct xfs_buf * bp)191 xfbtree_free_block(
192 struct xfs_btree_cur *cur,
193 struct xfs_buf *bp)
194 {
195 struct xfbtree *xfbt = cur->bc_mem.xfbtree;
196 xfs_daddr_t daddr = xfs_buf_daddr(bp);
197 xfbno_t bno = xfs_daddr_to_xfbno(daddr);
198
199 ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_MEM);
200
201 trace_xfbtree_free_block(xfbt, cur, bno);
202
203 if (bno + 1 == xfbt->highest_bno)
204 xfbt->highest_bno--;
205
206 return 0;
207 }
208
209 /* Return the minimum number of records for a btree block. */
210 int
xfbtree_get_minrecs(struct xfs_btree_cur * cur,int level)211 xfbtree_get_minrecs(
212 struct xfs_btree_cur *cur,
213 int level)
214 {
215 struct xfbtree *xfbt = cur->bc_mem.xfbtree;
216
217 return xfbt->minrecs[level != 0];
218 }
219
220 /* Return the maximum number of records for a btree block. */
221 int
xfbtree_get_maxrecs(struct xfs_btree_cur * cur,int level)222 xfbtree_get_maxrecs(
223 struct xfs_btree_cur *cur,
224 int level)
225 {
226 struct xfbtree *xfbt = cur->bc_mem.xfbtree;
227
228 return xfbt->maxrecs[level != 0];
229 }
230
231 /* If this log item is a buffer item that came from the xfbtree, return it. */
232 static inline struct xfs_buf *
xfbtree_buf_match(struct xfbtree * xfbt,const struct xfs_log_item * lip)233 xfbtree_buf_match(
234 struct xfbtree *xfbt,
235 const struct xfs_log_item *lip)
236 {
237 const struct xfs_buf_log_item *bli;
238 struct xfs_buf *bp;
239
240 if (lip->li_type != XFS_LI_BUF)
241 return NULL;
242
243 bli = container_of(lip, struct xfs_buf_log_item, bli_item);
244 bp = bli->bli_buf;
245 if (bp->b_target != xfbt->target)
246 return NULL;
247
248 return bp;
249 }
250
251 /*
252 * Commit changes to the incore btree immediately by writing all dirty xfbtree
253 * buffers to the backing xfile. This detaches all xfbtree buffers from the
254 * transaction, even on failure. The buffer locks are dropped between the
255 * delwri queue and submit, so the caller must synchronize btree access.
256 *
257 * Normally we'd let the buffers commit with the transaction and get written to
258 * the xfile via the log, but online repair stages ephemeral btrees in memory
259 * and uses the btree_staging functions to write new btrees to disk atomically.
260 * The in-memory btree (and its backing store) are discarded at the end of the
261 * repair phase, which means that xfbtree buffers cannot commit with the rest
262 * of a transaction.
263 *
264 * In other words, online repair only needs the transaction to collect buffer
265 * pointers and to avoid buffer deadlocks, not to guarantee consistency of
266 * updates.
267 */
268 int
xfbtree_trans_commit(struct xfbtree * xfbt,struct xfs_trans * tp)269 xfbtree_trans_commit(
270 struct xfbtree *xfbt,
271 struct xfs_trans *tp)
272 {
273 struct xfs_log_item *lip, *n;
274 bool tp_dirty = false;
275 int error = 0;
276
277 /*
278 * For each xfbtree buffer attached to the transaction, write the dirty
279 * buffers to the xfile and release them.
280 */
281 list_for_each_entry_safe(lip, n, &tp->t_items, li_trans) {
282 struct xfs_buf *bp = xfbtree_buf_match(xfbt, lip);
283
284 if (!bp) {
285 if (test_bit(XFS_LI_DIRTY, &lip->li_flags))
286 tp_dirty |= true;
287 continue;
288 }
289
290 trace_xfbtree_trans_commit_buf(xfbt, bp);
291
292 xmbuf_trans_bdetach(tp, bp);
293
294 /*
295 * If the buffer fails verification, note the failure but
296 * continue walking the transaction items so that we remove all
297 * ephemeral btree buffers.
298 */
299 if (!error)
300 error = xmbuf_finalize(bp);
301
302 xfs_buf_relse(bp);
303 }
304
305 /*
306 * Reset the transaction's dirty flag to reflect the dirty state of the
307 * log items that are still attached.
308 */
309 tp->t_flags = (tp->t_flags & ~XFS_TRANS_DIRTY) |
310 (tp_dirty ? XFS_TRANS_DIRTY : 0);
311
312 return error;
313 }
314
315 /*
316 * Cancel changes to the incore btree by detaching all the xfbtree buffers.
317 * Changes are not undone, so callers must not access the btree ever again.
318 */
319 void
xfbtree_trans_cancel(struct xfbtree * xfbt,struct xfs_trans * tp)320 xfbtree_trans_cancel(
321 struct xfbtree *xfbt,
322 struct xfs_trans *tp)
323 {
324 struct xfs_log_item *lip, *n;
325 bool tp_dirty = false;
326
327 list_for_each_entry_safe(lip, n, &tp->t_items, li_trans) {
328 struct xfs_buf *bp = xfbtree_buf_match(xfbt, lip);
329
330 if (!bp) {
331 if (test_bit(XFS_LI_DIRTY, &lip->li_flags))
332 tp_dirty |= true;
333 continue;
334 }
335
336 trace_xfbtree_trans_cancel_buf(xfbt, bp);
337
338 xmbuf_trans_bdetach(tp, bp);
339 xfs_buf_relse(bp);
340 }
341
342 /*
343 * Reset the transaction's dirty flag to reflect the dirty state of the
344 * log items that are still attached.
345 */
346 tp->t_flags = (tp->t_flags & ~XFS_TRANS_DIRTY) |
347 (tp_dirty ? XFS_TRANS_DIRTY : 0);
348 }
349