accel/qaic: Add AIC200 support
[drm/drm-misc.git] / fs / xfs / scrub / rcbag_btree.c
blob709356dc62568958b42d1ec4cec7ad1019c53c16
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2022-2024 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <djwong@kernel.org>
5 */
6 #include "xfs.h"
7 #include "xfs_fs.h"
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;
22 STATIC void
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;
37 STATIC void
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;
50 STATIC int64_t
51 rcbagbt_key_diff(
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)
59 return 1;
60 if (kp->rbg_startblock < rec->rbg_startblock)
61 return -1;
63 if (kp->rbg_blockcount > rec->rbg_blockcount)
64 return 1;
65 if (kp->rbg_blockcount < rec->rbg_blockcount)
66 return -1;
68 return 0;
71 STATIC int64_t
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;
81 ASSERT(mask == NULL);
83 if (kp1->rbg_startblock > kp2->rbg_startblock)
84 return 1;
85 if (kp1->rbg_startblock < kp2->rbg_startblock)
86 return -1;
88 if (kp1->rbg_blockcount > kp2->rbg_blockcount)
89 return 1;
90 if (kp1->rbg_blockcount < kp2->rbg_blockcount)
91 return -1;
93 return 0;
96 STATIC int
97 rcbagbt_keys_inorder(
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)
106 return 0;
107 if (kp1->rbg_startblock < kp2->rbg_startblock)
108 return 1;
110 if (kp1->rbg_blockcount > kp2->rbg_blockcount)
111 return 0;
112 if (kp1->rbg_blockcount < kp2->rbg_blockcount)
113 return 1;
115 return 0;
118 STATIC int
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)
128 return 0;
129 if (rp1->rbg_startblock < rp2->rbg_startblock)
130 return 1;
132 if (rp1->rbg_blockcount > rp2->rbg_blockcount)
133 return 0;
134 if (rp1->rbg_blockcount < rp2->rbg_blockcount)
135 return 1;
137 return 0;
140 static xfs_failaddr_t
141 rcbagbt_verify(
142 struct xfs_buf *bp)
144 struct xfs_mount *mp = bp->b_mount;
145 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
146 xfs_failaddr_t fa;
147 unsigned int level;
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);
154 if (fa)
155 return fa;
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);
165 static void
166 rcbagbt_rw_verify(
167 struct xfs_buf *bp)
169 xfs_failaddr_t fa = rcbagbt_verify(bp);
171 if (fa)
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 = {
185 .name = "rcbag",
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,
192 .lru_refs = 1,
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 *
213 rcbagbt_mem_cursor(
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;
225 return cur;
228 /* Create an in-memory refcount bag btree. */
230 rcbagbt_mem_init(
231 struct xfs_mount *mp,
232 struct xfbtree *xfbt,
233 struct xfs_buftarg *btp)
235 xfbt->owner = 0;
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,
243 bool leaf)
245 if (leaf)
246 return blocklen / sizeof(struct rcbag_rec);
247 return blocklen /
248 (sizeof(struct rcbag_key) + sizeof(rcbag_ptr_t));
252 * Calculate number of records in an refcount bag btree block.
254 unsigned int
255 rcbagbt_maxrecs(
256 struct xfs_mount *mp,
257 unsigned int blocklen,
258 bool leaf)
260 blocklen -= RCBAG_BLOCK_LEN;
261 return rcbagbt_block_maxrecs(blocklen, leaf);
264 /* Compute the max possible height for refcount bag btrees. */
265 unsigned int
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. */
280 unsigned long long
281 rcbagbt_calc_size(
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);
295 int __init
296 rcbagbt_init_cur_cache(void)
298 rcbagbt_cur_cache = kmem_cache_create("xfs_rcbagbt_cur",
299 xfs_btree_cur_sizeof(rcbagbt_maxlevels_possible()),
300 0, 0, NULL);
302 if (!rcbagbt_cur_cache)
303 return -ENOMEM;
304 return 0;
307 void
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. */
316 rcbagbt_lookup_eq(
317 struct xfs_btree_cur *cur,
318 const struct xfs_rmap_irec *rmap,
319 int *success)
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. */
331 rcbagbt_get_rec(
332 struct xfs_btree_cur *cur,
333 struct rcbag_rec *rec,
334 int *has)
336 union xfs_btree_rec *btrec;
337 int error;
339 error = xfs_btree_get_rec(cur, &btrec, has);
340 if (error || !(*has))
341 return error;
343 memcpy(rec, btrec, sizeof(struct rcbag_rec));
344 return 0;
347 /* Update the record referred to by cur to the value given. */
349 rcbagbt_update(
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. */
361 rcbagbt_insert(
362 struct xfs_btree_cur *cur,
363 const struct rcbag_rec *rec,
364 int *success)
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);