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 = mp->m_rsumblocks; 60 blocks += xfs_bmbt_calc_size(mp, blocks) * 2; 61 if (blocks > UINT_MAX) 62 return -EOPNOTSUPP; 63 64 rts->resblks += blocks; 65 return 0; 66 } 67 68 static int 69 xrep_rtsummary_prep_buf( 70 struct xfs_scrub *sc, 71 struct xfs_buf *bp, 72 void *data) 73 { 74 struct xchk_rtsummary *rts = data; 75 struct xfs_mount *mp = sc->mp; 76 union xfs_suminfo_raw *ondisk; 77 int error; 78 79 rts->args.mp = mp; 80 rts->args.tp = sc->tp; 81 rts->args.rtg = sc->sr.rtg; 82 rts->args.sumbp = bp; 83 ondisk = xfs_rsumblock_infoptr(&rts->args, 0); 84 rts->args.sumbp = NULL; 85 86 error = xfsum_copyout(sc, rts->prep_wordoff, ondisk, mp->m_blockwsize); 87 if (error) 88 return error; 89 90 if (xfs_has_rtgroups(sc->mp)) { 91 struct xfs_rtbuf_blkinfo *hdr = bp->b_addr; 92 93 hdr->rt_magic = cpu_to_be32(XFS_RTSUMMARY_MAGIC); 94 hdr->rt_owner = cpu_to_be64(sc->ip->i_ino); 95 hdr->rt_blkno = cpu_to_be64(xfs_buf_daddr(bp)); 96 hdr->rt_lsn = 0; 97 uuid_copy(&hdr->rt_uuid, &sc->mp->m_sb.sb_meta_uuid); 98 bp->b_ops = &xfs_rtsummary_buf_ops; 99 } else { 100 bp->b_ops = &xfs_rtbuf_ops; 101 } 102 103 rts->prep_wordoff += mp->m_blockwsize; 104 xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_RTSUMMARY_BUF); 105 return 0; 106 } 107 108 /* Repair the realtime summary. */ 109 int 110 xrep_rtsummary( 111 struct xfs_scrub *sc) 112 { 113 struct xchk_rtsummary *rts = sc->buf; 114 struct xfs_mount *mp = sc->mp; 115 int error; 116 117 /* We require the rmapbt to rebuild anything. */ 118 if (!xfs_has_rmapbt(mp)) 119 return -EOPNOTSUPP; 120 /* We require atomic file exchange range to rebuild anything. */ 121 if (!xfs_has_exchange_range(mp)) 122 return -EOPNOTSUPP; 123 124 /* Walk away if we disagree on the size of the rt bitmap. */ 125 if (rts->rbmblocks != mp->m_sb.sb_rbmblocks) 126 return 0; 127 128 /* Make sure any problems with the fork are fixed. */ 129 error = xrep_metadata_inode_forks(sc); 130 if (error) 131 return error; 132 133 /* 134 * Try to take ILOCK_EXCL of the temporary file. We had better be the 135 * only ones holding onto this inode, but we can't block while holding 136 * the rtsummary file's ILOCK_EXCL. 137 */ 138 while (!xrep_tempfile_ilock_nowait(sc)) { 139 if (xchk_should_terminate(sc, &error)) 140 return error; 141 delay(1); 142 } 143 144 /* Make sure we have space allocated for the entire summary file. */ 145 xfs_trans_ijoin(sc->tp, sc->ip, 0); 146 xfs_trans_ijoin(sc->tp, sc->tempip, 0); 147 error = xrep_tempfile_prealloc(sc, 0, rts->rsumblocks); 148 if (error) 149 return error; 150 151 /* Last chance to abort before we start committing fixes. */ 152 if (xchk_should_terminate(sc, &error)) 153 return error; 154 155 /* Copy the rtsummary file that we generated. */ 156 error = xrep_tempfile_copyin(sc, 0, rts->rsumblocks, 157 xrep_rtsummary_prep_buf, rts); 158 if (error) 159 return error; 160 error = xrep_tempfile_set_isize(sc, XFS_FSB_TO_B(mp, rts->rsumblocks)); 161 if (error) 162 return error; 163 164 /* 165 * Now exchange the contents. Nothing in repair uses the temporary 166 * buffer, so we can reuse it for the tempfile exchrange information. 167 */ 168 error = xrep_tempexch_trans_reserve(sc, XFS_DATA_FORK, &rts->tempexch); 169 if (error) 170 return error; 171 172 error = xrep_tempexch_contents(sc, &rts->tempexch); 173 if (error) 174 return error; 175 176 /* Reset incore state and blow out the summary cache. */ 177 if (sc->sr.rtg->rtg_rsum_cache) 178 memset(sc->sr.rtg->rtg_rsum_cache, 0xFF, mp->m_sb.sb_rbmblocks); 179 180 mp->m_rsumlevels = rts->rsumlevels; 181 mp->m_rsumblocks = rts->rsumblocks; 182 183 /* Free the old rtsummary blocks if they're not in use. */ 184 return xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK); 185 } 186