1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2022-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_trans_resv.h"
11 #include "xfs_mount.h"
12 #include "xfs_defer.h"
13 #include "xfs_btree.h"
14 #include "xfs_buf_mem.h"
15 #include "xfs_btree_mem.h"
16 #include "xfs_error.h"
17 #include "scrub/rcbag_btree.h"
18 #include "scrub/trace.h"
20 static struct kmem_cache
*rcbagbt_cur_cache
;
23 rcbagbt_init_key_from_rec(
24 union xfs_btree_key
*key
,
25 const union xfs_btree_rec
*rec
)
27 struct rcbag_key
*bag_key
= (struct rcbag_key
*)key
;
28 const struct rcbag_rec
*bag_rec
= (const struct rcbag_rec
*)rec
;
30 BUILD_BUG_ON(sizeof(struct rcbag_key
) > sizeof(union xfs_btree_key
));
31 BUILD_BUG_ON(sizeof(struct rcbag_rec
) > sizeof(union xfs_btree_rec
));
33 bag_key
->rbg_startblock
= bag_rec
->rbg_startblock
;
34 bag_key
->rbg_blockcount
= bag_rec
->rbg_blockcount
;
38 rcbagbt_init_rec_from_cur(
39 struct xfs_btree_cur
*cur
,
40 union xfs_btree_rec
*rec
)
42 struct rcbag_rec
*bag_rec
= (struct rcbag_rec
*)rec
;
43 struct rcbag_rec
*bag_irec
= (struct rcbag_rec
*)&cur
->bc_rec
;
45 bag_rec
->rbg_startblock
= bag_irec
->rbg_startblock
;
46 bag_rec
->rbg_blockcount
= bag_irec
->rbg_blockcount
;
47 bag_rec
->rbg_refcount
= bag_irec
->rbg_refcount
;
52 struct xfs_btree_cur
*cur
,
53 const union xfs_btree_key
*key
)
55 struct rcbag_rec
*rec
= (struct rcbag_rec
*)&cur
->bc_rec
;
56 const struct rcbag_key
*kp
= (const struct rcbag_key
*)key
;
58 if (kp
->rbg_startblock
> rec
->rbg_startblock
)
60 if (kp
->rbg_startblock
< rec
->rbg_startblock
)
63 if (kp
->rbg_blockcount
> rec
->rbg_blockcount
)
65 if (kp
->rbg_blockcount
< rec
->rbg_blockcount
)
72 rcbagbt_diff_two_keys(
73 struct xfs_btree_cur
*cur
,
74 const union xfs_btree_key
*k1
,
75 const union xfs_btree_key
*k2
,
76 const union xfs_btree_key
*mask
)
78 const struct rcbag_key
*kp1
= (const struct rcbag_key
*)k1
;
79 const struct rcbag_key
*kp2
= (const struct rcbag_key
*)k2
;
83 if (kp1
->rbg_startblock
> kp2
->rbg_startblock
)
85 if (kp1
->rbg_startblock
< kp2
->rbg_startblock
)
88 if (kp1
->rbg_blockcount
> kp2
->rbg_blockcount
)
90 if (kp1
->rbg_blockcount
< kp2
->rbg_blockcount
)
98 struct xfs_btree_cur
*cur
,
99 const union xfs_btree_key
*k1
,
100 const union xfs_btree_key
*k2
)
102 const struct rcbag_key
*kp1
= (const struct rcbag_key
*)k1
;
103 const struct rcbag_key
*kp2
= (const struct rcbag_key
*)k2
;
105 if (kp1
->rbg_startblock
> kp2
->rbg_startblock
)
107 if (kp1
->rbg_startblock
< kp2
->rbg_startblock
)
110 if (kp1
->rbg_blockcount
> kp2
->rbg_blockcount
)
112 if (kp1
->rbg_blockcount
< kp2
->rbg_blockcount
)
119 rcbagbt_recs_inorder(
120 struct xfs_btree_cur
*cur
,
121 const union xfs_btree_rec
*r1
,
122 const union xfs_btree_rec
*r2
)
124 const struct rcbag_rec
*rp1
= (const struct rcbag_rec
*)r1
;
125 const struct rcbag_rec
*rp2
= (const struct rcbag_rec
*)r2
;
127 if (rp1
->rbg_startblock
> rp2
->rbg_startblock
)
129 if (rp1
->rbg_startblock
< rp2
->rbg_startblock
)
132 if (rp1
->rbg_blockcount
> rp2
->rbg_blockcount
)
134 if (rp1
->rbg_blockcount
< rp2
->rbg_blockcount
)
140 static xfs_failaddr_t
144 struct xfs_mount
*mp
= bp
->b_mount
;
145 struct xfs_btree_block
*block
= XFS_BUF_TO_BLOCK(bp
);
148 unsigned int maxrecs
;
150 if (!xfs_verify_magic(bp
, block
->bb_magic
))
151 return __this_address
;
153 fa
= xfs_btree_fsblock_v5hdr_verify(bp
, XFS_RMAP_OWN_UNKNOWN
);
157 level
= be16_to_cpu(block
->bb_level
);
158 if (level
>= rcbagbt_maxlevels_possible())
159 return __this_address
;
161 maxrecs
= rcbagbt_maxrecs(mp
, XFBNO_BLOCKSIZE
, level
== 0);
162 return xfs_btree_memblock_verify(bp
, maxrecs
);
169 xfs_failaddr_t fa
= rcbagbt_verify(bp
);
172 xfs_verifier_error(bp
, -EFSCORRUPTED
, fa
);
175 /* skip crc checks on in-memory btrees to save time */
176 static const struct xfs_buf_ops rcbagbt_mem_buf_ops
= {
177 .name
= "rcbagbt_mem",
178 .magic
= { 0, cpu_to_be32(RCBAG_MAGIC
) },
179 .verify_read
= rcbagbt_rw_verify
,
180 .verify_write
= rcbagbt_rw_verify
,
181 .verify_struct
= rcbagbt_verify
,
184 static const struct xfs_btree_ops rcbagbt_mem_ops
= {
186 .type
= XFS_BTREE_TYPE_MEM
,
188 .rec_len
= sizeof(struct rcbag_rec
),
189 .key_len
= sizeof(struct rcbag_key
),
190 .ptr_len
= XFS_BTREE_LONG_PTR_LEN
,
193 .statoff
= XFS_STATS_CALC_INDEX(xs_rcbag_2
),
195 .dup_cursor
= xfbtree_dup_cursor
,
196 .set_root
= xfbtree_set_root
,
197 .alloc_block
= xfbtree_alloc_block
,
198 .free_block
= xfbtree_free_block
,
199 .get_minrecs
= xfbtree_get_minrecs
,
200 .get_maxrecs
= xfbtree_get_maxrecs
,
201 .init_key_from_rec
= rcbagbt_init_key_from_rec
,
202 .init_rec_from_cur
= rcbagbt_init_rec_from_cur
,
203 .init_ptr_from_cur
= xfbtree_init_ptr_from_cur
,
204 .key_diff
= rcbagbt_key_diff
,
205 .buf_ops
= &rcbagbt_mem_buf_ops
,
206 .diff_two_keys
= rcbagbt_diff_two_keys
,
207 .keys_inorder
= rcbagbt_keys_inorder
,
208 .recs_inorder
= rcbagbt_recs_inorder
,
211 /* Create a cursor for an in-memory btree. */
212 struct xfs_btree_cur
*
214 struct xfs_mount
*mp
,
215 struct xfs_trans
*tp
,
216 struct xfbtree
*xfbtree
)
218 struct xfs_btree_cur
*cur
;
220 cur
= xfs_btree_alloc_cursor(mp
, tp
, &rcbagbt_mem_ops
,
221 rcbagbt_maxlevels_possible(), rcbagbt_cur_cache
);
223 cur
->bc_mem
.xfbtree
= xfbtree
;
224 cur
->bc_nlevels
= xfbtree
->nlevels
;
228 /* Create an in-memory refcount bag btree. */
231 struct xfs_mount
*mp
,
232 struct xfbtree
*xfbt
,
233 struct xfs_buftarg
*btp
)
236 return xfbtree_init(mp
, xfbt
, btp
, &rcbagbt_mem_ops
);
239 /* Calculate number of records in a refcount bag btree block. */
240 static inline unsigned int
241 rcbagbt_block_maxrecs(
242 unsigned int blocklen
,
246 return blocklen
/ sizeof(struct rcbag_rec
);
248 (sizeof(struct rcbag_key
) + sizeof(rcbag_ptr_t
));
252 * Calculate number of records in an refcount bag btree block.
256 struct xfs_mount
*mp
,
257 unsigned int blocklen
,
260 blocklen
-= RCBAG_BLOCK_LEN
;
261 return rcbagbt_block_maxrecs(blocklen
, leaf
);
264 /* Compute the max possible height for refcount bag btrees. */
266 rcbagbt_maxlevels_possible(void)
268 unsigned int minrecs
[2];
269 unsigned int blocklen
;
271 blocklen
= XFBNO_BLOCKSIZE
- XFS_BTREE_LBLOCK_CRC_LEN
;
273 minrecs
[0] = rcbagbt_block_maxrecs(blocklen
, true) / 2;
274 minrecs
[1] = rcbagbt_block_maxrecs(blocklen
, false) / 2;
276 return xfs_btree_space_to_height(minrecs
, ULLONG_MAX
);
279 /* Calculate the refcount bag btree size for some records. */
282 unsigned long long nr_records
)
284 unsigned int minrecs
[2];
285 unsigned int blocklen
;
287 blocklen
= XFBNO_BLOCKSIZE
- XFS_BTREE_LBLOCK_CRC_LEN
;
289 minrecs
[0] = rcbagbt_block_maxrecs(blocklen
, true) / 2;
290 minrecs
[1] = rcbagbt_block_maxrecs(blocklen
, false) / 2;
292 return xfs_btree_calc_size(minrecs
, nr_records
);
296 rcbagbt_init_cur_cache(void)
298 rcbagbt_cur_cache
= kmem_cache_create("xfs_rcbagbt_cur",
299 xfs_btree_cur_sizeof(rcbagbt_maxlevels_possible()),
302 if (!rcbagbt_cur_cache
)
308 rcbagbt_destroy_cur_cache(void)
310 kmem_cache_destroy(rcbagbt_cur_cache
);
311 rcbagbt_cur_cache
= NULL
;
314 /* Look up the refcount bag record corresponding to this reverse mapping. */
317 struct xfs_btree_cur
*cur
,
318 const struct xfs_rmap_irec
*rmap
,
321 struct rcbag_rec
*rec
= (struct rcbag_rec
*)&cur
->bc_rec
;
323 rec
->rbg_startblock
= rmap
->rm_startblock
;
324 rec
->rbg_blockcount
= rmap
->rm_blockcount
;
326 return xfs_btree_lookup(cur
, XFS_LOOKUP_EQ
, success
);
329 /* Get the data from the pointed-to record. */
332 struct xfs_btree_cur
*cur
,
333 struct rcbag_rec
*rec
,
336 union xfs_btree_rec
*btrec
;
339 error
= xfs_btree_get_rec(cur
, &btrec
, has
);
340 if (error
|| !(*has
))
343 memcpy(rec
, btrec
, sizeof(struct rcbag_rec
));
347 /* Update the record referred to by cur to the value given. */
350 struct xfs_btree_cur
*cur
,
351 const struct rcbag_rec
*rec
)
353 union xfs_btree_rec btrec
;
355 memcpy(&btrec
, rec
, sizeof(struct rcbag_rec
));
356 return xfs_btree_update(cur
, &btrec
);
359 /* Update the record referred to by cur to the value given. */
362 struct xfs_btree_cur
*cur
,
363 const struct rcbag_rec
*rec
,
366 struct rcbag_rec
*btrec
= (struct rcbag_rec
*)&cur
->bc_rec
;
368 memcpy(btrec
, rec
, sizeof(struct rcbag_rec
));
369 return xfs_btree_insert(cur
, success
);