rcbag.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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_log_format.h"
  11. #include "xfs_trans.h"
  12. #include "xfs_trans_resv.h"
  13. #include "xfs_mount.h"
  14. #include "xfs_defer.h"
  15. #include "xfs_btree.h"
  16. #include "xfs_buf_mem.h"
  17. #include "xfs_btree_mem.h"
  18. #include "xfs_error.h"
  19. #include "scrub/scrub.h"
  20. #include "scrub/rcbag_btree.h"
  21. #include "scrub/rcbag.h"
  22. #include "scrub/trace.h"
  23. struct rcbag {
  24. struct xfs_mount *mp;
  25. struct xfbtree xfbtree;
  26. uint64_t nr_items;
  27. };
  28. int
  29. rcbag_init(
  30. struct xfs_mount *mp,
  31. struct xfs_buftarg *btp,
  32. struct rcbag **bagp)
  33. {
  34. struct rcbag *bag;
  35. int error;
  36. bag = kzalloc(sizeof(struct rcbag), XCHK_GFP_FLAGS);
  37. if (!bag)
  38. return -ENOMEM;
  39. bag->nr_items = 0;
  40. bag->mp = mp;
  41. error = rcbagbt_mem_init(mp, &bag->xfbtree, btp);
  42. if (error)
  43. goto out_bag;
  44. *bagp = bag;
  45. return 0;
  46. out_bag:
  47. kfree(bag);
  48. return error;
  49. }
  50. void
  51. rcbag_free(
  52. struct rcbag **bagp)
  53. {
  54. struct rcbag *bag = *bagp;
  55. xfbtree_destroy(&bag->xfbtree);
  56. kfree(bag);
  57. *bagp = NULL;
  58. }
  59. /* Track an rmap in the refcount bag. */
  60. int
  61. rcbag_add(
  62. struct rcbag *bag,
  63. struct xfs_trans *tp,
  64. const struct xfs_rmap_irec *rmap)
  65. {
  66. struct rcbag_rec bagrec;
  67. struct xfs_mount *mp = bag->mp;
  68. struct xfs_btree_cur *cur;
  69. int has;
  70. int error;
  71. cur = rcbagbt_mem_cursor(mp, tp, &bag->xfbtree);
  72. error = rcbagbt_lookup_eq(cur, rmap, &has);
  73. if (error)
  74. goto out_cur;
  75. if (has) {
  76. error = rcbagbt_get_rec(cur, &bagrec, &has);
  77. if (error)
  78. goto out_cur;
  79. if (!has) {
  80. error = -EFSCORRUPTED;
  81. goto out_cur;
  82. }
  83. bagrec.rbg_refcount++;
  84. error = rcbagbt_update(cur, &bagrec);
  85. if (error)
  86. goto out_cur;
  87. } else {
  88. bagrec.rbg_startblock = rmap->rm_startblock;
  89. bagrec.rbg_blockcount = rmap->rm_blockcount;
  90. bagrec.rbg_refcount = 1;
  91. error = rcbagbt_insert(cur, &bagrec, &has);
  92. if (error)
  93. goto out_cur;
  94. if (!has) {
  95. error = -EFSCORRUPTED;
  96. goto out_cur;
  97. }
  98. }
  99. xfs_btree_del_cursor(cur, 0);
  100. error = xfbtree_trans_commit(&bag->xfbtree, tp);
  101. if (error)
  102. return error;
  103. bag->nr_items++;
  104. return 0;
  105. out_cur:
  106. xfs_btree_del_cursor(cur, error);
  107. xfbtree_trans_cancel(&bag->xfbtree, tp);
  108. return error;
  109. }
  110. /* Return the number of records in the bag. */
  111. uint64_t
  112. rcbag_count(
  113. const struct rcbag *rcbag)
  114. {
  115. return rcbag->nr_items;
  116. }
  117. static inline uint32_t rcbag_rec_next_bno(const struct rcbag_rec *r)
  118. {
  119. return r->rbg_startblock + r->rbg_blockcount;
  120. }
  121. /*
  122. * Find the next block where the refcount changes, given the next rmap we
  123. * looked at and the ones we're already tracking.
  124. */
  125. int
  126. rcbag_next_edge(
  127. struct rcbag *bag,
  128. struct xfs_trans *tp,
  129. const struct xfs_rmap_irec *next_rmap,
  130. bool next_valid,
  131. uint32_t *next_bnop)
  132. {
  133. struct rcbag_rec bagrec;
  134. struct xfs_mount *mp = bag->mp;
  135. struct xfs_btree_cur *cur;
  136. uint32_t next_bno = NULLAGBLOCK;
  137. int has;
  138. int error;
  139. if (next_valid)
  140. next_bno = next_rmap->rm_startblock;
  141. cur = rcbagbt_mem_cursor(mp, tp, &bag->xfbtree);
  142. error = xfs_btree_goto_left_edge(cur);
  143. if (error)
  144. goto out_cur;
  145. while (true) {
  146. error = xfs_btree_increment(cur, 0, &has);
  147. if (error)
  148. goto out_cur;
  149. if (!has)
  150. break;
  151. error = rcbagbt_get_rec(cur, &bagrec, &has);
  152. if (error)
  153. goto out_cur;
  154. if (!has) {
  155. error = -EFSCORRUPTED;
  156. goto out_cur;
  157. }
  158. next_bno = min(next_bno, rcbag_rec_next_bno(&bagrec));
  159. }
  160. /*
  161. * We should have found /something/ because either next_rrm is the next
  162. * interesting rmap to look at after emitting this refcount extent, or
  163. * there are other rmaps in rmap_bag contributing to the current
  164. * sharing count. But if something is seriously wrong, bail out.
  165. */
  166. if (next_bno == NULLAGBLOCK) {
  167. error = -EFSCORRUPTED;
  168. goto out_cur;
  169. }
  170. xfs_btree_del_cursor(cur, 0);
  171. *next_bnop = next_bno;
  172. return 0;
  173. out_cur:
  174. xfs_btree_del_cursor(cur, error);
  175. return error;
  176. }
  177. /* Pop all refcount bag records that end at next_bno */
  178. int
  179. rcbag_remove_ending_at(
  180. struct rcbag *bag,
  181. struct xfs_trans *tp,
  182. uint32_t next_bno)
  183. {
  184. struct rcbag_rec bagrec;
  185. struct xfs_mount *mp = bag->mp;
  186. struct xfs_btree_cur *cur;
  187. int has;
  188. int error;
  189. /* go to the right edge of the tree */
  190. cur = rcbagbt_mem_cursor(mp, tp, &bag->xfbtree);
  191. memset(&cur->bc_rec, 0xFF, sizeof(cur->bc_rec));
  192. error = xfs_btree_lookup(cur, XFS_LOOKUP_GE, &has);
  193. if (error)
  194. goto out_cur;
  195. while (true) {
  196. error = xfs_btree_decrement(cur, 0, &has);
  197. if (error)
  198. goto out_cur;
  199. if (!has)
  200. break;
  201. error = rcbagbt_get_rec(cur, &bagrec, &has);
  202. if (error)
  203. goto out_cur;
  204. if (!has) {
  205. error = -EFSCORRUPTED;
  206. goto out_cur;
  207. }
  208. if (rcbag_rec_next_bno(&bagrec) != next_bno)
  209. continue;
  210. error = xfs_btree_delete(cur, &has);
  211. if (error)
  212. goto out_cur;
  213. if (!has) {
  214. error = -EFSCORRUPTED;
  215. goto out_cur;
  216. }
  217. bag->nr_items -= bagrec.rbg_refcount;
  218. }
  219. xfs_btree_del_cursor(cur, 0);
  220. return xfbtree_trans_commit(&bag->xfbtree, tp);
  221. out_cur:
  222. xfs_btree_del_cursor(cur, error);
  223. xfbtree_trans_cancel(&bag->xfbtree, tp);
  224. return error;
  225. }
  226. /* Dump the rcbag. */
  227. void
  228. rcbag_dump(
  229. struct rcbag *bag,
  230. struct xfs_trans *tp)
  231. {
  232. struct rcbag_rec bagrec;
  233. struct xfs_mount *mp = bag->mp;
  234. struct xfs_btree_cur *cur;
  235. unsigned long long nr = 0;
  236. int has;
  237. int error;
  238. cur = rcbagbt_mem_cursor(mp, tp, &bag->xfbtree);
  239. error = xfs_btree_goto_left_edge(cur);
  240. if (error)
  241. goto out_cur;
  242. while (true) {
  243. error = xfs_btree_increment(cur, 0, &has);
  244. if (error)
  245. goto out_cur;
  246. if (!has)
  247. break;
  248. error = rcbagbt_get_rec(cur, &bagrec, &has);
  249. if (error)
  250. goto out_cur;
  251. if (!has) {
  252. error = -EFSCORRUPTED;
  253. goto out_cur;
  254. }
  255. xfs_err(bag->mp, "[%llu]: bno 0x%x fsbcount 0x%x refcount 0x%llx\n",
  256. nr++,
  257. (unsigned int)bagrec.rbg_startblock,
  258. (unsigned int)bagrec.rbg_blockcount,
  259. (unsigned long long)bagrec.rbg_refcount);
  260. }
  261. out_cur:
  262. xfs_btree_del_cursor(cur, error);
  263. }