rtsummary_repair.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (c) 2020-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_btree.h"
  13. #include "xfs_log_format.h"
  14. #include "xfs_trans.h"
  15. #include "xfs_rtalloc.h"
  16. #include "xfs_inode.h"
  17. #include "xfs_bit.h"
  18. #include "xfs_bmap.h"
  19. #include "xfs_bmap_btree.h"
  20. #include "xfs_exchmaps.h"
  21. #include "xfs_rtbitmap.h"
  22. #include "scrub/scrub.h"
  23. #include "scrub/common.h"
  24. #include "scrub/trace.h"
  25. #include "scrub/repair.h"
  26. #include "scrub/tempfile.h"
  27. #include "scrub/tempexch.h"
  28. #include "scrub/reap.h"
  29. #include "scrub/xfile.h"
  30. #include "scrub/rtsummary.h"
  31. /* Set us up to repair the rtsummary file. */
  32. int
  33. xrep_setup_rtsummary(
  34. struct xfs_scrub *sc,
  35. struct xchk_rtsummary *rts)
  36. {
  37. struct xfs_mount *mp = sc->mp;
  38. unsigned long long blocks;
  39. int error;
  40. error = xrep_tempfile_create(sc, S_IFREG);
  41. if (error)
  42. return error;
  43. /*
  44. * If we're doing a repair, we reserve enough blocks to write out a
  45. * completely new summary file, plus twice as many blocks as we would
  46. * need if we can only allocate one block per data fork mapping. This
  47. * should cover the preallocation of the temporary file and exchanging
  48. * the extent mappings.
  49. *
  50. * We cannot use xfs_exchmaps_estimate because we have not yet
  51. * constructed the replacement rtsummary and therefore do not know how
  52. * many extents it will use. By the time we do, we will have a dirty
  53. * transaction (which we cannot drop because we cannot drop the
  54. * rtsummary ILOCK) and cannot ask for more reservation.
  55. */
  56. blocks = mp->m_rsumblocks;
  57. blocks += xfs_bmbt_calc_size(mp, blocks) * 2;
  58. if (blocks > UINT_MAX)
  59. return -EOPNOTSUPP;
  60. rts->resblks += blocks;
  61. return 0;
  62. }
  63. static int
  64. xrep_rtsummary_prep_buf(
  65. struct xfs_scrub *sc,
  66. struct xfs_buf *bp,
  67. void *data)
  68. {
  69. struct xchk_rtsummary *rts = data;
  70. struct xfs_mount *mp = sc->mp;
  71. union xfs_suminfo_raw *ondisk;
  72. int error;
  73. rts->args.mp = sc->mp;
  74. rts->args.tp = sc->tp;
  75. rts->args.sumbp = bp;
  76. ondisk = xfs_rsumblock_infoptr(&rts->args, 0);
  77. rts->args.sumbp = NULL;
  78. bp->b_ops = &xfs_rtbuf_ops;
  79. error = xfsum_copyout(sc, rts->prep_wordoff, ondisk, mp->m_blockwsize);
  80. if (error)
  81. return error;
  82. rts->prep_wordoff += mp->m_blockwsize;
  83. xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_RTSUMMARY_BUF);
  84. return 0;
  85. }
  86. /* Repair the realtime summary. */
  87. int
  88. xrep_rtsummary(
  89. struct xfs_scrub *sc)
  90. {
  91. struct xchk_rtsummary *rts = sc->buf;
  92. struct xfs_mount *mp = sc->mp;
  93. int error;
  94. /* We require the rmapbt to rebuild anything. */
  95. if (!xfs_has_rmapbt(mp))
  96. return -EOPNOTSUPP;
  97. /* We require atomic file exchange range to rebuild anything. */
  98. if (!xfs_has_exchange_range(mp))
  99. return -EOPNOTSUPP;
  100. /* Walk away if we disagree on the size of the rt bitmap. */
  101. if (rts->rbmblocks != mp->m_sb.sb_rbmblocks)
  102. return 0;
  103. /* Make sure any problems with the fork are fixed. */
  104. error = xrep_metadata_inode_forks(sc);
  105. if (error)
  106. return error;
  107. /*
  108. * Try to take ILOCK_EXCL of the temporary file. We had better be the
  109. * only ones holding onto this inode, but we can't block while holding
  110. * the rtsummary file's ILOCK_EXCL.
  111. */
  112. while (!xrep_tempfile_ilock_nowait(sc)) {
  113. if (xchk_should_terminate(sc, &error))
  114. return error;
  115. delay(1);
  116. }
  117. /* Make sure we have space allocated for the entire summary file. */
  118. xfs_trans_ijoin(sc->tp, sc->ip, 0);
  119. xfs_trans_ijoin(sc->tp, sc->tempip, 0);
  120. error = xrep_tempfile_prealloc(sc, 0, rts->rsumblocks);
  121. if (error)
  122. return error;
  123. /* Last chance to abort before we start committing fixes. */
  124. if (xchk_should_terminate(sc, &error))
  125. return error;
  126. /* Copy the rtsummary file that we generated. */
  127. error = xrep_tempfile_copyin(sc, 0, rts->rsumblocks,
  128. xrep_rtsummary_prep_buf, rts);
  129. if (error)
  130. return error;
  131. error = xrep_tempfile_set_isize(sc, XFS_FSB_TO_B(mp, rts->rsumblocks));
  132. if (error)
  133. return error;
  134. /*
  135. * Now exchange the contents. Nothing in repair uses the temporary
  136. * buffer, so we can reuse it for the tempfile exchrange information.
  137. */
  138. error = xrep_tempexch_trans_reserve(sc, XFS_DATA_FORK, &rts->tempexch);
  139. if (error)
  140. return error;
  141. error = xrep_tempexch_contents(sc, &rts->tempexch);
  142. if (error)
  143. return error;
  144. /* Reset incore state and blow out the summary cache. */
  145. if (mp->m_rsum_cache)
  146. memset(mp->m_rsum_cache, 0xFF, mp->m_sb.sb_rbmblocks);
  147. mp->m_rsumlevels = rts->rsumlevels;
  148. mp->m_rsumblocks = rts->rsumblocks;
  149. /* Free the old rtsummary blocks if they're not in use. */
  150. return xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK);
  151. }