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 "scrub/scrub.h" 20 #include "scrub/common.h" 21 #include "scrub/trace.h" 22 #include "scrub/xfile.h" 23 24 /* 25 * Realtime Summary 26 * ================ 27 * 28 * We check the realtime summary by scanning the realtime bitmap file to create 29 * a new summary file incore, and then we compare the computed version against 30 * the ondisk version. We use the 'xfile' functionality to store this 31 * (potentially large) amount of data in pageable memory. 32 */ 33 34 struct xchk_rtsummary { 35 struct xfs_rtalloc_args args; 36 37 uint64_t rextents; 38 uint64_t rbmblocks; 39 uint64_t rsumsize; 40 unsigned int rsumlevels; 41 42 /* Memory buffer for the summary comparison. */ 43 union xfs_suminfo_raw words[]; 44 }; 45 46 /* Set us up to check the rtsummary file. */ 47 int 48 xchk_setup_rtsummary( 49 struct xfs_scrub *sc) 50 { 51 struct xfs_mount *mp = sc->mp; 52 char *descr; 53 struct xchk_rtsummary *rts; 54 int error; 55 56 rts = kvzalloc(struct_size(rts, words, mp->m_blockwsize), 57 XCHK_GFP_FLAGS); 58 if (!rts) 59 return -ENOMEM; 60 sc->buf = rts; 61 62 /* 63 * Create an xfile to construct a new rtsummary file. The xfile allows 64 * us to avoid pinning kernel memory for this purpose. 65 */ 66 descr = xchk_xfile_descr(sc, "realtime summary file"); 67 error = xfile_create(descr, mp->m_rsumsize, &sc->xfile); 68 kfree(descr); 69 if (error) 70 return error; 71 72 error = xchk_trans_alloc(sc, 0); 73 if (error) 74 return error; 75 76 error = xchk_install_live_inode(sc, mp->m_rsumip); 77 if (error) 78 return error; 79 80 error = xchk_ino_dqattach(sc); 81 if (error) 82 return error; 83 84 /* 85 * Locking order requires us to take the rtbitmap first. We must be 86 * careful to unlock it ourselves when we are done with the rtbitmap 87 * file since the scrub infrastructure won't do that for us. Only 88 * then we can lock the rtsummary inode. 89 */ 90 xfs_ilock(mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP); 91 xchk_ilock(sc, XFS_ILOCK_EXCL | XFS_ILOCK_RTSUM); 92 93 /* 94 * Now that we've locked the rtbitmap and rtsummary, we can't race with 95 * growfsrt trying to expand the summary or change the size of the rt 96 * volume. Hence it is safe to compute and check the geometry values. 97 */ 98 if (mp->m_sb.sb_rblocks) { 99 xfs_filblks_t rsumblocks; 100 int rextslog; 101 102 rts->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks); 103 rextslog = xfs_compute_rextslog(rts->rextents); 104 rts->rsumlevels = rextslog + 1; 105 rts->rbmblocks = xfs_rtbitmap_blockcount(mp, rts->rextents); 106 rsumblocks = xfs_rtsummary_blockcount(mp, rts->rsumlevels, 107 rts->rbmblocks); 108 rts->rsumsize = XFS_FSB_TO_B(mp, rsumblocks); 109 } 110 return 0; 111 } 112 113 /* Helper functions to record suminfo words in an xfile. */ 114 115 static inline int 116 xfsum_load( 117 struct xfs_scrub *sc, 118 xfs_rtsumoff_t sumoff, 119 union xfs_suminfo_raw *rawinfo) 120 { 121 return xfile_obj_load(sc->xfile, rawinfo, 122 sizeof(union xfs_suminfo_raw), 123 sumoff << XFS_WORDLOG); 124 } 125 126 static inline int 127 xfsum_store( 128 struct xfs_scrub *sc, 129 xfs_rtsumoff_t sumoff, 130 const union xfs_suminfo_raw rawinfo) 131 { 132 return xfile_obj_store(sc->xfile, &rawinfo, 133 sizeof(union xfs_suminfo_raw), 134 sumoff << XFS_WORDLOG); 135 } 136 137 static inline int 138 xfsum_copyout( 139 struct xfs_scrub *sc, 140 xfs_rtsumoff_t sumoff, 141 union xfs_suminfo_raw *rawinfo, 142 unsigned int nr_words) 143 { 144 return xfile_obj_load(sc->xfile, rawinfo, nr_words << XFS_WORDLOG, 145 sumoff << XFS_WORDLOG); 146 } 147 148 static inline xfs_suminfo_t 149 xchk_rtsum_inc( 150 struct xfs_mount *mp, 151 union xfs_suminfo_raw *v) 152 { 153 v->old += 1; 154 return v->old; 155 } 156 157 /* Update the summary file to reflect the free extent that we've accumulated. */ 158 STATIC int 159 xchk_rtsum_record_free( 160 struct xfs_mount *mp, 161 struct xfs_trans *tp, 162 const struct xfs_rtalloc_rec *rec, 163 void *priv) 164 { 165 struct xfs_scrub *sc = priv; 166 xfs_fileoff_t rbmoff; 167 xfs_rtblock_t rtbno; 168 xfs_filblks_t rtlen; 169 xfs_rtsumoff_t offs; 170 unsigned int lenlog; 171 union xfs_suminfo_raw v; 172 xfs_suminfo_t value; 173 int error = 0; 174 175 if (xchk_should_terminate(sc, &error)) 176 return error; 177 178 /* Compute the relevant location in the rtsum file. */ 179 rbmoff = xfs_rtx_to_rbmblock(mp, rec->ar_startext); 180 lenlog = xfs_highbit64(rec->ar_extcount); 181 offs = xfs_rtsumoffs(mp, lenlog, rbmoff); 182 183 rtbno = xfs_rtx_to_rtb(mp, rec->ar_startext); 184 rtlen = xfs_rtx_to_rtb(mp, rec->ar_extcount); 185 186 if (!xfs_verify_rtbext(mp, rtbno, rtlen)) { 187 xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino); 188 return -EFSCORRUPTED; 189 } 190 191 /* Bump the summary count. */ 192 error = xfsum_load(sc, offs, &v); 193 if (error) 194 return error; 195 196 value = xchk_rtsum_inc(sc->mp, &v); 197 trace_xchk_rtsum_record_free(mp, rec->ar_startext, rec->ar_extcount, 198 lenlog, offs, value); 199 200 return xfsum_store(sc, offs, v); 201 } 202 203 /* Compute the realtime summary from the realtime bitmap. */ 204 STATIC int 205 xchk_rtsum_compute( 206 struct xfs_scrub *sc) 207 { 208 struct xfs_mount *mp = sc->mp; 209 unsigned long long rtbmp_blocks; 210 211 /* If the bitmap size doesn't match the computed size, bail. */ 212 rtbmp_blocks = xfs_rtbitmap_blockcount(mp, mp->m_sb.sb_rextents); 213 if (XFS_FSB_TO_B(mp, rtbmp_blocks) != mp->m_rbmip->i_disk_size) 214 return -EFSCORRUPTED; 215 216 return xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtsum_record_free, 217 sc); 218 } 219 220 /* Compare the rtsummary file against the one we computed. */ 221 STATIC int 222 xchk_rtsum_compare( 223 struct xfs_scrub *sc) 224 { 225 struct xfs_bmbt_irec map; 226 struct xfs_iext_cursor icur; 227 228 struct xfs_mount *mp = sc->mp; 229 struct xfs_inode *ip = sc->ip; 230 struct xchk_rtsummary *rts = sc->buf; 231 xfs_fileoff_t off = 0; 232 xfs_fileoff_t endoff; 233 xfs_rtsumoff_t sumoff = 0; 234 int error = 0; 235 236 rts->args.mp = sc->mp; 237 rts->args.tp = sc->tp; 238 239 /* Mappings may not cross or lie beyond EOF. */ 240 endoff = XFS_B_TO_FSB(mp, ip->i_disk_size); 241 if (xfs_iext_lookup_extent(ip, &ip->i_df, endoff, &icur, &map)) { 242 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, endoff); 243 return 0; 244 } 245 246 while (off < endoff) { 247 int nmap = 1; 248 249 if (xchk_should_terminate(sc, &error)) 250 return error; 251 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 252 return 0; 253 254 /* Make sure we have a written extent. */ 255 error = xfs_bmapi_read(ip, off, endoff - off, &map, &nmap, 256 XFS_DATA_FORK); 257 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error)) 258 return error; 259 260 if (nmap != 1 || !xfs_bmap_is_written_extent(&map)) { 261 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off); 262 return 0; 263 } 264 265 off += map.br_blockcount; 266 } 267 268 for (off = 0; off < endoff; off++) { 269 union xfs_suminfo_raw *ondisk_info; 270 271 /* Read a block's worth of ondisk rtsummary file. */ 272 error = xfs_rtsummary_read_buf(&rts->args, off); 273 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error)) 274 return error; 275 276 /* Read a block's worth of computed rtsummary file. */ 277 error = xfsum_copyout(sc, sumoff, rts->words, mp->m_blockwsize); 278 if (error) { 279 xfs_rtbuf_cache_relse(&rts->args); 280 return error; 281 } 282 283 ondisk_info = xfs_rsumblock_infoptr(&rts->args, 0); 284 if (memcmp(ondisk_info, rts->words, 285 mp->m_blockwsize << XFS_WORDLOG) != 0) { 286 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off); 287 xfs_rtbuf_cache_relse(&rts->args); 288 return error; 289 } 290 291 xfs_rtbuf_cache_relse(&rts->args); 292 sumoff += mp->m_blockwsize; 293 } 294 295 return 0; 296 } 297 298 /* Scrub the realtime summary. */ 299 int 300 xchk_rtsummary( 301 struct xfs_scrub *sc) 302 { 303 struct xfs_mount *mp = sc->mp; 304 struct xchk_rtsummary *rts = sc->buf; 305 int error = 0; 306 307 /* Is sb_rextents correct? */ 308 if (mp->m_sb.sb_rextents != rts->rextents) { 309 xchk_ino_set_corrupt(sc, mp->m_rbmip->i_ino); 310 goto out_rbm; 311 } 312 313 /* Is m_rsumlevels correct? */ 314 if (mp->m_rsumlevels != rts->rsumlevels) { 315 xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino); 316 goto out_rbm; 317 } 318 319 /* Is m_rsumsize correct? */ 320 if (mp->m_rsumsize != rts->rsumsize) { 321 xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino); 322 goto out_rbm; 323 } 324 325 /* The summary file length must be aligned to an fsblock. */ 326 if (mp->m_rsumip->i_disk_size & mp->m_blockmask) { 327 xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino); 328 goto out_rbm; 329 } 330 331 /* 332 * Is the summary file itself large enough to handle the rt volume? 333 * growfsrt expands the summary file before updating sb_rextents, so 334 * the file can be larger than rsumsize. 335 */ 336 if (mp->m_rsumip->i_disk_size < rts->rsumsize) { 337 xchk_ino_set_corrupt(sc, mp->m_rsumip->i_ino); 338 goto out_rbm; 339 } 340 341 /* Invoke the fork scrubber. */ 342 error = xchk_metadata_inode_forks(sc); 343 if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 344 goto out_rbm; 345 346 /* Construct the new summary file from the rtbitmap. */ 347 error = xchk_rtsum_compute(sc); 348 if (error == -EFSCORRUPTED) { 349 /* 350 * EFSCORRUPTED means the rtbitmap is corrupt, which is an xref 351 * error since we're checking the summary file. 352 */ 353 xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino); 354 error = 0; 355 goto out_rbm; 356 } 357 if (error) 358 goto out_rbm; 359 360 /* Does the computed summary file match the actual rtsummary file? */ 361 error = xchk_rtsum_compare(sc); 362 363 out_rbm: 364 /* Unlock the rtbitmap since we're done with it. */ 365 xfs_iunlock(mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP); 366 return error; 367 } 368