995 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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_sb.h"14#include "xfs_alloc.h"15#include "xfs_ialloc.h"16#include "xfs_rmap.h"17#include "xfs_ag.h"18#include "xfs_inode.h"19#include "scrub/scrub.h"20#include "scrub/common.h"21 22int23xchk_setup_agheader(24 struct xfs_scrub *sc)25{26 if (xchk_need_intent_drain(sc))27 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);28 return xchk_setup_fs(sc);29}30 31/* Superblock */32 33/* Cross-reference with the other btrees. */34STATIC void35xchk_superblock_xref(36 struct xfs_scrub *sc,37 struct xfs_buf *bp)38{39 struct xfs_mount *mp = sc->mp;40 xfs_agnumber_t agno = sc->sm->sm_agno;41 xfs_agblock_t agbno;42 int error;43 44 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)45 return;46 47 agbno = XFS_SB_BLOCK(mp);48 49 error = xchk_ag_init_existing(sc, agno, &sc->sa);50 if (!xchk_xref_process_error(sc, agno, agbno, &error))51 return;52 53 xchk_xref_is_used_space(sc, agbno, 1);54 xchk_xref_is_not_inode_chunk(sc, agbno, 1);55 xchk_xref_is_only_owned_by(sc, agbno, 1, &XFS_RMAP_OINFO_FS);56 xchk_xref_is_not_shared(sc, agbno, 1);57 xchk_xref_is_not_cow_staging(sc, agbno, 1);58 59 /* scrub teardown will take care of sc->sa for us */60}61 62/*63 * Scrub the filesystem superblock.64 *65 * Note: We do /not/ attempt to check AG 0's superblock. Mount is66 * responsible for validating all the geometry information in sb 0, so67 * if the filesystem is capable of initiating online scrub, then clearly68 * sb 0 is ok and we can use its information to check everything else.69 */70int71xchk_superblock(72 struct xfs_scrub *sc)73{74 struct xfs_mount *mp = sc->mp;75 struct xfs_buf *bp;76 struct xfs_dsb *sb;77 struct xfs_perag *pag;78 xfs_agnumber_t agno;79 uint32_t v2_ok;80 __be32 features_mask;81 int error;82 __be16 vernum_mask;83 84 agno = sc->sm->sm_agno;85 if (agno == 0)86 return 0;87 88 /*89 * Grab an active reference to the perag structure. If we can't get90 * it, we're racing with something that's tearing down the AG, so91 * signal that the AG no longer exists.92 */93 pag = xfs_perag_get(mp, agno);94 if (!pag)95 return -ENOENT;96 97 error = xfs_sb_read_secondary(mp, sc->tp, agno, &bp);98 /*99 * The superblock verifier can return several different error codes100 * if it thinks the superblock doesn't look right. For a mount these101 * would all get bounced back to userspace, but if we're here then the102 * fs mounted successfully, which means that this secondary superblock103 * is simply incorrect. Treat all these codes the same way we treat104 * any corruption.105 */106 switch (error) {107 case -EINVAL: /* also -EWRONGFS */108 case -ENOSYS:109 case -EFBIG:110 error = -EFSCORRUPTED;111 fallthrough;112 default:113 break;114 }115 if (!xchk_process_error(sc, agno, XFS_SB_BLOCK(mp), &error))116 goto out_pag;117 118 sb = bp->b_addr;119 120 /*121 * Verify the geometries match. Fields that are permanently122 * set by mkfs are checked; fields that can be updated later123 * (and are not propagated to backup superblocks) are preen124 * checked.125 */126 if (sb->sb_blocksize != cpu_to_be32(mp->m_sb.sb_blocksize))127 xchk_block_set_corrupt(sc, bp);128 129 if (sb->sb_dblocks != cpu_to_be64(mp->m_sb.sb_dblocks))130 xchk_block_set_corrupt(sc, bp);131 132 if (sb->sb_rblocks != cpu_to_be64(mp->m_sb.sb_rblocks))133 xchk_block_set_corrupt(sc, bp);134 135 if (sb->sb_rextents != cpu_to_be64(mp->m_sb.sb_rextents))136 xchk_block_set_corrupt(sc, bp);137 138 if (!uuid_equal(&sb->sb_uuid, &mp->m_sb.sb_uuid))139 xchk_block_set_preen(sc, bp);140 141 if (sb->sb_logstart != cpu_to_be64(mp->m_sb.sb_logstart))142 xchk_block_set_corrupt(sc, bp);143 144 if (sb->sb_rootino != cpu_to_be64(mp->m_sb.sb_rootino))145 xchk_block_set_preen(sc, bp);146 147 if (sb->sb_rbmino != cpu_to_be64(mp->m_sb.sb_rbmino))148 xchk_block_set_preen(sc, bp);149 150 if (sb->sb_rsumino != cpu_to_be64(mp->m_sb.sb_rsumino))151 xchk_block_set_preen(sc, bp);152 153 if (sb->sb_rextsize != cpu_to_be32(mp->m_sb.sb_rextsize))154 xchk_block_set_corrupt(sc, bp);155 156 if (sb->sb_agblocks != cpu_to_be32(mp->m_sb.sb_agblocks))157 xchk_block_set_corrupt(sc, bp);158 159 if (sb->sb_agcount != cpu_to_be32(mp->m_sb.sb_agcount))160 xchk_block_set_corrupt(sc, bp);161 162 if (sb->sb_rbmblocks != cpu_to_be32(mp->m_sb.sb_rbmblocks))163 xchk_block_set_corrupt(sc, bp);164 165 if (sb->sb_logblocks != cpu_to_be32(mp->m_sb.sb_logblocks))166 xchk_block_set_corrupt(sc, bp);167 168 /* Check sb_versionnum bits that are set at mkfs time. */169 vernum_mask = cpu_to_be16(XFS_SB_VERSION_NUMBITS |170 XFS_SB_VERSION_ALIGNBIT |171 XFS_SB_VERSION_DALIGNBIT |172 XFS_SB_VERSION_SHAREDBIT |173 XFS_SB_VERSION_LOGV2BIT |174 XFS_SB_VERSION_SECTORBIT |175 XFS_SB_VERSION_EXTFLGBIT |176 XFS_SB_VERSION_DIRV2BIT);177 if ((sb->sb_versionnum & vernum_mask) !=178 (cpu_to_be16(mp->m_sb.sb_versionnum) & vernum_mask))179 xchk_block_set_corrupt(sc, bp);180 181 /* Check sb_versionnum bits that can be set after mkfs time. */182 vernum_mask = cpu_to_be16(XFS_SB_VERSION_ATTRBIT |183 XFS_SB_VERSION_NLINKBIT |184 XFS_SB_VERSION_QUOTABIT);185 if ((sb->sb_versionnum & vernum_mask) !=186 (cpu_to_be16(mp->m_sb.sb_versionnum) & vernum_mask))187 xchk_block_set_preen(sc, bp);188 189 if (sb->sb_sectsize != cpu_to_be16(mp->m_sb.sb_sectsize))190 xchk_block_set_corrupt(sc, bp);191 192 if (sb->sb_inodesize != cpu_to_be16(mp->m_sb.sb_inodesize))193 xchk_block_set_corrupt(sc, bp);194 195 if (sb->sb_inopblock != cpu_to_be16(mp->m_sb.sb_inopblock))196 xchk_block_set_corrupt(sc, bp);197 198 if (memcmp(sb->sb_fname, mp->m_sb.sb_fname, sizeof(sb->sb_fname)))199 xchk_block_set_preen(sc, bp);200 201 if (sb->sb_blocklog != mp->m_sb.sb_blocklog)202 xchk_block_set_corrupt(sc, bp);203 204 if (sb->sb_sectlog != mp->m_sb.sb_sectlog)205 xchk_block_set_corrupt(sc, bp);206 207 if (sb->sb_inodelog != mp->m_sb.sb_inodelog)208 xchk_block_set_corrupt(sc, bp);209 210 if (sb->sb_inopblog != mp->m_sb.sb_inopblog)211 xchk_block_set_corrupt(sc, bp);212 213 if (sb->sb_agblklog != mp->m_sb.sb_agblklog)214 xchk_block_set_corrupt(sc, bp);215 216 if (sb->sb_rextslog != mp->m_sb.sb_rextslog)217 xchk_block_set_corrupt(sc, bp);218 219 if (sb->sb_imax_pct != mp->m_sb.sb_imax_pct)220 xchk_block_set_preen(sc, bp);221 222 /*223 * Skip the summary counters since we track them in memory anyway.224 * sb_icount, sb_ifree, sb_fdblocks, sb_frexents225 */226 227 if (sb->sb_uquotino != cpu_to_be64(mp->m_sb.sb_uquotino))228 xchk_block_set_preen(sc, bp);229 230 if (sb->sb_gquotino != cpu_to_be64(mp->m_sb.sb_gquotino))231 xchk_block_set_preen(sc, bp);232 233 /*234 * Skip the quota flags since repair will force quotacheck.235 * sb_qflags236 */237 238 if (sb->sb_flags != mp->m_sb.sb_flags)239 xchk_block_set_corrupt(sc, bp);240 241 if (sb->sb_shared_vn != mp->m_sb.sb_shared_vn)242 xchk_block_set_corrupt(sc, bp);243 244 if (sb->sb_inoalignmt != cpu_to_be32(mp->m_sb.sb_inoalignmt))245 xchk_block_set_corrupt(sc, bp);246 247 if (sb->sb_unit != cpu_to_be32(mp->m_sb.sb_unit))248 xchk_block_set_preen(sc, bp);249 250 if (sb->sb_width != cpu_to_be32(mp->m_sb.sb_width))251 xchk_block_set_preen(sc, bp);252 253 if (sb->sb_dirblklog != mp->m_sb.sb_dirblklog)254 xchk_block_set_corrupt(sc, bp);255 256 if (sb->sb_logsectlog != mp->m_sb.sb_logsectlog)257 xchk_block_set_corrupt(sc, bp);258 259 if (sb->sb_logsectsize != cpu_to_be16(mp->m_sb.sb_logsectsize))260 xchk_block_set_corrupt(sc, bp);261 262 if (sb->sb_logsunit != cpu_to_be32(mp->m_sb.sb_logsunit))263 xchk_block_set_corrupt(sc, bp);264 265 /* Do we see any invalid bits in sb_features2? */266 if (!xfs_sb_version_hasmorebits(&mp->m_sb)) {267 if (sb->sb_features2 != 0)268 xchk_block_set_corrupt(sc, bp);269 } else {270 v2_ok = XFS_SB_VERSION2_OKBITS;271 if (xfs_sb_is_v5(&mp->m_sb))272 v2_ok |= XFS_SB_VERSION2_CRCBIT;273 274 if (!!(sb->sb_features2 & cpu_to_be32(~v2_ok)))275 xchk_block_set_corrupt(sc, bp);276 277 if (sb->sb_features2 != sb->sb_bad_features2)278 xchk_block_set_preen(sc, bp);279 }280 281 /* Check sb_features2 flags that are set at mkfs time. */282 features_mask = cpu_to_be32(XFS_SB_VERSION2_LAZYSBCOUNTBIT |283 XFS_SB_VERSION2_PROJID32BIT |284 XFS_SB_VERSION2_CRCBIT |285 XFS_SB_VERSION2_FTYPE);286 if ((sb->sb_features2 & features_mask) !=287 (cpu_to_be32(mp->m_sb.sb_features2) & features_mask))288 xchk_block_set_corrupt(sc, bp);289 290 /* Check sb_features2 flags that can be set after mkfs time. */291 features_mask = cpu_to_be32(XFS_SB_VERSION2_ATTR2BIT);292 if ((sb->sb_features2 & features_mask) !=293 (cpu_to_be32(mp->m_sb.sb_features2) & features_mask))294 xchk_block_set_preen(sc, bp);295 296 if (!xfs_has_crc(mp)) {297 /* all v5 fields must be zero */298 if (memchr_inv(&sb->sb_features_compat, 0,299 sizeof(struct xfs_dsb) -300 offsetof(struct xfs_dsb, sb_features_compat)))301 xchk_block_set_corrupt(sc, bp);302 } else {303 /* compat features must match */304 if (sb->sb_features_compat !=305 cpu_to_be32(mp->m_sb.sb_features_compat))306 xchk_block_set_corrupt(sc, bp);307 308 /* ro compat features must match */309 if (sb->sb_features_ro_compat !=310 cpu_to_be32(mp->m_sb.sb_features_ro_compat))311 xchk_block_set_corrupt(sc, bp);312 313 /*314 * NEEDSREPAIR is ignored on a secondary super, so we should315 * clear it when we find it, though it's not a corruption.316 */317 features_mask = cpu_to_be32(XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR);318 if ((cpu_to_be32(mp->m_sb.sb_features_incompat) ^319 sb->sb_features_incompat) & features_mask)320 xchk_block_set_preen(sc, bp);321 322 /* all other incompat features must match */323 if ((cpu_to_be32(mp->m_sb.sb_features_incompat) ^324 sb->sb_features_incompat) & ~features_mask)325 xchk_block_set_corrupt(sc, bp);326 327 /*328 * log incompat features protect newer log record types from329 * older log recovery code. Log recovery doesn't check the330 * secondary supers, so we can clear these if needed.331 */332 if (sb->sb_features_log_incompat)333 xchk_block_set_preen(sc, bp);334 335 /* Don't care about sb_crc */336 337 if (sb->sb_spino_align != cpu_to_be32(mp->m_sb.sb_spino_align))338 xchk_block_set_corrupt(sc, bp);339 340 if (sb->sb_pquotino != cpu_to_be64(mp->m_sb.sb_pquotino))341 xchk_block_set_preen(sc, bp);342 343 /* Don't care about sb_lsn */344 }345 346 if (xfs_has_metauuid(mp)) {347 /* The metadata UUID must be the same for all supers */348 if (!uuid_equal(&sb->sb_meta_uuid, &mp->m_sb.sb_meta_uuid))349 xchk_block_set_corrupt(sc, bp);350 }351 352 /* Everything else must be zero. */353 if (memchr_inv(sb + 1, 0,354 BBTOB(bp->b_length) - sizeof(struct xfs_dsb)))355 xchk_block_set_corrupt(sc, bp);356 357 xchk_superblock_xref(sc, bp);358out_pag:359 xfs_perag_put(pag);360 return error;361}362 363/* AGF */364 365/* Tally freespace record lengths. */366STATIC int367xchk_agf_record_bno_lengths(368 struct xfs_btree_cur *cur,369 const struct xfs_alloc_rec_incore *rec,370 void *priv)371{372 xfs_extlen_t *blocks = priv;373 374 (*blocks) += rec->ar_blockcount;375 return 0;376}377 378/* Check agf_freeblks */379static inline void380xchk_agf_xref_freeblks(381 struct xfs_scrub *sc)382{383 struct xfs_agf *agf = sc->sa.agf_bp->b_addr;384 xfs_extlen_t blocks = 0;385 int error;386 387 if (!sc->sa.bno_cur)388 return;389 390 error = xfs_alloc_query_all(sc->sa.bno_cur,391 xchk_agf_record_bno_lengths, &blocks);392 if (!xchk_should_check_xref(sc, &error, &sc->sa.bno_cur))393 return;394 if (blocks != be32_to_cpu(agf->agf_freeblks))395 xchk_block_xref_set_corrupt(sc, sc->sa.agf_bp);396}397 398/* Cross reference the AGF with the cntbt (freespace by length btree) */399static inline void400xchk_agf_xref_cntbt(401 struct xfs_scrub *sc)402{403 struct xfs_agf *agf = sc->sa.agf_bp->b_addr;404 xfs_agblock_t agbno;405 xfs_extlen_t blocks;406 int have;407 int error;408 409 if (!sc->sa.cnt_cur)410 return;411 412 /* Any freespace at all? */413 error = xfs_alloc_lookup_le(sc->sa.cnt_cur, 0, -1U, &have);414 if (!xchk_should_check_xref(sc, &error, &sc->sa.cnt_cur))415 return;416 if (!have) {417 if (agf->agf_freeblks != cpu_to_be32(0))418 xchk_block_xref_set_corrupt(sc, sc->sa.agf_bp);419 return;420 }421 422 /* Check agf_longest */423 error = xfs_alloc_get_rec(sc->sa.cnt_cur, &agbno, &blocks, &have);424 if (!xchk_should_check_xref(sc, &error, &sc->sa.cnt_cur))425 return;426 if (!have || blocks != be32_to_cpu(agf->agf_longest))427 xchk_block_xref_set_corrupt(sc, sc->sa.agf_bp);428}429 430/* Check the btree block counts in the AGF against the btrees. */431STATIC void432xchk_agf_xref_btreeblks(433 struct xfs_scrub *sc)434{435 struct xfs_agf *agf = sc->sa.agf_bp->b_addr;436 struct xfs_mount *mp = sc->mp;437 xfs_agblock_t blocks;438 xfs_agblock_t btreeblks;439 int error;440 441 /* agf_btreeblks didn't exist before lazysbcount */442 if (!xfs_has_lazysbcount(sc->mp))443 return;444 445 /* Check agf_rmap_blocks; set up for agf_btreeblks check */446 if (sc->sa.rmap_cur) {447 error = xfs_btree_count_blocks(sc->sa.rmap_cur, &blocks);448 if (!xchk_should_check_xref(sc, &error, &sc->sa.rmap_cur))449 return;450 btreeblks = blocks - 1;451 if (blocks != be32_to_cpu(agf->agf_rmap_blocks))452 xchk_block_xref_set_corrupt(sc, sc->sa.agf_bp);453 } else {454 btreeblks = 0;455 }456 457 /*458 * No rmap cursor; we can't xref if we have the rmapbt feature.459 * We also can't do it if we're missing the free space btree cursors.460 */461 if ((xfs_has_rmapbt(mp) && !sc->sa.rmap_cur) ||462 !sc->sa.bno_cur || !sc->sa.cnt_cur)463 return;464 465 /* Check agf_btreeblks */466 error = xfs_btree_count_blocks(sc->sa.bno_cur, &blocks);467 if (!xchk_should_check_xref(sc, &error, &sc->sa.bno_cur))468 return;469 btreeblks += blocks - 1;470 471 error = xfs_btree_count_blocks(sc->sa.cnt_cur, &blocks);472 if (!xchk_should_check_xref(sc, &error, &sc->sa.cnt_cur))473 return;474 btreeblks += blocks - 1;475 476 if (btreeblks != be32_to_cpu(agf->agf_btreeblks))477 xchk_block_xref_set_corrupt(sc, sc->sa.agf_bp);478}479 480/* Check agf_refcount_blocks against tree size */481static inline void482xchk_agf_xref_refcblks(483 struct xfs_scrub *sc)484{485 struct xfs_agf *agf = sc->sa.agf_bp->b_addr;486 xfs_agblock_t blocks;487 int error;488 489 if (!sc->sa.refc_cur)490 return;491 492 error = xfs_btree_count_blocks(sc->sa.refc_cur, &blocks);493 if (!xchk_should_check_xref(sc, &error, &sc->sa.refc_cur))494 return;495 if (blocks != be32_to_cpu(agf->agf_refcount_blocks))496 xchk_block_xref_set_corrupt(sc, sc->sa.agf_bp);497}498 499/* Cross-reference with the other btrees. */500STATIC void501xchk_agf_xref(502 struct xfs_scrub *sc)503{504 struct xfs_mount *mp = sc->mp;505 xfs_agblock_t agbno;506 507 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)508 return;509 510 agbno = XFS_AGF_BLOCK(mp);511 512 xchk_ag_btcur_init(sc, &sc->sa);513 514 xchk_xref_is_used_space(sc, agbno, 1);515 xchk_agf_xref_freeblks(sc);516 xchk_agf_xref_cntbt(sc);517 xchk_xref_is_not_inode_chunk(sc, agbno, 1);518 xchk_xref_is_only_owned_by(sc, agbno, 1, &XFS_RMAP_OINFO_FS);519 xchk_agf_xref_btreeblks(sc);520 xchk_xref_is_not_shared(sc, agbno, 1);521 xchk_xref_is_not_cow_staging(sc, agbno, 1);522 xchk_agf_xref_refcblks(sc);523 524 /* scrub teardown will take care of sc->sa for us */525}526 527/* Scrub the AGF. */528int529xchk_agf(530 struct xfs_scrub *sc)531{532 struct xfs_mount *mp = sc->mp;533 struct xfs_agf *agf;534 struct xfs_perag *pag;535 xfs_agnumber_t agno = sc->sm->sm_agno;536 xfs_agblock_t agbno;537 xfs_agblock_t eoag;538 xfs_agblock_t agfl_first;539 xfs_agblock_t agfl_last;540 xfs_agblock_t agfl_count;541 xfs_agblock_t fl_count;542 int level;543 int error = 0;544 545 error = xchk_ag_read_headers(sc, agno, &sc->sa);546 if (!xchk_process_error(sc, agno, XFS_AGF_BLOCK(sc->mp), &error))547 goto out;548 xchk_buffer_recheck(sc, sc->sa.agf_bp);549 550 agf = sc->sa.agf_bp->b_addr;551 pag = sc->sa.pag;552 553 /* Check the AG length */554 eoag = be32_to_cpu(agf->agf_length);555 if (eoag != pag->block_count)556 xchk_block_set_corrupt(sc, sc->sa.agf_bp);557 558 /* Check the AGF btree roots and levels */559 agbno = be32_to_cpu(agf->agf_bno_root);560 if (!xfs_verify_agbno(pag, agbno))561 xchk_block_set_corrupt(sc, sc->sa.agf_bp);562 563 agbno = be32_to_cpu(agf->agf_cnt_root);564 if (!xfs_verify_agbno(pag, agbno))565 xchk_block_set_corrupt(sc, sc->sa.agf_bp);566 567 level = be32_to_cpu(agf->agf_bno_level);568 if (level <= 0 || level > mp->m_alloc_maxlevels)569 xchk_block_set_corrupt(sc, sc->sa.agf_bp);570 571 level = be32_to_cpu(agf->agf_cnt_level);572 if (level <= 0 || level > mp->m_alloc_maxlevels)573 xchk_block_set_corrupt(sc, sc->sa.agf_bp);574 575 if (xfs_has_rmapbt(mp)) {576 agbno = be32_to_cpu(agf->agf_rmap_root);577 if (!xfs_verify_agbno(pag, agbno))578 xchk_block_set_corrupt(sc, sc->sa.agf_bp);579 580 level = be32_to_cpu(agf->agf_rmap_level);581 if (level <= 0 || level > mp->m_rmap_maxlevels)582 xchk_block_set_corrupt(sc, sc->sa.agf_bp);583 }584 585 if (xfs_has_reflink(mp)) {586 agbno = be32_to_cpu(agf->agf_refcount_root);587 if (!xfs_verify_agbno(pag, agbno))588 xchk_block_set_corrupt(sc, sc->sa.agf_bp);589 590 level = be32_to_cpu(agf->agf_refcount_level);591 if (level <= 0 || level > mp->m_refc_maxlevels)592 xchk_block_set_corrupt(sc, sc->sa.agf_bp);593 }594 595 /* Check the AGFL counters */596 agfl_first = be32_to_cpu(agf->agf_flfirst);597 agfl_last = be32_to_cpu(agf->agf_fllast);598 agfl_count = be32_to_cpu(agf->agf_flcount);599 if (agfl_last > agfl_first)600 fl_count = agfl_last - agfl_first + 1;601 else602 fl_count = xfs_agfl_size(mp) - agfl_first + agfl_last + 1;603 if (agfl_count != 0 && fl_count != agfl_count)604 xchk_block_set_corrupt(sc, sc->sa.agf_bp);605 606 /* Do the incore counters match? */607 if (pag->pagf_freeblks != be32_to_cpu(agf->agf_freeblks))608 xchk_block_set_corrupt(sc, sc->sa.agf_bp);609 if (pag->pagf_flcount != be32_to_cpu(agf->agf_flcount))610 xchk_block_set_corrupt(sc, sc->sa.agf_bp);611 if (xfs_has_lazysbcount(sc->mp) &&612 pag->pagf_btreeblks != be32_to_cpu(agf->agf_btreeblks))613 xchk_block_set_corrupt(sc, sc->sa.agf_bp);614 615 xchk_agf_xref(sc);616out:617 return error;618}619 620/* AGFL */621 622struct xchk_agfl_info {623 /* Number of AGFL entries that the AGF claims are in use. */624 unsigned int agflcount;625 626 /* Number of AGFL entries that we found. */627 unsigned int nr_entries;628 629 /* Buffer to hold AGFL entries for extent checking. */630 xfs_agblock_t *entries;631 632 struct xfs_buf *agfl_bp;633 struct xfs_scrub *sc;634};635 636/* Cross-reference with the other btrees. */637STATIC void638xchk_agfl_block_xref(639 struct xfs_scrub *sc,640 xfs_agblock_t agbno)641{642 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)643 return;644 645 xchk_xref_is_used_space(sc, agbno, 1);646 xchk_xref_is_not_inode_chunk(sc, agbno, 1);647 xchk_xref_is_only_owned_by(sc, agbno, 1, &XFS_RMAP_OINFO_AG);648 xchk_xref_is_not_shared(sc, agbno, 1);649 xchk_xref_is_not_cow_staging(sc, agbno, 1);650}651 652/* Scrub an AGFL block. */653STATIC int654xchk_agfl_block(655 struct xfs_mount *mp,656 xfs_agblock_t agbno,657 void *priv)658{659 struct xchk_agfl_info *sai = priv;660 struct xfs_scrub *sc = sai->sc;661 662 if (xfs_verify_agbno(sc->sa.pag, agbno) &&663 sai->nr_entries < sai->agflcount)664 sai->entries[sai->nr_entries++] = agbno;665 else666 xchk_block_set_corrupt(sc, sai->agfl_bp);667 668 xchk_agfl_block_xref(sc, agbno);669 670 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)671 return -ECANCELED;672 673 return 0;674}675 676static int677xchk_agblock_cmp(678 const void *pa,679 const void *pb)680{681 const xfs_agblock_t *a = pa;682 const xfs_agblock_t *b = pb;683 684 return (int)*a - (int)*b;685}686 687/* Cross-reference with the other btrees. */688STATIC void689xchk_agfl_xref(690 struct xfs_scrub *sc)691{692 struct xfs_mount *mp = sc->mp;693 xfs_agblock_t agbno;694 695 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)696 return;697 698 agbno = XFS_AGFL_BLOCK(mp);699 700 xchk_ag_btcur_init(sc, &sc->sa);701 702 xchk_xref_is_used_space(sc, agbno, 1);703 xchk_xref_is_not_inode_chunk(sc, agbno, 1);704 xchk_xref_is_only_owned_by(sc, agbno, 1, &XFS_RMAP_OINFO_FS);705 xchk_xref_is_not_shared(sc, agbno, 1);706 xchk_xref_is_not_cow_staging(sc, agbno, 1);707 708 /*709 * Scrub teardown will take care of sc->sa for us. Leave sc->sa710 * active so that the agfl block xref can use it too.711 */712}713 714/* Scrub the AGFL. */715int716xchk_agfl(717 struct xfs_scrub *sc)718{719 struct xchk_agfl_info sai = {720 .sc = sc,721 };722 struct xfs_agf *agf;723 xfs_agnumber_t agno = sc->sm->sm_agno;724 unsigned int i;725 int error;726 727 /* Lock the AGF and AGI so that nobody can touch this AG. */728 error = xchk_ag_read_headers(sc, agno, &sc->sa);729 if (!xchk_process_error(sc, agno, XFS_AGFL_BLOCK(sc->mp), &error))730 return error;731 if (!sc->sa.agf_bp)732 return -EFSCORRUPTED;733 734 /* Try to read the AGFL, and verify its structure if we get it. */735 error = xfs_alloc_read_agfl(sc->sa.pag, sc->tp, &sai.agfl_bp);736 if (!xchk_process_error(sc, agno, XFS_AGFL_BLOCK(sc->mp), &error))737 return error;738 xchk_buffer_recheck(sc, sai.agfl_bp);739 740 xchk_agfl_xref(sc);741 742 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)743 goto out;744 745 /* Allocate buffer to ensure uniqueness of AGFL entries. */746 agf = sc->sa.agf_bp->b_addr;747 sai.agflcount = be32_to_cpu(agf->agf_flcount);748 if (sai.agflcount > xfs_agfl_size(sc->mp)) {749 xchk_block_set_corrupt(sc, sc->sa.agf_bp);750 goto out;751 }752 sai.entries = kvcalloc(sai.agflcount, sizeof(xfs_agblock_t),753 XCHK_GFP_FLAGS);754 if (!sai.entries) {755 error = -ENOMEM;756 goto out;757 }758 759 /* Check the blocks in the AGFL. */760 error = xfs_agfl_walk(sc->mp, sc->sa.agf_bp->b_addr, sai.agfl_bp,761 xchk_agfl_block, &sai);762 if (error == -ECANCELED) {763 error = 0;764 goto out_free;765 }766 if (error)767 goto out_free;768 769 if (sai.agflcount != sai.nr_entries) {770 xchk_block_set_corrupt(sc, sc->sa.agf_bp);771 goto out_free;772 }773 774 /* Sort entries, check for duplicates. */775 sort(sai.entries, sai.nr_entries, sizeof(sai.entries[0]),776 xchk_agblock_cmp, NULL);777 for (i = 1; i < sai.nr_entries; i++) {778 if (sai.entries[i] == sai.entries[i - 1]) {779 xchk_block_set_corrupt(sc, sc->sa.agf_bp);780 break;781 }782 }783 784out_free:785 kvfree(sai.entries);786out:787 return error;788}789 790/* AGI */791 792/* Check agi_count/agi_freecount */793static inline void794xchk_agi_xref_icounts(795 struct xfs_scrub *sc)796{797 struct xfs_agi *agi = sc->sa.agi_bp->b_addr;798 xfs_agino_t icount;799 xfs_agino_t freecount;800 int error;801 802 if (!sc->sa.ino_cur)803 return;804 805 error = xfs_ialloc_count_inodes(sc->sa.ino_cur, &icount, &freecount);806 if (!xchk_should_check_xref(sc, &error, &sc->sa.ino_cur))807 return;808 if (be32_to_cpu(agi->agi_count) != icount ||809 be32_to_cpu(agi->agi_freecount) != freecount)810 xchk_block_xref_set_corrupt(sc, sc->sa.agi_bp);811}812 813/* Check agi_[fi]blocks against tree size */814static inline void815xchk_agi_xref_fiblocks(816 struct xfs_scrub *sc)817{818 struct xfs_agi *agi = sc->sa.agi_bp->b_addr;819 xfs_agblock_t blocks;820 int error = 0;821 822 if (!xfs_has_inobtcounts(sc->mp))823 return;824 825 if (sc->sa.ino_cur) {826 error = xfs_btree_count_blocks(sc->sa.ino_cur, &blocks);827 if (!xchk_should_check_xref(sc, &error, &sc->sa.ino_cur))828 return;829 if (blocks != be32_to_cpu(agi->agi_iblocks))830 xchk_block_xref_set_corrupt(sc, sc->sa.agi_bp);831 }832 833 if (sc->sa.fino_cur) {834 error = xfs_btree_count_blocks(sc->sa.fino_cur, &blocks);835 if (!xchk_should_check_xref(sc, &error, &sc->sa.fino_cur))836 return;837 if (blocks != be32_to_cpu(agi->agi_fblocks))838 xchk_block_xref_set_corrupt(sc, sc->sa.agi_bp);839 }840}841 842/* Cross-reference with the other btrees. */843STATIC void844xchk_agi_xref(845 struct xfs_scrub *sc)846{847 struct xfs_mount *mp = sc->mp;848 xfs_agblock_t agbno;849 850 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)851 return;852 853 agbno = XFS_AGI_BLOCK(mp);854 855 xchk_ag_btcur_init(sc, &sc->sa);856 857 xchk_xref_is_used_space(sc, agbno, 1);858 xchk_xref_is_not_inode_chunk(sc, agbno, 1);859 xchk_agi_xref_icounts(sc);860 xchk_xref_is_only_owned_by(sc, agbno, 1, &XFS_RMAP_OINFO_FS);861 xchk_xref_is_not_shared(sc, agbno, 1);862 xchk_xref_is_not_cow_staging(sc, agbno, 1);863 xchk_agi_xref_fiblocks(sc);864 865 /* scrub teardown will take care of sc->sa for us */866}867 868/*869 * Check the unlinked buckets for links to bad inodes. We hold the AGI, so870 * there cannot be any threads updating unlinked list pointers in this AG.871 */872STATIC void873xchk_iunlink(874 struct xfs_scrub *sc,875 struct xfs_agi *agi)876{877 unsigned int i;878 struct xfs_inode *ip;879 880 for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {881 xfs_agino_t agino = be32_to_cpu(agi->agi_unlinked[i]);882 883 while (agino != NULLAGINO) {884 if (agino % XFS_AGI_UNLINKED_BUCKETS != i) {885 xchk_block_set_corrupt(sc, sc->sa.agi_bp);886 return;887 }888 889 ip = xfs_iunlink_lookup(sc->sa.pag, agino);890 if (!ip) {891 xchk_block_set_corrupt(sc, sc->sa.agi_bp);892 return;893 }894 895 if (!xfs_inode_on_unlinked_list(ip)) {896 xchk_block_set_corrupt(sc, sc->sa.agi_bp);897 return;898 }899 900 agino = ip->i_next_unlinked;901 }902 }903}904 905/* Scrub the AGI. */906int907xchk_agi(908 struct xfs_scrub *sc)909{910 struct xfs_mount *mp = sc->mp;911 struct xfs_agi *agi;912 struct xfs_perag *pag;913 struct xfs_ino_geometry *igeo = M_IGEO(sc->mp);914 xfs_agnumber_t agno = sc->sm->sm_agno;915 xfs_agblock_t agbno;916 xfs_agblock_t eoag;917 xfs_agino_t agino;918 xfs_agino_t first_agino;919 xfs_agino_t last_agino;920 xfs_agino_t icount;921 int i;922 int level;923 int error = 0;924 925 error = xchk_ag_read_headers(sc, agno, &sc->sa);926 if (!xchk_process_error(sc, agno, XFS_AGI_BLOCK(sc->mp), &error))927 goto out;928 xchk_buffer_recheck(sc, sc->sa.agi_bp);929 930 agi = sc->sa.agi_bp->b_addr;931 pag = sc->sa.pag;932 933 /* Check the AG length */934 eoag = be32_to_cpu(agi->agi_length);935 if (eoag != pag->block_count)936 xchk_block_set_corrupt(sc, sc->sa.agi_bp);937 938 /* Check btree roots and levels */939 agbno = be32_to_cpu(agi->agi_root);940 if (!xfs_verify_agbno(pag, agbno))941 xchk_block_set_corrupt(sc, sc->sa.agi_bp);942 943 level = be32_to_cpu(agi->agi_level);944 if (level <= 0 || level > igeo->inobt_maxlevels)945 xchk_block_set_corrupt(sc, sc->sa.agi_bp);946 947 if (xfs_has_finobt(mp)) {948 agbno = be32_to_cpu(agi->agi_free_root);949 if (!xfs_verify_agbno(pag, agbno))950 xchk_block_set_corrupt(sc, sc->sa.agi_bp);951 952 level = be32_to_cpu(agi->agi_free_level);953 if (level <= 0 || level > igeo->inobt_maxlevels)954 xchk_block_set_corrupt(sc, sc->sa.agi_bp);955 }956 957 /* Check inode counters */958 xfs_agino_range(mp, agno, &first_agino, &last_agino);959 icount = be32_to_cpu(agi->agi_count);960 if (icount > last_agino - first_agino + 1 ||961 icount < be32_to_cpu(agi->agi_freecount))962 xchk_block_set_corrupt(sc, sc->sa.agi_bp);963 964 /* Check inode pointers */965 agino = be32_to_cpu(agi->agi_newino);966 if (!xfs_verify_agino_or_null(pag, agino))967 xchk_block_set_corrupt(sc, sc->sa.agi_bp);968 969 agino = be32_to_cpu(agi->agi_dirino);970 if (!xfs_verify_agino_or_null(pag, agino))971 xchk_block_set_corrupt(sc, sc->sa.agi_bp);972 973 /* Check unlinked inode buckets */974 for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {975 agino = be32_to_cpu(agi->agi_unlinked[i]);976 if (!xfs_verify_agino_or_null(pag, agino))977 xchk_block_set_corrupt(sc, sc->sa.agi_bp);978 }979 980 if (agi->agi_pad32 != cpu_to_be32(0))981 xchk_block_set_corrupt(sc, sc->sa.agi_bp);982 983 /* Do the incore counters match? */984 if (pag->pagi_count != be32_to_cpu(agi->agi_count))985 xchk_block_set_corrupt(sc, sc->sa.agi_bp);986 if (pag->pagi_freecount != be32_to_cpu(agi->agi_freecount))987 xchk_block_set_corrupt(sc, sc->sa.agi_bp);988 989 xchk_iunlink(sc, agi);990 991 xchk_agi_xref(sc);992out:993 return error;994}995