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.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_inode.h" 14 #include "xfs_log_format.h" 15 #include "xfs_trans.h" 16 #include "xfs_rtbitmap.h" 17 #include "xfs_bit.h" 18 #include "xfs_bmap.h" 19 #include "xfs_sb.h" 20 #include "scrub/scrub.h" 21 #include "scrub/common.h" 22 #include "scrub/trace.h" 23 #include "scrub/xfile.h" 24 25 /* 26 * Realtime Summary 27 * ================ 28 * 29 * We check the realtime summary by scanning the realtime bitmap file to create 30 * a new summary file incore, and then we compare the computed version against 31 * the ondisk version. We use the 'xfile' functionality to store this 32 * (potentially large) amount of data in pageable memory. 33 */ 34 35 /* Set us up to check the rtsummary file. */ 36 int 37 xchk_setup_rtsummary( 38 struct xfs_scrub *sc) 39 { 40 struct xfs_mount *mp = sc->mp; 41 char *descr; 42 int error; 43 44 /* 45 * Create an xfile to construct a new rtsummary file. The xfile allows 46 * us to avoid pinning kernel memory for this purpose. 47 */ 48 descr = xchk_xfile_descr(sc, "realtime summary file"); 49 error = xfile_create(descr, mp->m_rsumsize, &sc->xfile); 50 kfree(descr); 51 if (error) 52 return error; 53 54 error = xchk_trans_alloc(sc, 0); 55 if (error) 56 return error; 57 58 /* Allocate a memory buffer for the summary comparison. */ 59 sc->buf = kvmalloc(mp->m_sb.sb_blocksize, XCHK_GFP_FLAGS); 60 if (!sc->buf) 61 return -ENOMEM; 62 63 error = xchk_install_live_inode(sc, mp->m_rsumip); 64 if (error) 65 return error; 66 67 /* 68 * Locking order requires us to take the rtbitmap first. We must be 69 * careful to unlock it ourselves when we are done with the rtbitmap 70 * file since the scrub infrastructure won't do that for us. Only 71 * then we can lock the rtsummary inode. 72 */ 73 xfs_ilock(mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP); 74 xchk_ilock(sc, XFS_ILOCK_EXCL | XFS_ILOCK_RTSUM); 75 return 0; 76 } 77 78 /* Helper functions to record suminfo words in an xfile. */ 79 80 typedef unsigned int xchk_rtsumoff_t; 81 82 static inline int 83 xfsum_load( 84 struct xfs_scrub *sc, 85 xchk_rtsumoff_t sumoff, 86 xfs_suminfo_t *info) 87 { 88 return xfile_obj_load(sc->xfile, info, sizeof(xfs_suminfo_t), 89 sumoff << XFS_WORDLOG); 90 } 91 92 static inline int 93 xfsum_store( 94 struct xfs_scrub *sc, 95 xchk_rtsumoff_t sumoff, 96 const xfs_suminfo_t info) 97 { 98 return xfile_obj_store(sc->xfile, &info, sizeof(xfs_suminfo_t), 99 sumoff << XFS_WORDLOG); 100 } 101 102 static inline int 103 xfsum_copyout( 104 struct xfs_scrub *sc, 105 xchk_rtsumoff_t sumoff, 106 xfs_suminfo_t *info, 107 unsigned int nr_words) 108 { 109 return xfile_obj_load(sc->xfile, info, nr_words << XFS_WORDLOG, 110 sumoff << XFS_WORDLOG); 111 } 112 113 /* Update the summary file to reflect the free extent that we've accumulated. */ 114 STATIC int 115 xchk_rtsum_record_free( 116 struct xfs_mount *mp, 117 struct xfs_trans *tp, 118 const struct xfs_rtalloc_rec *rec, 119 void *priv) 120 { 121 struct xfs_scrub *sc = priv; 122 xfs_fileoff_t rbmoff; 123 xfs_rtblock_t rtbno; 124 xfs_filblks_t rtlen; 125 xchk_rtsumoff_t offs; 126 unsigned int lenlog; 127 xfs_suminfo_t v = 0; 128 int error = 0; 129 130 if (xchk_should_terminate(sc, &error)) 131 return error; 132 133 /* Compute the relevant location in the rtsum file. */ 134 rbmoff = XFS_BITTOBLOCK(mp, rec->ar_startext); 135 lenlog = XFS_RTBLOCKLOG(rec->ar_extcount); 136 offs = XFS_SUMOFFS(mp, lenlog, rbmoff); 137 138 rtbno = rec->ar_startext * mp->m_sb.sb_rextsize; 139 rtlen = rec->ar_extcount * mp->m_sb.sb_rextsize; 140 141 if (!xfs_verify_rtext(mp, rtbno, rtlen)) { 142 xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino); 143 return -EFSCORRUPTED; 144 } 145 146 /* Bump the summary count. */ 147 error = xfsum_load(sc, offs, &v); 148 if (error) 149 return error; 150 151 v++; 152 trace_xchk_rtsum_record_free(mp, rec->ar_startext, rec->ar_extcount, 153 lenlog, offs, v); 154 155 return xfsum_store(sc, offs, v); 156 } 157 158 /* Compute the realtime summary from the realtime bitmap. */ 159 STATIC int 160 xchk_rtsum_compute( 161 struct xfs_scrub *sc) 162 { 163 struct xfs_mount *mp = sc->mp; 164 unsigned long long rtbmp_bytes; 165 166 /* If the bitmap size doesn't match the computed size, bail. */ 167 rtbmp_bytes = howmany_64(mp->m_sb.sb_rextents, NBBY); 168 if (roundup_64(rtbmp_bytes, mp->m_sb.sb_blocksize) != 169 mp->m_rbmip->i_disk_size) 170 return -EFSCORRUPTED; 171 172 return xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtsum_record_free, 173 sc); 174 } 175 176 /* Compare the rtsummary file against the one we computed. */ 177 STATIC int 178 xchk_rtsum_compare( 179 struct xfs_scrub *sc) 180 { 181 struct xfs_mount *mp = sc->mp; 182 struct xfs_buf *bp; 183 struct xfs_bmbt_irec map; 184 xfs_fileoff_t off; 185 xchk_rtsumoff_t sumoff = 0; 186 int nmap; 187 188 for (off = 0; off < XFS_B_TO_FSB(mp, mp->m_rsumsize); off++) { 189 int error = 0; 190 191 if (xchk_should_terminate(sc, &error)) 192 return error; 193 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 194 return 0; 195 196 /* Make sure we have a written extent. */ 197 nmap = 1; 198 error = xfs_bmapi_read(mp->m_rsumip, off, 1, &map, &nmap, 199 XFS_DATA_FORK); 200 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error)) 201 return error; 202 203 if (nmap != 1 || !xfs_bmap_is_written_extent(&map)) { 204 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off); 205 return 0; 206 } 207 208 /* Read a block's worth of ondisk rtsummary file. */ 209 error = xfs_rtbuf_get(mp, sc->tp, off, 1, &bp); 210 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error)) 211 return error; 212 213 /* Read a block's worth of computed rtsummary file. */ 214 error = xfsum_copyout(sc, sumoff, sc->buf, mp->m_blockwsize); 215 if (error) { 216 xfs_trans_brelse(sc->tp, bp); 217 return error; 218 } 219 220 if (memcmp(bp->b_addr, sc->buf, 221 mp->m_blockwsize << XFS_WORDLOG) != 0) 222 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off); 223 224 xfs_trans_brelse(sc->tp, bp); 225 sumoff += mp->m_blockwsize; 226 } 227 228 return 0; 229 } 230 231 /* Scrub the realtime summary. */ 232 int 233 xchk_rtsummary( 234 struct xfs_scrub *sc) 235 { 236 struct xfs_mount *mp = sc->mp; 237 int error = 0; 238 239 /* Invoke the fork scrubber. */ 240 error = xchk_metadata_inode_forks(sc); 241 if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 242 goto out_rbm; 243 244 /* Construct the new summary file from the rtbitmap. */ 245 error = xchk_rtsum_compute(sc); 246 if (error == -EFSCORRUPTED) { 247 /* 248 * EFSCORRUPTED means the rtbitmap is corrupt, which is an xref 249 * error since we're checking the summary file. 250 */ 251 xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino); 252 error = 0; 253 goto out_rbm; 254 } 255 if (error) 256 goto out_rbm; 257 258 /* Does the computed summary file match the actual rtsummary file? */ 259 error = xchk_rtsum_compare(sc); 260 261 out_rbm: 262 /* Unlock the rtbitmap since we're done with it. */ 263 xfs_iunlock(mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP); 264 return error; 265 } 266