rcbag_btree.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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"
  19. static struct kmem_cache *rcbagbt_cur_cache;
  20. STATIC void
  21. rcbagbt_init_key_from_rec(
  22. union xfs_btree_key *key,
  23. const union xfs_btree_rec *rec)
  24. {
  25. struct rcbag_key *bag_key = (struct rcbag_key *)key;
  26. const struct rcbag_rec *bag_rec = (const struct rcbag_rec *)rec;
  27. BUILD_BUG_ON(sizeof(struct rcbag_key) > sizeof(union xfs_btree_key));
  28. BUILD_BUG_ON(sizeof(struct rcbag_rec) > sizeof(union xfs_btree_rec));
  29. bag_key->rbg_startblock = bag_rec->rbg_startblock;
  30. bag_key->rbg_blockcount = bag_rec->rbg_blockcount;
  31. }
  32. STATIC void
  33. rcbagbt_init_rec_from_cur(
  34. struct xfs_btree_cur *cur,
  35. union xfs_btree_rec *rec)
  36. {
  37. struct rcbag_rec *bag_rec = (struct rcbag_rec *)rec;
  38. struct rcbag_rec *bag_irec = (struct rcbag_rec *)&cur->bc_rec;
  39. bag_rec->rbg_startblock = bag_irec->rbg_startblock;
  40. bag_rec->rbg_blockcount = bag_irec->rbg_blockcount;
  41. bag_rec->rbg_refcount = bag_irec->rbg_refcount;
  42. }
  43. STATIC int64_t
  44. rcbagbt_key_diff(
  45. struct xfs_btree_cur *cur,
  46. const union xfs_btree_key *key)
  47. {
  48. struct rcbag_rec *rec = (struct rcbag_rec *)&cur->bc_rec;
  49. const struct rcbag_key *kp = (const struct rcbag_key *)key;
  50. if (kp->rbg_startblock > rec->rbg_startblock)
  51. return 1;
  52. if (kp->rbg_startblock < rec->rbg_startblock)
  53. return -1;
  54. if (kp->rbg_blockcount > rec->rbg_blockcount)
  55. return 1;
  56. if (kp->rbg_blockcount < rec->rbg_blockcount)
  57. return -1;
  58. return 0;
  59. }
  60. STATIC int64_t
  61. rcbagbt_diff_two_keys(
  62. struct xfs_btree_cur *cur,
  63. const union xfs_btree_key *k1,
  64. const union xfs_btree_key *k2,
  65. const union xfs_btree_key *mask)
  66. {
  67. const struct rcbag_key *kp1 = (const struct rcbag_key *)k1;
  68. const struct rcbag_key *kp2 = (const struct rcbag_key *)k2;
  69. ASSERT(mask == NULL);
  70. if (kp1->rbg_startblock > kp2->rbg_startblock)
  71. return 1;
  72. if (kp1->rbg_startblock < kp2->rbg_startblock)
  73. return -1;
  74. if (kp1->rbg_blockcount > kp2->rbg_blockcount)
  75. return 1;
  76. if (kp1->rbg_blockcount < kp2->rbg_blockcount)
  77. return -1;
  78. return 0;
  79. }
  80. STATIC int
  81. rcbagbt_keys_inorder(
  82. struct xfs_btree_cur *cur,
  83. const union xfs_btree_key *k1,
  84. const union xfs_btree_key *k2)
  85. {
  86. const struct rcbag_key *kp1 = (const struct rcbag_key *)k1;
  87. const struct rcbag_key *kp2 = (const struct rcbag_key *)k2;
  88. if (kp1->rbg_startblock > kp2->rbg_startblock)
  89. return 0;
  90. if (kp1->rbg_startblock < kp2->rbg_startblock)
  91. return 1;
  92. if (kp1->rbg_blockcount > kp2->rbg_blockcount)
  93. return 0;
  94. if (kp1->rbg_blockcount < kp2->rbg_blockcount)
  95. return 1;
  96. return 0;
  97. }
  98. STATIC int
  99. rcbagbt_recs_inorder(
  100. struct xfs_btree_cur *cur,
  101. const union xfs_btree_rec *r1,
  102. const union xfs_btree_rec *r2)
  103. {
  104. const struct rcbag_rec *rp1 = (const struct rcbag_rec *)r1;
  105. const struct rcbag_rec *rp2 = (const struct rcbag_rec *)r2;
  106. if (rp1->rbg_startblock > rp2->rbg_startblock)
  107. return 0;
  108. if (rp1->rbg_startblock < rp2->rbg_startblock)
  109. return 1;
  110. if (rp1->rbg_blockcount > rp2->rbg_blockcount)
  111. return 0;
  112. if (rp1->rbg_blockcount < rp2->rbg_blockcount)
  113. return 1;
  114. return 0;
  115. }
  116. static xfs_failaddr_t
  117. rcbagbt_verify(
  118. struct xfs_buf *bp)
  119. {
  120. struct xfs_mount *mp = bp->b_mount;
  121. struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
  122. xfs_failaddr_t fa;
  123. unsigned int level;
  124. unsigned int maxrecs;
  125. if (!xfs_verify_magic(bp, block->bb_magic))
  126. return __this_address;
  127. fa = xfs_btree_fsblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN);
  128. if (fa)
  129. return fa;
  130. level = be16_to_cpu(block->bb_level);
  131. if (level >= rcbagbt_maxlevels_possible())
  132. return __this_address;
  133. maxrecs = rcbagbt_maxrecs(mp, XFBNO_BLOCKSIZE, level == 0);
  134. return xfs_btree_memblock_verify(bp, maxrecs);
  135. }
  136. static void
  137. rcbagbt_rw_verify(
  138. struct xfs_buf *bp)
  139. {
  140. xfs_failaddr_t fa = rcbagbt_verify(bp);
  141. if (fa)
  142. xfs_verifier_error(bp, -EFSCORRUPTED, fa);
  143. }
  144. /* skip crc checks on in-memory btrees to save time */
  145. static const struct xfs_buf_ops rcbagbt_mem_buf_ops = {
  146. .name = "rcbagbt_mem",
  147. .magic = { 0, cpu_to_be32(RCBAG_MAGIC) },
  148. .verify_read = rcbagbt_rw_verify,
  149. .verify_write = rcbagbt_rw_verify,
  150. .verify_struct = rcbagbt_verify,
  151. };
  152. static const struct xfs_btree_ops rcbagbt_mem_ops = {
  153. .name = "rcbag",
  154. .type = XFS_BTREE_TYPE_MEM,
  155. .rec_len = sizeof(struct rcbag_rec),
  156. .key_len = sizeof(struct rcbag_key),
  157. .ptr_len = XFS_BTREE_LONG_PTR_LEN,
  158. .lru_refs = 1,
  159. .statoff = XFS_STATS_CALC_INDEX(xs_rcbag_2),
  160. .dup_cursor = xfbtree_dup_cursor,
  161. .set_root = xfbtree_set_root,
  162. .alloc_block = xfbtree_alloc_block,
  163. .free_block = xfbtree_free_block,
  164. .get_minrecs = xfbtree_get_minrecs,
  165. .get_maxrecs = xfbtree_get_maxrecs,
  166. .init_key_from_rec = rcbagbt_init_key_from_rec,
  167. .init_rec_from_cur = rcbagbt_init_rec_from_cur,
  168. .init_ptr_from_cur = xfbtree_init_ptr_from_cur,
  169. .key_diff = rcbagbt_key_diff,
  170. .buf_ops = &rcbagbt_mem_buf_ops,
  171. .diff_two_keys = rcbagbt_diff_two_keys,
  172. .keys_inorder = rcbagbt_keys_inorder,
  173. .recs_inorder = rcbagbt_recs_inorder,
  174. };
  175. /* Create a cursor for an in-memory btree. */
  176. struct xfs_btree_cur *
  177. rcbagbt_mem_cursor(
  178. struct xfs_mount *mp,
  179. struct xfs_trans *tp,
  180. struct xfbtree *xfbtree)
  181. {
  182. struct xfs_btree_cur *cur;
  183. cur = xfs_btree_alloc_cursor(mp, tp, &rcbagbt_mem_ops,
  184. rcbagbt_maxlevels_possible(), rcbagbt_cur_cache);
  185. cur->bc_mem.xfbtree = xfbtree;
  186. cur->bc_nlevels = xfbtree->nlevels;
  187. return cur;
  188. }
  189. /* Create an in-memory refcount bag btree. */
  190. int
  191. rcbagbt_mem_init(
  192. struct xfs_mount *mp,
  193. struct xfbtree *xfbt,
  194. struct xfs_buftarg *btp)
  195. {
  196. xfbt->owner = 0;
  197. return xfbtree_init(mp, xfbt, btp, &rcbagbt_mem_ops);
  198. }
  199. /* Calculate number of records in a refcount bag btree block. */
  200. static inline unsigned int
  201. rcbagbt_block_maxrecs(
  202. unsigned int blocklen,
  203. bool leaf)
  204. {
  205. if (leaf)
  206. return blocklen / sizeof(struct rcbag_rec);
  207. return blocklen /
  208. (sizeof(struct rcbag_key) + sizeof(rcbag_ptr_t));
  209. }
  210. /*
  211. * Calculate number of records in an refcount bag btree block.
  212. */
  213. unsigned int
  214. rcbagbt_maxrecs(
  215. struct xfs_mount *mp,
  216. unsigned int blocklen,
  217. bool leaf)
  218. {
  219. blocklen -= RCBAG_BLOCK_LEN;
  220. return rcbagbt_block_maxrecs(blocklen, leaf);
  221. }
  222. /* Compute the max possible height for refcount bag btrees. */
  223. unsigned int
  224. rcbagbt_maxlevels_possible(void)
  225. {
  226. unsigned int minrecs[2];
  227. unsigned int blocklen;
  228. blocklen = XFBNO_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;
  229. minrecs[0] = rcbagbt_block_maxrecs(blocklen, true) / 2;
  230. minrecs[1] = rcbagbt_block_maxrecs(blocklen, false) / 2;
  231. return xfs_btree_space_to_height(minrecs, ULLONG_MAX);
  232. }
  233. /* Calculate the refcount bag btree size for some records. */
  234. unsigned long long
  235. rcbagbt_calc_size(
  236. unsigned long long nr_records)
  237. {
  238. unsigned int minrecs[2];
  239. unsigned int blocklen;
  240. blocklen = XFBNO_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;
  241. minrecs[0] = rcbagbt_block_maxrecs(blocklen, true) / 2;
  242. minrecs[1] = rcbagbt_block_maxrecs(blocklen, false) / 2;
  243. return xfs_btree_calc_size(minrecs, nr_records);
  244. }
  245. int __init
  246. rcbagbt_init_cur_cache(void)
  247. {
  248. rcbagbt_cur_cache = kmem_cache_create("xfs_rcbagbt_cur",
  249. xfs_btree_cur_sizeof(rcbagbt_maxlevels_possible()),
  250. 0, 0, NULL);
  251. if (!rcbagbt_cur_cache)
  252. return -ENOMEM;
  253. return 0;
  254. }
  255. void
  256. rcbagbt_destroy_cur_cache(void)
  257. {
  258. kmem_cache_destroy(rcbagbt_cur_cache);
  259. rcbagbt_cur_cache = NULL;
  260. }
  261. /* Look up the refcount bag record corresponding to this reverse mapping. */
  262. int
  263. rcbagbt_lookup_eq(
  264. struct xfs_btree_cur *cur,
  265. const struct xfs_rmap_irec *rmap,
  266. int *success)
  267. {
  268. struct rcbag_rec *rec = (struct rcbag_rec *)&cur->bc_rec;
  269. rec->rbg_startblock = rmap->rm_startblock;
  270. rec->rbg_blockcount = rmap->rm_blockcount;
  271. return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, success);
  272. }
  273. /* Get the data from the pointed-to record. */
  274. int
  275. rcbagbt_get_rec(
  276. struct xfs_btree_cur *cur,
  277. struct rcbag_rec *rec,
  278. int *has)
  279. {
  280. union xfs_btree_rec *btrec;
  281. int error;
  282. error = xfs_btree_get_rec(cur, &btrec, has);
  283. if (error || !(*has))
  284. return error;
  285. memcpy(rec, btrec, sizeof(struct rcbag_rec));
  286. return 0;
  287. }
  288. /* Update the record referred to by cur to the value given. */
  289. int
  290. rcbagbt_update(
  291. struct xfs_btree_cur *cur,
  292. const struct rcbag_rec *rec)
  293. {
  294. union xfs_btree_rec btrec;
  295. memcpy(&btrec, rec, sizeof(struct rcbag_rec));
  296. return xfs_btree_update(cur, &btrec);
  297. }
  298. /* Update the record referred to by cur to the value given. */
  299. int
  300. rcbagbt_insert(
  301. struct xfs_btree_cur *cur,
  302. const struct rcbag_rec *rec,
  303. int *success)
  304. {
  305. struct rcbag_rec *btrec = (struct rcbag_rec *)&cur->bc_rec;
  306. memcpy(btrec, rec, sizeof(struct rcbag_rec));
  307. return xfs_btree_insert(cur, success);
  308. }