alloc.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2017-2023 Oracle. All Rights Reserved.
  4. * Author: Darrick J. Wong <djwong@kernel.org>
  5. */
  6. #include "xfs_platform.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_log_format.h"
  13. #include "xfs_trans.h"
  14. #include "xfs_btree.h"
  15. #include "xfs_alloc.h"
  16. #include "xfs_rmap.h"
  17. #include "xfs_ag.h"
  18. #include "scrub/scrub.h"
  19. #include "scrub/common.h"
  20. #include "scrub/btree.h"
  21. #include "scrub/repair.h"
  22. /*
  23. * Set us up to scrub free space btrees.
  24. */
  25. int
  26. xchk_setup_ag_allocbt(
  27. struct xfs_scrub *sc)
  28. {
  29. int error;
  30. if (xchk_need_intent_drain(sc))
  31. xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
  32. error = xchk_setup_ag_btree(sc, false);
  33. if (error)
  34. return error;
  35. if (xchk_could_repair(sc))
  36. return xrep_setup_ag_allocbt(sc);
  37. return 0;
  38. }
  39. /* Free space btree scrubber. */
  40. struct xchk_alloc {
  41. /* Previous free space extent. */
  42. struct xfs_alloc_rec_incore prev;
  43. };
  44. /*
  45. * Ensure there's a corresponding cntbt/bnobt record matching this
  46. * bnobt/cntbt record, respectively.
  47. */
  48. STATIC void
  49. xchk_allocbt_xref_other(
  50. struct xfs_scrub *sc,
  51. xfs_agblock_t agbno,
  52. xfs_extlen_t len)
  53. {
  54. struct xfs_btree_cur **pcur;
  55. xfs_agblock_t fbno;
  56. xfs_extlen_t flen;
  57. int has_otherrec;
  58. int error;
  59. if (sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT)
  60. pcur = &sc->sa.cnt_cur;
  61. else
  62. pcur = &sc->sa.bno_cur;
  63. if (!*pcur || xchk_skip_xref(sc->sm))
  64. return;
  65. error = xfs_alloc_lookup_le(*pcur, agbno, len, &has_otherrec);
  66. if (!xchk_should_check_xref(sc, &error, pcur))
  67. return;
  68. if (!has_otherrec) {
  69. xchk_btree_xref_set_corrupt(sc, *pcur, 0);
  70. return;
  71. }
  72. error = xfs_alloc_get_rec(*pcur, &fbno, &flen, &has_otherrec);
  73. if (!xchk_should_check_xref(sc, &error, pcur))
  74. return;
  75. if (!has_otherrec) {
  76. xchk_btree_xref_set_corrupt(sc, *pcur, 0);
  77. return;
  78. }
  79. if (fbno != agbno || flen != len)
  80. xchk_btree_xref_set_corrupt(sc, *pcur, 0);
  81. }
  82. /* Cross-reference with the other btrees. */
  83. STATIC void
  84. xchk_allocbt_xref(
  85. struct xfs_scrub *sc,
  86. const struct xfs_alloc_rec_incore *irec)
  87. {
  88. xfs_agblock_t agbno = irec->ar_startblock;
  89. xfs_extlen_t len = irec->ar_blockcount;
  90. if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
  91. return;
  92. xchk_allocbt_xref_other(sc, agbno, len);
  93. xchk_xref_is_not_inode_chunk(sc, agbno, len);
  94. xchk_xref_has_no_owner(sc, agbno, len);
  95. xchk_xref_is_not_shared(sc, agbno, len);
  96. xchk_xref_is_not_cow_staging(sc, agbno, len);
  97. }
  98. /* Flag failures for records that could be merged. */
  99. STATIC void
  100. xchk_allocbt_mergeable(
  101. struct xchk_btree *bs,
  102. struct xchk_alloc *ca,
  103. const struct xfs_alloc_rec_incore *irec)
  104. {
  105. if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
  106. return;
  107. if (ca->prev.ar_blockcount > 0 &&
  108. ca->prev.ar_startblock + ca->prev.ar_blockcount == irec->ar_startblock &&
  109. ca->prev.ar_blockcount + irec->ar_blockcount < (uint32_t)~0U)
  110. xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
  111. memcpy(&ca->prev, irec, sizeof(*irec));
  112. }
  113. /* Scrub a bnobt/cntbt record. */
  114. STATIC int
  115. xchk_allocbt_rec(
  116. struct xchk_btree *bs,
  117. const union xfs_btree_rec *rec)
  118. {
  119. struct xfs_alloc_rec_incore irec;
  120. struct xchk_alloc *ca = bs->private;
  121. xfs_alloc_btrec_to_irec(rec, &irec);
  122. if (xfs_alloc_check_irec(to_perag(bs->cur->bc_group), &irec) != NULL) {
  123. xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
  124. return 0;
  125. }
  126. xchk_allocbt_mergeable(bs, ca, &irec);
  127. xchk_allocbt_xref(bs->sc, &irec);
  128. return 0;
  129. }
  130. /* Scrub one of the freespace btrees for some AG. */
  131. int
  132. xchk_allocbt(
  133. struct xfs_scrub *sc)
  134. {
  135. struct xchk_alloc ca = { };
  136. struct xfs_btree_cur *cur;
  137. switch (sc->sm->sm_type) {
  138. case XFS_SCRUB_TYPE_BNOBT:
  139. cur = sc->sa.bno_cur;
  140. break;
  141. case XFS_SCRUB_TYPE_CNTBT:
  142. cur = sc->sa.cnt_cur;
  143. break;
  144. default:
  145. ASSERT(0);
  146. return -EIO;
  147. }
  148. return xchk_btree(sc, cur, xchk_allocbt_rec, &XFS_RMAP_OINFO_AG, &ca);
  149. }
  150. /* xref check that the extent is not free */
  151. void
  152. xchk_xref_is_used_space(
  153. struct xfs_scrub *sc,
  154. xfs_agblock_t agbno,
  155. xfs_extlen_t len)
  156. {
  157. enum xbtree_recpacking outcome;
  158. int error;
  159. if (!sc->sa.bno_cur || xchk_skip_xref(sc->sm))
  160. return;
  161. error = xfs_alloc_has_records(sc->sa.bno_cur, agbno, len, &outcome);
  162. if (!xchk_should_check_xref(sc, &error, &sc->sa.bno_cur))
  163. return;
  164. if (outcome != XBTREE_RECPACKING_EMPTY)
  165. xchk_btree_xref_set_corrupt(sc, sc->sa.bno_cur, 0);
  166. }