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 32 /* Set us up to repair the rtsummary file. */ 33 int 34 xrep_setup_rtsummary( 35 struct xfs_scrub *sc, 36 struct xchk_rtsummary *rts) 37 { 38 struct xfs_mount *mp = sc->mp; 39 unsigned long long blocks; 40 int error; 41 42 error = xrep_tempfile_create(sc, S_IFREG); 43 if (error) 44 return error; 45 46 /* 47 * If we're doing a repair, we reserve enough blocks to write out a 48 * completely new summary file, plus twice as many blocks as we would 49 * need if we can only allocate one block per data fork mapping. This 50 * should cover the preallocation of the temporary file and exchanging 51 * the extent mappings. 52 * 53 * We cannot use xfs_exchmaps_estimate because we have not yet 54 * constructed the replacement rtsummary and therefore do not know how 55 * many extents it will use. By the time we do, we will have a dirty 56 * transaction (which we cannot drop because we cannot drop the 57 * rtsummary ILOCK) and cannot ask for more reservation. 58 */ 59 blocks = XFS_B_TO_FSB(mp, mp->m_rsumsize); 60 blocks += xfs_bmbt_calc_size(mp, blocks) * 2; 61 if (blocks > UINT_MAX) 62 return -EOPNOTSUPP; 63 64 rts->resblks += blocks; 65 66 /* 67 * Grab support for atomic file content exchanges before we allocate 68 * any transactions or grab ILOCKs. 69 */ 70 return xrep_tempexch_enable(sc); 71 } 72 73 static int 74 xrep_rtsummary_prep_buf( 75 struct xfs_scrub *sc, 76 struct xfs_buf *bp, 77 void *data) 78 { 79 struct xchk_rtsummary *rts = data; 80 struct xfs_mount *mp = sc->mp; 81 union xfs_suminfo_raw *ondisk; 82 int error; 83 84 rts->args.mp = sc->mp; 85 rts->args.tp = sc->tp; 86 rts->args.sumbp = bp; 87 ondisk = xfs_rsumblock_infoptr(&rts->args, 0); 88 rts->args.sumbp = NULL; 89 90 bp->b_ops = &xfs_rtbuf_ops; 91 92 error = xfsum_copyout(sc, rts->prep_wordoff, ondisk, mp->m_blockwsize); 93 if (error) 94 return error; 95 96 rts->prep_wordoff += mp->m_blockwsize; 97 xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_RTSUMMARY_BUF); 98 return 0; 99 } 100 101 /* Repair the realtime summary. */ 102 int 103 xrep_rtsummary( 104 struct xfs_scrub *sc) 105 { 106 struct xchk_rtsummary *rts = sc->buf; 107 struct xfs_mount *mp = sc->mp; 108 xfs_filblks_t rsumblocks; 109 int error; 110 111 /* We require the rmapbt to rebuild anything. */ 112 if (!xfs_has_rmapbt(mp)) 113 return -EOPNOTSUPP; 114 115 /* Walk away if we disagree on the size of the rt bitmap. */ 116 if (rts->rbmblocks != mp->m_sb.sb_rbmblocks) 117 return 0; 118 119 /* Make sure any problems with the fork are fixed. */ 120 error = xrep_metadata_inode_forks(sc); 121 if (error) 122 return error; 123 124 /* 125 * Try to take ILOCK_EXCL of the temporary file. We had better be the 126 * only ones holding onto this inode, but we can't block while holding 127 * the rtsummary file's ILOCK_EXCL. 128 */ 129 while (!xrep_tempfile_ilock_nowait(sc)) { 130 if (xchk_should_terminate(sc, &error)) 131 return error; 132 delay(1); 133 } 134 135 /* Make sure we have space allocated for the entire summary file. */ 136 rsumblocks = XFS_B_TO_FSB(mp, rts->rsumsize); 137 xfs_trans_ijoin(sc->tp, sc->ip, 0); 138 xfs_trans_ijoin(sc->tp, sc->tempip, 0); 139 error = xrep_tempfile_prealloc(sc, 0, rsumblocks); 140 if (error) 141 return error; 142 143 /* Last chance to abort before we start committing fixes. */ 144 if (xchk_should_terminate(sc, &error)) 145 return error; 146 147 /* Copy the rtsummary file that we generated. */ 148 error = xrep_tempfile_copyin(sc, 0, rsumblocks, 149 xrep_rtsummary_prep_buf, rts); 150 if (error) 151 return error; 152 error = xrep_tempfile_set_isize(sc, rts->rsumsize); 153 if (error) 154 return error; 155 156 /* 157 * Now exchange the contents. Nothing in repair uses the temporary 158 * buffer, so we can reuse it for the tempfile exchrange information. 159 */ 160 error = xrep_tempexch_trans_reserve(sc, XFS_DATA_FORK, &rts->tempexch); 161 if (error) 162 return error; 163 164 error = xrep_tempexch_contents(sc, &rts->tempexch); 165 if (error) 166 return error; 167 168 /* Reset incore state and blow out the summary cache. */ 169 if (mp->m_rsum_cache) 170 memset(mp->m_rsum_cache, 0xFF, mp->m_sb.sb_rbmblocks); 171 172 mp->m_rsumlevels = rts->rsumlevels; 173 mp->m_rsumsize = rts->rsumsize; 174 175 /* Free the old rtsummary blocks if they're not in use. */ 176 return xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK); 177 } 178