brintos

brintos / linux-shallow public Read only

0
0
Text · 25.9 KiB · f8e5b67 Raw
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