1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <djwong@kernel.org>
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"
19 #include "xfs_buf_item.h"
20 #include "xfs_trace.h"
22 /* Set the root of an in-memory btree. */
25 struct xfs_btree_cur
*cur
,
26 const union xfs_btree_ptr
*ptr
,
29 ASSERT(cur
->bc_ops
->type
== XFS_BTREE_TYPE_MEM
);
31 cur
->bc_mem
.xfbtree
->root
= *ptr
;
32 cur
->bc_mem
.xfbtree
->nlevels
+= inc
;
35 /* Initialize a pointer from the in-memory btree header. */
37 xfbtree_init_ptr_from_cur(
38 struct xfs_btree_cur
*cur
,
39 union xfs_btree_ptr
*ptr
)
41 ASSERT(cur
->bc_ops
->type
== XFS_BTREE_TYPE_MEM
);
43 *ptr
= cur
->bc_mem
.xfbtree
->root
;
46 /* Duplicate an in-memory btree cursor. */
47 struct xfs_btree_cur
*
49 struct xfs_btree_cur
*cur
)
51 struct xfs_btree_cur
*ncur
;
53 ASSERT(cur
->bc_ops
->type
== XFS_BTREE_TYPE_MEM
);
55 ncur
= xfs_btree_alloc_cursor(cur
->bc_mp
, cur
->bc_tp
, cur
->bc_ops
,
56 cur
->bc_maxlevels
, cur
->bc_cache
);
57 ncur
->bc_flags
= cur
->bc_flags
;
58 ncur
->bc_nlevels
= cur
->bc_nlevels
;
59 ncur
->bc_mem
.xfbtree
= cur
->bc_mem
.xfbtree
;
61 ncur
->bc_group
= xfs_group_hold(cur
->bc_group
);
65 /* Close the btree xfile and release all resources. */
70 xfs_buftarg_drain(xfbt
->target
);
73 /* Compute the number of bytes available for records. */
74 static inline unsigned int
77 const struct xfs_btree_ops
*ops
)
79 return XMBUF_BLOCKSIZE
- XFS_BTREE_LBLOCK_CRC_LEN
;
82 /* Initialize an empty leaf block as the btree root. */
84 xfbtree_init_leaf_block(
87 const struct xfs_btree_ops
*ops
)
90 xfbno_t bno
= xfbt
->highest_bno
++;
93 error
= xfs_buf_get(xfbt
->target
, xfbno_to_daddr(bno
), XFBNO_BBSIZE
,
98 trace_xfbtree_create_root_buf(xfbt
, bp
);
100 bp
->b_ops
= ops
->buf_ops
;
101 xfs_btree_init_buf(mp
, bp
, ops
, 0, 0, xfbt
->owner
);
104 xfbt
->root
.l
= cpu_to_be64(bno
);
109 * Create an in-memory btree root that can be used with the given xmbuf.
110 * Callers must set xfbt->owner.
114 struct xfs_mount
*mp
,
115 struct xfbtree
*xfbt
,
116 struct xfs_buftarg
*btp
,
117 const struct xfs_btree_ops
*ops
)
119 unsigned int blocklen
= xfbtree_rec_bytes(mp
, ops
);
120 unsigned int keyptr_len
;
123 /* Requires a long-format CRC-format btree */
124 if (!xfs_has_crc(mp
)) {
125 ASSERT(xfs_has_crc(mp
));
128 if (ops
->ptr_len
!= XFS_BTREE_LONG_PTR_LEN
) {
129 ASSERT(ops
->ptr_len
== XFS_BTREE_LONG_PTR_LEN
);
133 memset(xfbt
, 0, sizeof(*xfbt
));
136 /* Set up min/maxrecs for this btree. */
137 keyptr_len
= ops
->key_len
+ sizeof(__be64
);
138 xfbt
->maxrecs
[0] = blocklen
/ ops
->rec_len
;
139 xfbt
->maxrecs
[1] = blocklen
/ keyptr_len
;
140 xfbt
->minrecs
[0] = xfbt
->maxrecs
[0] / 2;
141 xfbt
->minrecs
[1] = xfbt
->maxrecs
[1] / 2;
142 xfbt
->highest_bno
= 0;
145 /* Initialize the empty btree. */
146 error
= xfbtree_init_leaf_block(mp
, xfbt
, ops
);
150 trace_xfbtree_init(mp
, xfbt
, ops
);
155 xfs_buftarg_drain(xfbt
->target
);
159 /* Allocate a block to our in-memory btree. */
162 struct xfs_btree_cur
*cur
,
163 const union xfs_btree_ptr
*start
,
164 union xfs_btree_ptr
*new,
167 struct xfbtree
*xfbt
= cur
->bc_mem
.xfbtree
;
168 xfbno_t bno
= xfbt
->highest_bno
++;
170 ASSERT(cur
->bc_ops
->type
== XFS_BTREE_TYPE_MEM
);
172 trace_xfbtree_alloc_block(xfbt
, cur
, bno
);
174 /* Fail if the block address exceeds the maximum for the buftarg. */
175 if (!xfbtree_verify_bno(xfbt
, bno
)) {
176 ASSERT(xfbtree_verify_bno(xfbt
, bno
));
181 new->l
= cpu_to_be64(bno
);
186 /* Free a block from our in-memory btree. */
189 struct xfs_btree_cur
*cur
,
192 struct xfbtree
*xfbt
= cur
->bc_mem
.xfbtree
;
193 xfs_daddr_t daddr
= xfs_buf_daddr(bp
);
194 xfbno_t bno
= xfs_daddr_to_xfbno(daddr
);
196 ASSERT(cur
->bc_ops
->type
== XFS_BTREE_TYPE_MEM
);
198 trace_xfbtree_free_block(xfbt
, cur
, bno
);
200 if (bno
+ 1 == xfbt
->highest_bno
)
206 /* Return the minimum number of records for a btree block. */
209 struct xfs_btree_cur
*cur
,
212 struct xfbtree
*xfbt
= cur
->bc_mem
.xfbtree
;
214 return xfbt
->minrecs
[level
!= 0];
217 /* Return the maximum number of records for a btree block. */
220 struct xfs_btree_cur
*cur
,
223 struct xfbtree
*xfbt
= cur
->bc_mem
.xfbtree
;
225 return xfbt
->maxrecs
[level
!= 0];
228 /* If this log item is a buffer item that came from the xfbtree, return it. */
229 static inline struct xfs_buf
*
231 struct xfbtree
*xfbt
,
232 const struct xfs_log_item
*lip
)
234 const struct xfs_buf_log_item
*bli
;
237 if (lip
->li_type
!= XFS_LI_BUF
)
240 bli
= container_of(lip
, struct xfs_buf_log_item
, bli_item
);
242 if (bp
->b_target
!= xfbt
->target
)
249 * Commit changes to the incore btree immediately by writing all dirty xfbtree
250 * buffers to the backing xfile. This detaches all xfbtree buffers from the
251 * transaction, even on failure. The buffer locks are dropped between the
252 * delwri queue and submit, so the caller must synchronize btree access.
254 * Normally we'd let the buffers commit with the transaction and get written to
255 * the xfile via the log, but online repair stages ephemeral btrees in memory
256 * and uses the btree_staging functions to write new btrees to disk atomically.
257 * The in-memory btree (and its backing store) are discarded at the end of the
258 * repair phase, which means that xfbtree buffers cannot commit with the rest
261 * In other words, online repair only needs the transaction to collect buffer
262 * pointers and to avoid buffer deadlocks, not to guarantee consistency of
266 xfbtree_trans_commit(
267 struct xfbtree
*xfbt
,
268 struct xfs_trans
*tp
)
270 struct xfs_log_item
*lip
, *n
;
271 bool tp_dirty
= false;
275 * For each xfbtree buffer attached to the transaction, write the dirty
276 * buffers to the xfile and release them.
278 list_for_each_entry_safe(lip
, n
, &tp
->t_items
, li_trans
) {
279 struct xfs_buf
*bp
= xfbtree_buf_match(xfbt
, lip
);
282 if (test_bit(XFS_LI_DIRTY
, &lip
->li_flags
))
287 trace_xfbtree_trans_commit_buf(xfbt
, bp
);
289 xmbuf_trans_bdetach(tp
, bp
);
292 * If the buffer fails verification, note the failure but
293 * continue walking the transaction items so that we remove all
294 * ephemeral btree buffers.
297 error
= xmbuf_finalize(bp
);
303 * Reset the transaction's dirty flag to reflect the dirty state of the
304 * log items that are still attached.
306 tp
->t_flags
= (tp
->t_flags
& ~XFS_TRANS_DIRTY
) |
307 (tp_dirty
? XFS_TRANS_DIRTY
: 0);
313 * Cancel changes to the incore btree by detaching all the xfbtree buffers.
314 * Changes are not undone, so callers must not access the btree ever again.
317 xfbtree_trans_cancel(
318 struct xfbtree
*xfbt
,
319 struct xfs_trans
*tp
)
321 struct xfs_log_item
*lip
, *n
;
322 bool tp_dirty
= false;
324 list_for_each_entry_safe(lip
, n
, &tp
->t_items
, li_trans
) {
325 struct xfs_buf
*bp
= xfbtree_buf_match(xfbt
, lip
);
328 if (test_bit(XFS_LI_DIRTY
, &lip
->li_flags
))
333 trace_xfbtree_trans_cancel_buf(xfbt
, bp
);
335 xmbuf_trans_bdetach(tp
, bp
);
340 * Reset the transaction's dirty flag to reflect the dirty state of the
341 * log items that are still attached.
343 tp
->t_flags
= (tp
->t_flags
& ~XFS_TRANS_DIRTY
) |
344 (tp_dirty
? XFS_TRANS_DIRTY
: 0);