18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2018 Oracle.  All Rights Reserved.
48c2ecf20Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include "xfs.h"
78c2ecf20Sopenharmony_ci#include "xfs_fs.h"
88c2ecf20Sopenharmony_ci#include "xfs_shared.h"
98c2ecf20Sopenharmony_ci#include "xfs_format.h"
108c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h"
118c2ecf20Sopenharmony_ci#include "xfs_mount.h"
128c2ecf20Sopenharmony_ci#include "xfs_btree.h"
138c2ecf20Sopenharmony_ci#include "xfs_log_format.h"
148c2ecf20Sopenharmony_ci#include "xfs_trans.h"
158c2ecf20Sopenharmony_ci#include "xfs_sb.h"
168c2ecf20Sopenharmony_ci#include "xfs_inode.h"
178c2ecf20Sopenharmony_ci#include "xfs_alloc.h"
188c2ecf20Sopenharmony_ci#include "xfs_alloc_btree.h"
198c2ecf20Sopenharmony_ci#include "xfs_ialloc.h"
208c2ecf20Sopenharmony_ci#include "xfs_ialloc_btree.h"
218c2ecf20Sopenharmony_ci#include "xfs_rmap.h"
228c2ecf20Sopenharmony_ci#include "xfs_rmap_btree.h"
238c2ecf20Sopenharmony_ci#include "xfs_refcount_btree.h"
248c2ecf20Sopenharmony_ci#include "xfs_extent_busy.h"
258c2ecf20Sopenharmony_ci#include "xfs_ag_resv.h"
268c2ecf20Sopenharmony_ci#include "xfs_quota.h"
278c2ecf20Sopenharmony_ci#include "scrub/scrub.h"
288c2ecf20Sopenharmony_ci#include "scrub/common.h"
298c2ecf20Sopenharmony_ci#include "scrub/trace.h"
308c2ecf20Sopenharmony_ci#include "scrub/repair.h"
318c2ecf20Sopenharmony_ci#include "scrub/bitmap.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/*
348c2ecf20Sopenharmony_ci * Attempt to repair some metadata, if the metadata is corrupt and userspace
358c2ecf20Sopenharmony_ci * told us to fix it.  This function returns -EAGAIN to mean "re-run scrub",
368c2ecf20Sopenharmony_ci * and will set *fixed to true if it thinks it repaired anything.
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_ciint
398c2ecf20Sopenharmony_cixrep_attempt(
408c2ecf20Sopenharmony_ci	struct xfs_inode	*ip,
418c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	int			error = 0;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	trace_xrep_attempt(ip, sc->sm, error);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	xchk_ag_btcur_free(&sc->sa);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	/* Repair whatever's broken. */
508c2ecf20Sopenharmony_ci	ASSERT(sc->ops->repair);
518c2ecf20Sopenharmony_ci	error = sc->ops->repair(sc);
528c2ecf20Sopenharmony_ci	trace_xrep_done(ip, sc->sm, error);
538c2ecf20Sopenharmony_ci	switch (error) {
548c2ecf20Sopenharmony_ci	case 0:
558c2ecf20Sopenharmony_ci		/*
568c2ecf20Sopenharmony_ci		 * Repair succeeded.  Commit the fixes and perform a second
578c2ecf20Sopenharmony_ci		 * scrub so that we can tell userspace if we fixed the problem.
588c2ecf20Sopenharmony_ci		 */
598c2ecf20Sopenharmony_ci		sc->sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT;
608c2ecf20Sopenharmony_ci		sc->flags |= XREP_ALREADY_FIXED;
618c2ecf20Sopenharmony_ci		return -EAGAIN;
628c2ecf20Sopenharmony_ci	case -EDEADLOCK:
638c2ecf20Sopenharmony_ci	case -EAGAIN:
648c2ecf20Sopenharmony_ci		/* Tell the caller to try again having grabbed all the locks. */
658c2ecf20Sopenharmony_ci		if (!(sc->flags & XCHK_TRY_HARDER)) {
668c2ecf20Sopenharmony_ci			sc->flags |= XCHK_TRY_HARDER;
678c2ecf20Sopenharmony_ci			return -EAGAIN;
688c2ecf20Sopenharmony_ci		}
698c2ecf20Sopenharmony_ci		/*
708c2ecf20Sopenharmony_ci		 * We tried harder but still couldn't grab all the resources
718c2ecf20Sopenharmony_ci		 * we needed to fix it.  The corruption has not been fixed,
728c2ecf20Sopenharmony_ci		 * so report back to userspace.
738c2ecf20Sopenharmony_ci		 */
748c2ecf20Sopenharmony_ci		return -EFSCORRUPTED;
758c2ecf20Sopenharmony_ci	default:
768c2ecf20Sopenharmony_ci		return error;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/*
818c2ecf20Sopenharmony_ci * Complain about unfixable problems in the filesystem.  We don't log
828c2ecf20Sopenharmony_ci * corruptions when IFLAG_REPAIR wasn't set on the assumption that the driver
838c2ecf20Sopenharmony_ci * program is xfs_scrub, which will call back with IFLAG_REPAIR set if the
848c2ecf20Sopenharmony_ci * administrator isn't running xfs_scrub in no-repairs mode.
858c2ecf20Sopenharmony_ci *
868c2ecf20Sopenharmony_ci * Use this helper function because _ratelimited silently declares a static
878c2ecf20Sopenharmony_ci * structure to track rate limiting information.
888c2ecf20Sopenharmony_ci */
898c2ecf20Sopenharmony_civoid
908c2ecf20Sopenharmony_cixrep_failure(
918c2ecf20Sopenharmony_ci	struct xfs_mount	*mp)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	xfs_alert_ratelimited(mp,
948c2ecf20Sopenharmony_ci"Corruption not fixed during online repair.  Unmount and run xfs_repair.");
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/*
988c2ecf20Sopenharmony_ci * Repair probe -- userspace uses this to probe if we're willing to repair a
998c2ecf20Sopenharmony_ci * given mountpoint.
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_ciint
1028c2ecf20Sopenharmony_cixrep_probe(
1038c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	int			error = 0;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (xchk_should_terminate(sc, &error))
1088c2ecf20Sopenharmony_ci		return error;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/*
1148c2ecf20Sopenharmony_ci * Roll a transaction, keeping the AG headers locked and reinitializing
1158c2ecf20Sopenharmony_ci * the btree cursors.
1168c2ecf20Sopenharmony_ci */
1178c2ecf20Sopenharmony_ciint
1188c2ecf20Sopenharmony_cixrep_roll_ag_trans(
1198c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	int			error;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* Keep the AG header buffers locked so we can keep going. */
1248c2ecf20Sopenharmony_ci	if (sc->sa.agi_bp)
1258c2ecf20Sopenharmony_ci		xfs_trans_bhold(sc->tp, sc->sa.agi_bp);
1268c2ecf20Sopenharmony_ci	if (sc->sa.agf_bp)
1278c2ecf20Sopenharmony_ci		xfs_trans_bhold(sc->tp, sc->sa.agf_bp);
1288c2ecf20Sopenharmony_ci	if (sc->sa.agfl_bp)
1298c2ecf20Sopenharmony_ci		xfs_trans_bhold(sc->tp, sc->sa.agfl_bp);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/*
1328c2ecf20Sopenharmony_ci	 * Roll the transaction.  We still own the buffer and the buffer lock
1338c2ecf20Sopenharmony_ci	 * regardless of whether or not the roll succeeds.  If the roll fails,
1348c2ecf20Sopenharmony_ci	 * the buffers will be released during teardown on our way out of the
1358c2ecf20Sopenharmony_ci	 * kernel.  If it succeeds, we join them to the new transaction and
1368c2ecf20Sopenharmony_ci	 * move on.
1378c2ecf20Sopenharmony_ci	 */
1388c2ecf20Sopenharmony_ci	error = xfs_trans_roll(&sc->tp);
1398c2ecf20Sopenharmony_ci	if (error)
1408c2ecf20Sopenharmony_ci		return error;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/* Join AG headers to the new transaction. */
1438c2ecf20Sopenharmony_ci	if (sc->sa.agi_bp)
1448c2ecf20Sopenharmony_ci		xfs_trans_bjoin(sc->tp, sc->sa.agi_bp);
1458c2ecf20Sopenharmony_ci	if (sc->sa.agf_bp)
1468c2ecf20Sopenharmony_ci		xfs_trans_bjoin(sc->tp, sc->sa.agf_bp);
1478c2ecf20Sopenharmony_ci	if (sc->sa.agfl_bp)
1488c2ecf20Sopenharmony_ci		xfs_trans_bjoin(sc->tp, sc->sa.agfl_bp);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return 0;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/*
1548c2ecf20Sopenharmony_ci * Does the given AG have enough space to rebuild a btree?  Neither AG
1558c2ecf20Sopenharmony_ci * reservation can be critical, and we must have enough space (factoring
1568c2ecf20Sopenharmony_ci * in AG reservations) to construct a whole btree.
1578c2ecf20Sopenharmony_ci */
1588c2ecf20Sopenharmony_cibool
1598c2ecf20Sopenharmony_cixrep_ag_has_space(
1608c2ecf20Sopenharmony_ci	struct xfs_perag	*pag,
1618c2ecf20Sopenharmony_ci	xfs_extlen_t		nr_blocks,
1628c2ecf20Sopenharmony_ci	enum xfs_ag_resv_type	type)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	return  !xfs_ag_resv_critical(pag, XFS_AG_RESV_RMAPBT) &&
1658c2ecf20Sopenharmony_ci		!xfs_ag_resv_critical(pag, XFS_AG_RESV_METADATA) &&
1668c2ecf20Sopenharmony_ci		pag->pagf_freeblks > xfs_ag_resv_needed(pag, type) + nr_blocks;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci/*
1708c2ecf20Sopenharmony_ci * Figure out how many blocks to reserve for an AG repair.  We calculate the
1718c2ecf20Sopenharmony_ci * worst case estimate for the number of blocks we'd need to rebuild one of
1728c2ecf20Sopenharmony_ci * any type of per-AG btree.
1738c2ecf20Sopenharmony_ci */
1748c2ecf20Sopenharmony_cixfs_extlen_t
1758c2ecf20Sopenharmony_cixrep_calc_ag_resblks(
1768c2ecf20Sopenharmony_ci	struct xfs_scrub		*sc)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct xfs_mount		*mp = sc->mp;
1798c2ecf20Sopenharmony_ci	struct xfs_scrub_metadata	*sm = sc->sm;
1808c2ecf20Sopenharmony_ci	struct xfs_perag		*pag;
1818c2ecf20Sopenharmony_ci	struct xfs_buf			*bp;
1828c2ecf20Sopenharmony_ci	xfs_agino_t			icount = NULLAGINO;
1838c2ecf20Sopenharmony_ci	xfs_extlen_t			aglen = NULLAGBLOCK;
1848c2ecf20Sopenharmony_ci	xfs_extlen_t			usedlen;
1858c2ecf20Sopenharmony_ci	xfs_extlen_t			freelen;
1868c2ecf20Sopenharmony_ci	xfs_extlen_t			bnobt_sz;
1878c2ecf20Sopenharmony_ci	xfs_extlen_t			inobt_sz;
1888c2ecf20Sopenharmony_ci	xfs_extlen_t			rmapbt_sz;
1898c2ecf20Sopenharmony_ci	xfs_extlen_t			refcbt_sz;
1908c2ecf20Sopenharmony_ci	int				error;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (!(sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR))
1938c2ecf20Sopenharmony_ci		return 0;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	pag = xfs_perag_get(mp, sm->sm_agno);
1968c2ecf20Sopenharmony_ci	if (pag->pagi_init) {
1978c2ecf20Sopenharmony_ci		/* Use in-core icount if possible. */
1988c2ecf20Sopenharmony_ci		icount = pag->pagi_count;
1998c2ecf20Sopenharmony_ci	} else {
2008c2ecf20Sopenharmony_ci		/* Try to get the actual counters from disk. */
2018c2ecf20Sopenharmony_ci		error = xfs_ialloc_read_agi(mp, NULL, sm->sm_agno, &bp);
2028c2ecf20Sopenharmony_ci		if (!error) {
2038c2ecf20Sopenharmony_ci			icount = pag->pagi_count;
2048c2ecf20Sopenharmony_ci			xfs_buf_relse(bp);
2058c2ecf20Sopenharmony_ci		}
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* Now grab the block counters from the AGF. */
2098c2ecf20Sopenharmony_ci	error = xfs_alloc_read_agf(mp, NULL, sm->sm_agno, 0, &bp);
2108c2ecf20Sopenharmony_ci	if (!error) {
2118c2ecf20Sopenharmony_ci		struct xfs_agf	*agf = bp->b_addr;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		aglen = be32_to_cpu(agf->agf_length);
2148c2ecf20Sopenharmony_ci		freelen = be32_to_cpu(agf->agf_freeblks);
2158c2ecf20Sopenharmony_ci		usedlen = aglen - freelen;
2168c2ecf20Sopenharmony_ci		xfs_buf_relse(bp);
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci	xfs_perag_put(pag);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	/* If the icount is impossible, make some worst-case assumptions. */
2218c2ecf20Sopenharmony_ci	if (icount == NULLAGINO ||
2228c2ecf20Sopenharmony_ci	    !xfs_verify_agino(mp, sm->sm_agno, icount)) {
2238c2ecf20Sopenharmony_ci		xfs_agino_t	first, last;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		xfs_agino_range(mp, sm->sm_agno, &first, &last);
2268c2ecf20Sopenharmony_ci		icount = last - first + 1;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* If the block counts are impossible, make worst-case assumptions. */
2308c2ecf20Sopenharmony_ci	if (aglen == NULLAGBLOCK ||
2318c2ecf20Sopenharmony_ci	    aglen != xfs_ag_block_count(mp, sm->sm_agno) ||
2328c2ecf20Sopenharmony_ci	    freelen >= aglen) {
2338c2ecf20Sopenharmony_ci		aglen = xfs_ag_block_count(mp, sm->sm_agno);
2348c2ecf20Sopenharmony_ci		freelen = aglen;
2358c2ecf20Sopenharmony_ci		usedlen = aglen;
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	trace_xrep_calc_ag_resblks(mp, sm->sm_agno, icount, aglen,
2398c2ecf20Sopenharmony_ci			freelen, usedlen);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/*
2428c2ecf20Sopenharmony_ci	 * Figure out how many blocks we'd need worst case to rebuild
2438c2ecf20Sopenharmony_ci	 * each type of btree.  Note that we can only rebuild the
2448c2ecf20Sopenharmony_ci	 * bnobt/cntbt or inobt/finobt as pairs.
2458c2ecf20Sopenharmony_ci	 */
2468c2ecf20Sopenharmony_ci	bnobt_sz = 2 * xfs_allocbt_calc_size(mp, freelen);
2478c2ecf20Sopenharmony_ci	if (xfs_sb_version_hassparseinodes(&mp->m_sb))
2488c2ecf20Sopenharmony_ci		inobt_sz = xfs_iallocbt_calc_size(mp, icount /
2498c2ecf20Sopenharmony_ci				XFS_INODES_PER_HOLEMASK_BIT);
2508c2ecf20Sopenharmony_ci	else
2518c2ecf20Sopenharmony_ci		inobt_sz = xfs_iallocbt_calc_size(mp, icount /
2528c2ecf20Sopenharmony_ci				XFS_INODES_PER_CHUNK);
2538c2ecf20Sopenharmony_ci	if (xfs_sb_version_hasfinobt(&mp->m_sb))
2548c2ecf20Sopenharmony_ci		inobt_sz *= 2;
2558c2ecf20Sopenharmony_ci	if (xfs_sb_version_hasreflink(&mp->m_sb))
2568c2ecf20Sopenharmony_ci		refcbt_sz = xfs_refcountbt_calc_size(mp, usedlen);
2578c2ecf20Sopenharmony_ci	else
2588c2ecf20Sopenharmony_ci		refcbt_sz = 0;
2598c2ecf20Sopenharmony_ci	if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
2608c2ecf20Sopenharmony_ci		/*
2618c2ecf20Sopenharmony_ci		 * Guess how many blocks we need to rebuild the rmapbt.
2628c2ecf20Sopenharmony_ci		 * For non-reflink filesystems we can't have more records than
2638c2ecf20Sopenharmony_ci		 * used blocks.  However, with reflink it's possible to have
2648c2ecf20Sopenharmony_ci		 * more than one rmap record per AG block.  We don't know how
2658c2ecf20Sopenharmony_ci		 * many rmaps there could be in the AG, so we start off with
2668c2ecf20Sopenharmony_ci		 * what we hope is an generous over-estimation.
2678c2ecf20Sopenharmony_ci		 */
2688c2ecf20Sopenharmony_ci		if (xfs_sb_version_hasreflink(&mp->m_sb))
2698c2ecf20Sopenharmony_ci			rmapbt_sz = xfs_rmapbt_calc_size(mp,
2708c2ecf20Sopenharmony_ci					(unsigned long long)aglen * 2);
2718c2ecf20Sopenharmony_ci		else
2728c2ecf20Sopenharmony_ci			rmapbt_sz = xfs_rmapbt_calc_size(mp, usedlen);
2738c2ecf20Sopenharmony_ci	} else {
2748c2ecf20Sopenharmony_ci		rmapbt_sz = 0;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	trace_xrep_calc_ag_resblks_btsize(mp, sm->sm_agno, bnobt_sz,
2788c2ecf20Sopenharmony_ci			inobt_sz, rmapbt_sz, refcbt_sz);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return max(max(bnobt_sz, inobt_sz), max(rmapbt_sz, refcbt_sz));
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/* Allocate a block in an AG. */
2848c2ecf20Sopenharmony_ciint
2858c2ecf20Sopenharmony_cixrep_alloc_ag_block(
2868c2ecf20Sopenharmony_ci	struct xfs_scrub		*sc,
2878c2ecf20Sopenharmony_ci	const struct xfs_owner_info	*oinfo,
2888c2ecf20Sopenharmony_ci	xfs_fsblock_t			*fsbno,
2898c2ecf20Sopenharmony_ci	enum xfs_ag_resv_type		resv)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct xfs_alloc_arg		args = {0};
2928c2ecf20Sopenharmony_ci	xfs_agblock_t			bno;
2938c2ecf20Sopenharmony_ci	int				error;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	switch (resv) {
2968c2ecf20Sopenharmony_ci	case XFS_AG_RESV_AGFL:
2978c2ecf20Sopenharmony_ci	case XFS_AG_RESV_RMAPBT:
2988c2ecf20Sopenharmony_ci		error = xfs_alloc_get_freelist(sc->tp, sc->sa.agf_bp, &bno, 1);
2998c2ecf20Sopenharmony_ci		if (error)
3008c2ecf20Sopenharmony_ci			return error;
3018c2ecf20Sopenharmony_ci		if (bno == NULLAGBLOCK)
3028c2ecf20Sopenharmony_ci			return -ENOSPC;
3038c2ecf20Sopenharmony_ci		xfs_extent_busy_reuse(sc->mp, sc->sa.agno, bno,
3048c2ecf20Sopenharmony_ci				1, false);
3058c2ecf20Sopenharmony_ci		*fsbno = XFS_AGB_TO_FSB(sc->mp, sc->sa.agno, bno);
3068c2ecf20Sopenharmony_ci		if (resv == XFS_AG_RESV_RMAPBT)
3078c2ecf20Sopenharmony_ci			xfs_ag_resv_rmapbt_alloc(sc->mp, sc->sa.agno);
3088c2ecf20Sopenharmony_ci		return 0;
3098c2ecf20Sopenharmony_ci	default:
3108c2ecf20Sopenharmony_ci		break;
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	args.tp = sc->tp;
3148c2ecf20Sopenharmony_ci	args.mp = sc->mp;
3158c2ecf20Sopenharmony_ci	args.oinfo = *oinfo;
3168c2ecf20Sopenharmony_ci	args.fsbno = XFS_AGB_TO_FSB(args.mp, sc->sa.agno, 0);
3178c2ecf20Sopenharmony_ci	args.minlen = 1;
3188c2ecf20Sopenharmony_ci	args.maxlen = 1;
3198c2ecf20Sopenharmony_ci	args.prod = 1;
3208c2ecf20Sopenharmony_ci	args.type = XFS_ALLOCTYPE_THIS_AG;
3218c2ecf20Sopenharmony_ci	args.resv = resv;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	error = xfs_alloc_vextent(&args);
3248c2ecf20Sopenharmony_ci	if (error)
3258c2ecf20Sopenharmony_ci		return error;
3268c2ecf20Sopenharmony_ci	if (args.fsbno == NULLFSBLOCK)
3278c2ecf20Sopenharmony_ci		return -ENOSPC;
3288c2ecf20Sopenharmony_ci	ASSERT(args.len == 1);
3298c2ecf20Sopenharmony_ci	*fsbno = args.fsbno;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	return 0;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci/* Initialize a new AG btree root block with zero entries. */
3358c2ecf20Sopenharmony_ciint
3368c2ecf20Sopenharmony_cixrep_init_btblock(
3378c2ecf20Sopenharmony_ci	struct xfs_scrub		*sc,
3388c2ecf20Sopenharmony_ci	xfs_fsblock_t			fsb,
3398c2ecf20Sopenharmony_ci	struct xfs_buf			**bpp,
3408c2ecf20Sopenharmony_ci	xfs_btnum_t			btnum,
3418c2ecf20Sopenharmony_ci	const struct xfs_buf_ops	*ops)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	struct xfs_trans		*tp = sc->tp;
3448c2ecf20Sopenharmony_ci	struct xfs_mount		*mp = sc->mp;
3458c2ecf20Sopenharmony_ci	struct xfs_buf			*bp;
3468c2ecf20Sopenharmony_ci	int				error;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	trace_xrep_init_btblock(mp, XFS_FSB_TO_AGNO(mp, fsb),
3498c2ecf20Sopenharmony_ci			XFS_FSB_TO_AGBNO(mp, fsb), btnum);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	ASSERT(XFS_FSB_TO_AGNO(mp, fsb) == sc->sa.agno);
3528c2ecf20Sopenharmony_ci	error = xfs_trans_get_buf(tp, mp->m_ddev_targp,
3538c2ecf20Sopenharmony_ci			XFS_FSB_TO_DADDR(mp, fsb), XFS_FSB_TO_BB(mp, 1), 0,
3548c2ecf20Sopenharmony_ci			&bp);
3558c2ecf20Sopenharmony_ci	if (error)
3568c2ecf20Sopenharmony_ci		return error;
3578c2ecf20Sopenharmony_ci	xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
3588c2ecf20Sopenharmony_ci	xfs_btree_init_block(mp, bp, btnum, 0, 0, sc->sa.agno);
3598c2ecf20Sopenharmony_ci	xfs_trans_buf_set_type(tp, bp, XFS_BLFT_BTREE_BUF);
3608c2ecf20Sopenharmony_ci	xfs_trans_log_buf(tp, bp, 0, BBTOB(bp->b_length) - 1);
3618c2ecf20Sopenharmony_ci	bp->b_ops = ops;
3628c2ecf20Sopenharmony_ci	*bpp = bp;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	return 0;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci/*
3688c2ecf20Sopenharmony_ci * Reconstructing per-AG Btrees
3698c2ecf20Sopenharmony_ci *
3708c2ecf20Sopenharmony_ci * When a space btree is corrupt, we don't bother trying to fix it.  Instead,
3718c2ecf20Sopenharmony_ci * we scan secondary space metadata to derive the records that should be in
3728c2ecf20Sopenharmony_ci * the damaged btree, initialize a fresh btree root, and insert the records.
3738c2ecf20Sopenharmony_ci * Note that for rebuilding the rmapbt we scan all the primary data to
3748c2ecf20Sopenharmony_ci * generate the new records.
3758c2ecf20Sopenharmony_ci *
3768c2ecf20Sopenharmony_ci * However, that leaves the matter of removing all the metadata describing the
3778c2ecf20Sopenharmony_ci * old broken structure.  For primary metadata we use the rmap data to collect
3788c2ecf20Sopenharmony_ci * every extent with a matching rmap owner (bitmap); we then iterate all other
3798c2ecf20Sopenharmony_ci * metadata structures with the same rmap owner to collect the extents that
3808c2ecf20Sopenharmony_ci * cannot be removed (sublist).  We then subtract sublist from bitmap to
3818c2ecf20Sopenharmony_ci * derive the blocks that were used by the old btree.  These blocks can be
3828c2ecf20Sopenharmony_ci * reaped.
3838c2ecf20Sopenharmony_ci *
3848c2ecf20Sopenharmony_ci * For rmapbt reconstructions we must use different tactics for extent
3858c2ecf20Sopenharmony_ci * collection.  First we iterate all primary metadata (this excludes the old
3868c2ecf20Sopenharmony_ci * rmapbt, obviously) to generate new rmap records.  The gaps in the rmap
3878c2ecf20Sopenharmony_ci * records are collected as bitmap.  The bnobt records are collected as
3888c2ecf20Sopenharmony_ci * sublist.  As with the other btrees we subtract sublist from bitmap, and the
3898c2ecf20Sopenharmony_ci * result (since the rmapbt lives in the free space) are the blocks from the
3908c2ecf20Sopenharmony_ci * old rmapbt.
3918c2ecf20Sopenharmony_ci *
3928c2ecf20Sopenharmony_ci * Disposal of Blocks from Old per-AG Btrees
3938c2ecf20Sopenharmony_ci *
3948c2ecf20Sopenharmony_ci * Now that we've constructed a new btree to replace the damaged one, we want
3958c2ecf20Sopenharmony_ci * to dispose of the blocks that (we think) the old btree was using.
3968c2ecf20Sopenharmony_ci * Previously, we used the rmapbt to collect the extents (bitmap) with the
3978c2ecf20Sopenharmony_ci * rmap owner corresponding to the tree we rebuilt, collected extents for any
3988c2ecf20Sopenharmony_ci * blocks with the same rmap owner that are owned by another data structure
3998c2ecf20Sopenharmony_ci * (sublist), and subtracted sublist from bitmap.  In theory the extents
4008c2ecf20Sopenharmony_ci * remaining in bitmap are the old btree's blocks.
4018c2ecf20Sopenharmony_ci *
4028c2ecf20Sopenharmony_ci * Unfortunately, it's possible that the btree was crosslinked with other
4038c2ecf20Sopenharmony_ci * blocks on disk.  The rmap data can tell us if there are multiple owners, so
4048c2ecf20Sopenharmony_ci * if the rmapbt says there is an owner of this block other than @oinfo, then
4058c2ecf20Sopenharmony_ci * the block is crosslinked.  Remove the reverse mapping and continue.
4068c2ecf20Sopenharmony_ci *
4078c2ecf20Sopenharmony_ci * If there is one rmap record, we can free the block, which removes the
4088c2ecf20Sopenharmony_ci * reverse mapping but doesn't add the block to the free space.  Our repair
4098c2ecf20Sopenharmony_ci * strategy is to hope the other metadata objects crosslinked on this block
4108c2ecf20Sopenharmony_ci * will be rebuilt (atop different blocks), thereby removing all the cross
4118c2ecf20Sopenharmony_ci * links.
4128c2ecf20Sopenharmony_ci *
4138c2ecf20Sopenharmony_ci * If there are no rmap records at all, we also free the block.  If the btree
4148c2ecf20Sopenharmony_ci * being rebuilt lives in the free space (bnobt/cntbt/rmapbt) then there isn't
4158c2ecf20Sopenharmony_ci * supposed to be a rmap record and everything is ok.  For other btrees there
4168c2ecf20Sopenharmony_ci * had to have been an rmap entry for the block to have ended up on @bitmap,
4178c2ecf20Sopenharmony_ci * so if it's gone now there's something wrong and the fs will shut down.
4188c2ecf20Sopenharmony_ci *
4198c2ecf20Sopenharmony_ci * Note: If there are multiple rmap records with only the same rmap owner as
4208c2ecf20Sopenharmony_ci * the btree we're trying to rebuild and the block is indeed owned by another
4218c2ecf20Sopenharmony_ci * data structure with the same rmap owner, then the block will be in sublist
4228c2ecf20Sopenharmony_ci * and therefore doesn't need disposal.  If there are multiple rmap records
4238c2ecf20Sopenharmony_ci * with only the same rmap owner but the block is not owned by something with
4248c2ecf20Sopenharmony_ci * the same rmap owner, the block will be freed.
4258c2ecf20Sopenharmony_ci *
4268c2ecf20Sopenharmony_ci * The caller is responsible for locking the AG headers for the entire rebuild
4278c2ecf20Sopenharmony_ci * operation so that nothing else can sneak in and change the AG state while
4288c2ecf20Sopenharmony_ci * we're not looking.  We also assume that the caller already invalidated any
4298c2ecf20Sopenharmony_ci * buffers associated with @bitmap.
4308c2ecf20Sopenharmony_ci */
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci/*
4338c2ecf20Sopenharmony_ci * Invalidate buffers for per-AG btree blocks we're dumping.  This function
4348c2ecf20Sopenharmony_ci * is not intended for use with file data repairs; we have bunmapi for that.
4358c2ecf20Sopenharmony_ci */
4368c2ecf20Sopenharmony_ciint
4378c2ecf20Sopenharmony_cixrep_invalidate_blocks(
4388c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
4398c2ecf20Sopenharmony_ci	struct xbitmap		*bitmap)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	struct xbitmap_range	*bmr;
4428c2ecf20Sopenharmony_ci	struct xbitmap_range	*n;
4438c2ecf20Sopenharmony_ci	struct xfs_buf		*bp;
4448c2ecf20Sopenharmony_ci	xfs_fsblock_t		fsbno;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/*
4478c2ecf20Sopenharmony_ci	 * For each block in each extent, see if there's an incore buffer for
4488c2ecf20Sopenharmony_ci	 * exactly that block; if so, invalidate it.  The buffer cache only
4498c2ecf20Sopenharmony_ci	 * lets us look for one buffer at a time, so we have to look one block
4508c2ecf20Sopenharmony_ci	 * at a time.  Avoid invalidating AG headers and post-EOFS blocks
4518c2ecf20Sopenharmony_ci	 * because we never own those; and if we can't TRYLOCK the buffer we
4528c2ecf20Sopenharmony_ci	 * assume it's owned by someone else.
4538c2ecf20Sopenharmony_ci	 */
4548c2ecf20Sopenharmony_ci	for_each_xbitmap_block(fsbno, bmr, n, bitmap) {
4558c2ecf20Sopenharmony_ci		/* Skip AG headers and post-EOFS blocks */
4568c2ecf20Sopenharmony_ci		if (!xfs_verify_fsbno(sc->mp, fsbno))
4578c2ecf20Sopenharmony_ci			continue;
4588c2ecf20Sopenharmony_ci		bp = xfs_buf_incore(sc->mp->m_ddev_targp,
4598c2ecf20Sopenharmony_ci				XFS_FSB_TO_DADDR(sc->mp, fsbno),
4608c2ecf20Sopenharmony_ci				XFS_FSB_TO_BB(sc->mp, 1), XBF_TRYLOCK);
4618c2ecf20Sopenharmony_ci		if (bp) {
4628c2ecf20Sopenharmony_ci			xfs_trans_bjoin(sc->tp, bp);
4638c2ecf20Sopenharmony_ci			xfs_trans_binval(sc->tp, bp);
4648c2ecf20Sopenharmony_ci		}
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	return 0;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci/* Ensure the freelist is the correct size. */
4718c2ecf20Sopenharmony_ciint
4728c2ecf20Sopenharmony_cixrep_fix_freelist(
4738c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
4748c2ecf20Sopenharmony_ci	bool			can_shrink)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	struct xfs_alloc_arg	args = {0};
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	args.mp = sc->mp;
4798c2ecf20Sopenharmony_ci	args.tp = sc->tp;
4808c2ecf20Sopenharmony_ci	args.agno = sc->sa.agno;
4818c2ecf20Sopenharmony_ci	args.alignment = 1;
4828c2ecf20Sopenharmony_ci	args.pag = sc->sa.pag;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	return xfs_alloc_fix_freelist(&args,
4858c2ecf20Sopenharmony_ci			can_shrink ? 0 : XFS_ALLOC_FLAG_NOSHRINK);
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci/*
4898c2ecf20Sopenharmony_ci * Put a block back on the AGFL.
4908c2ecf20Sopenharmony_ci */
4918c2ecf20Sopenharmony_ciSTATIC int
4928c2ecf20Sopenharmony_cixrep_put_freelist(
4938c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
4948c2ecf20Sopenharmony_ci	xfs_agblock_t		agbno)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	int			error;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	/* Make sure there's space on the freelist. */
4998c2ecf20Sopenharmony_ci	error = xrep_fix_freelist(sc, true);
5008c2ecf20Sopenharmony_ci	if (error)
5018c2ecf20Sopenharmony_ci		return error;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	/*
5048c2ecf20Sopenharmony_ci	 * Since we're "freeing" a lost block onto the AGFL, we have to
5058c2ecf20Sopenharmony_ci	 * create an rmap for the block prior to merging it or else other
5068c2ecf20Sopenharmony_ci	 * parts will break.
5078c2ecf20Sopenharmony_ci	 */
5088c2ecf20Sopenharmony_ci	error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.agno, agbno, 1,
5098c2ecf20Sopenharmony_ci			&XFS_RMAP_OINFO_AG);
5108c2ecf20Sopenharmony_ci	if (error)
5118c2ecf20Sopenharmony_ci		return error;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	/* Put the block on the AGFL. */
5148c2ecf20Sopenharmony_ci	error = xfs_alloc_put_freelist(sc->tp, sc->sa.agf_bp, sc->sa.agfl_bp,
5158c2ecf20Sopenharmony_ci			agbno, 0);
5168c2ecf20Sopenharmony_ci	if (error)
5178c2ecf20Sopenharmony_ci		return error;
5188c2ecf20Sopenharmony_ci	xfs_extent_busy_insert(sc->tp, sc->sa.agno, agbno, 1,
5198c2ecf20Sopenharmony_ci			XFS_EXTENT_BUSY_SKIP_DISCARD);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	return 0;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci/* Dispose of a single block. */
5258c2ecf20Sopenharmony_ciSTATIC int
5268c2ecf20Sopenharmony_cixrep_reap_block(
5278c2ecf20Sopenharmony_ci	struct xfs_scrub		*sc,
5288c2ecf20Sopenharmony_ci	xfs_fsblock_t			fsbno,
5298c2ecf20Sopenharmony_ci	const struct xfs_owner_info	*oinfo,
5308c2ecf20Sopenharmony_ci	enum xfs_ag_resv_type		resv)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	struct xfs_btree_cur		*cur;
5338c2ecf20Sopenharmony_ci	struct xfs_buf			*agf_bp = NULL;
5348c2ecf20Sopenharmony_ci	xfs_agnumber_t			agno;
5358c2ecf20Sopenharmony_ci	xfs_agblock_t			agbno;
5368c2ecf20Sopenharmony_ci	bool				has_other_rmap;
5378c2ecf20Sopenharmony_ci	int				error;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	agno = XFS_FSB_TO_AGNO(sc->mp, fsbno);
5408c2ecf20Sopenharmony_ci	agbno = XFS_FSB_TO_AGBNO(sc->mp, fsbno);
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	/*
5438c2ecf20Sopenharmony_ci	 * If we are repairing per-inode metadata, we need to read in the AGF
5448c2ecf20Sopenharmony_ci	 * buffer.  Otherwise, we're repairing a per-AG structure, so reuse
5458c2ecf20Sopenharmony_ci	 * the AGF buffer that the setup functions already grabbed.
5468c2ecf20Sopenharmony_ci	 */
5478c2ecf20Sopenharmony_ci	if (sc->ip) {
5488c2ecf20Sopenharmony_ci		error = xfs_alloc_read_agf(sc->mp, sc->tp, agno, 0, &agf_bp);
5498c2ecf20Sopenharmony_ci		if (error)
5508c2ecf20Sopenharmony_ci			return error;
5518c2ecf20Sopenharmony_ci	} else {
5528c2ecf20Sopenharmony_ci		agf_bp = sc->sa.agf_bp;
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci	cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	/* Can we find any other rmappings? */
5578c2ecf20Sopenharmony_ci	error = xfs_rmap_has_other_keys(cur, agbno, 1, oinfo, &has_other_rmap);
5588c2ecf20Sopenharmony_ci	xfs_btree_del_cursor(cur, error);
5598c2ecf20Sopenharmony_ci	if (error)
5608c2ecf20Sopenharmony_ci		goto out_free;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	/*
5638c2ecf20Sopenharmony_ci	 * If there are other rmappings, this block is cross linked and must
5648c2ecf20Sopenharmony_ci	 * not be freed.  Remove the reverse mapping and move on.  Otherwise,
5658c2ecf20Sopenharmony_ci	 * we were the only owner of the block, so free the extent, which will
5668c2ecf20Sopenharmony_ci	 * also remove the rmap.
5678c2ecf20Sopenharmony_ci	 *
5688c2ecf20Sopenharmony_ci	 * XXX: XFS doesn't support detecting the case where a single block
5698c2ecf20Sopenharmony_ci	 * metadata structure is crosslinked with a multi-block structure
5708c2ecf20Sopenharmony_ci	 * because the buffer cache doesn't detect aliasing problems, so we
5718c2ecf20Sopenharmony_ci	 * can't fix 100% of crosslinking problems (yet).  The verifiers will
5728c2ecf20Sopenharmony_ci	 * blow on writeout, the filesystem will shut down, and the admin gets
5738c2ecf20Sopenharmony_ci	 * to run xfs_repair.
5748c2ecf20Sopenharmony_ci	 */
5758c2ecf20Sopenharmony_ci	if (has_other_rmap)
5768c2ecf20Sopenharmony_ci		error = xfs_rmap_free(sc->tp, agf_bp, agno, agbno, 1, oinfo);
5778c2ecf20Sopenharmony_ci	else if (resv == XFS_AG_RESV_AGFL)
5788c2ecf20Sopenharmony_ci		error = xrep_put_freelist(sc, agbno);
5798c2ecf20Sopenharmony_ci	else
5808c2ecf20Sopenharmony_ci		error = xfs_free_extent(sc->tp, fsbno, 1, oinfo, resv);
5818c2ecf20Sopenharmony_ci	if (agf_bp != sc->sa.agf_bp)
5828c2ecf20Sopenharmony_ci		xfs_trans_brelse(sc->tp, agf_bp);
5838c2ecf20Sopenharmony_ci	if (error)
5848c2ecf20Sopenharmony_ci		return error;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if (sc->ip)
5878c2ecf20Sopenharmony_ci		return xfs_trans_roll_inode(&sc->tp, sc->ip);
5888c2ecf20Sopenharmony_ci	return xrep_roll_ag_trans(sc);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ciout_free:
5918c2ecf20Sopenharmony_ci	if (agf_bp != sc->sa.agf_bp)
5928c2ecf20Sopenharmony_ci		xfs_trans_brelse(sc->tp, agf_bp);
5938c2ecf20Sopenharmony_ci	return error;
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci/* Dispose of every block of every extent in the bitmap. */
5978c2ecf20Sopenharmony_ciint
5988c2ecf20Sopenharmony_cixrep_reap_extents(
5998c2ecf20Sopenharmony_ci	struct xfs_scrub		*sc,
6008c2ecf20Sopenharmony_ci	struct xbitmap			*bitmap,
6018c2ecf20Sopenharmony_ci	const struct xfs_owner_info	*oinfo,
6028c2ecf20Sopenharmony_ci	enum xfs_ag_resv_type		type)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	struct xbitmap_range		*bmr;
6058c2ecf20Sopenharmony_ci	struct xbitmap_range		*n;
6068c2ecf20Sopenharmony_ci	xfs_fsblock_t			fsbno;
6078c2ecf20Sopenharmony_ci	int				error = 0;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	ASSERT(xfs_sb_version_hasrmapbt(&sc->mp->m_sb));
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	for_each_xbitmap_block(fsbno, bmr, n, bitmap) {
6128c2ecf20Sopenharmony_ci		ASSERT(sc->ip != NULL ||
6138c2ecf20Sopenharmony_ci		       XFS_FSB_TO_AGNO(sc->mp, fsbno) == sc->sa.agno);
6148c2ecf20Sopenharmony_ci		trace_xrep_dispose_btree_extent(sc->mp,
6158c2ecf20Sopenharmony_ci				XFS_FSB_TO_AGNO(sc->mp, fsbno),
6168c2ecf20Sopenharmony_ci				XFS_FSB_TO_AGBNO(sc->mp, fsbno), 1);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci		error = xrep_reap_block(sc, fsbno, oinfo, type);
6198c2ecf20Sopenharmony_ci		if (error)
6208c2ecf20Sopenharmony_ci			break;
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	return error;
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci/*
6278c2ecf20Sopenharmony_ci * Finding per-AG Btree Roots for AGF/AGI Reconstruction
6288c2ecf20Sopenharmony_ci *
6298c2ecf20Sopenharmony_ci * If the AGF or AGI become slightly corrupted, it may be necessary to rebuild
6308c2ecf20Sopenharmony_ci * the AG headers by using the rmap data to rummage through the AG looking for
6318c2ecf20Sopenharmony_ci * btree roots.  This is not guaranteed to work if the AG is heavily damaged
6328c2ecf20Sopenharmony_ci * or the rmap data are corrupt.
6338c2ecf20Sopenharmony_ci *
6348c2ecf20Sopenharmony_ci * Callers of xrep_find_ag_btree_roots must lock the AGF and AGFL
6358c2ecf20Sopenharmony_ci * buffers if the AGF is being rebuilt; or the AGF and AGI buffers if the
6368c2ecf20Sopenharmony_ci * AGI is being rebuilt.  It must maintain these locks until it's safe for
6378c2ecf20Sopenharmony_ci * other threads to change the btrees' shapes.  The caller provides
6388c2ecf20Sopenharmony_ci * information about the btrees to look for by passing in an array of
6398c2ecf20Sopenharmony_ci * xrep_find_ag_btree with the (rmap owner, buf_ops, magic) fields set.
6408c2ecf20Sopenharmony_ci * The (root, height) fields will be set on return if anything is found.  The
6418c2ecf20Sopenharmony_ci * last element of the array should have a NULL buf_ops to mark the end of the
6428c2ecf20Sopenharmony_ci * array.
6438c2ecf20Sopenharmony_ci *
6448c2ecf20Sopenharmony_ci * For every rmapbt record matching any of the rmap owners in btree_info,
6458c2ecf20Sopenharmony_ci * read each block referenced by the rmap record.  If the block is a btree
6468c2ecf20Sopenharmony_ci * block from this filesystem matching any of the magic numbers and has a
6478c2ecf20Sopenharmony_ci * level higher than what we've already seen, remember the block and the
6488c2ecf20Sopenharmony_ci * height of the tree required to have such a block.  When the call completes,
6498c2ecf20Sopenharmony_ci * we return the highest block we've found for each btree description; those
6508c2ecf20Sopenharmony_ci * should be the roots.
6518c2ecf20Sopenharmony_ci */
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistruct xrep_findroot {
6548c2ecf20Sopenharmony_ci	struct xfs_scrub		*sc;
6558c2ecf20Sopenharmony_ci	struct xfs_buf			*agfl_bp;
6568c2ecf20Sopenharmony_ci	struct xfs_agf			*agf;
6578c2ecf20Sopenharmony_ci	struct xrep_find_ag_btree	*btree_info;
6588c2ecf20Sopenharmony_ci};
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci/* See if our block is in the AGFL. */
6618c2ecf20Sopenharmony_ciSTATIC int
6628c2ecf20Sopenharmony_cixrep_findroot_agfl_walk(
6638c2ecf20Sopenharmony_ci	struct xfs_mount	*mp,
6648c2ecf20Sopenharmony_ci	xfs_agblock_t		bno,
6658c2ecf20Sopenharmony_ci	void			*priv)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	xfs_agblock_t		*agbno = priv;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	return (*agbno == bno) ? -ECANCELED : 0;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci/* Does this block match the btree information passed in? */
6738c2ecf20Sopenharmony_ciSTATIC int
6748c2ecf20Sopenharmony_cixrep_findroot_block(
6758c2ecf20Sopenharmony_ci	struct xrep_findroot		*ri,
6768c2ecf20Sopenharmony_ci	struct xrep_find_ag_btree	*fab,
6778c2ecf20Sopenharmony_ci	uint64_t			owner,
6788c2ecf20Sopenharmony_ci	xfs_agblock_t			agbno,
6798c2ecf20Sopenharmony_ci	bool				*done_with_block)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct xfs_mount		*mp = ri->sc->mp;
6828c2ecf20Sopenharmony_ci	struct xfs_buf			*bp;
6838c2ecf20Sopenharmony_ci	struct xfs_btree_block		*btblock;
6848c2ecf20Sopenharmony_ci	xfs_daddr_t			daddr;
6858c2ecf20Sopenharmony_ci	int				block_level;
6868c2ecf20Sopenharmony_ci	int				error = 0;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	daddr = XFS_AGB_TO_DADDR(mp, ri->sc->sa.agno, agbno);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	/*
6918c2ecf20Sopenharmony_ci	 * Blocks in the AGFL have stale contents that might just happen to
6928c2ecf20Sopenharmony_ci	 * have a matching magic and uuid.  We don't want to pull these blocks
6938c2ecf20Sopenharmony_ci	 * in as part of a tree root, so we have to filter out the AGFL stuff
6948c2ecf20Sopenharmony_ci	 * here.  If the AGFL looks insane we'll just refuse to repair.
6958c2ecf20Sopenharmony_ci	 */
6968c2ecf20Sopenharmony_ci	if (owner == XFS_RMAP_OWN_AG) {
6978c2ecf20Sopenharmony_ci		error = xfs_agfl_walk(mp, ri->agf, ri->agfl_bp,
6988c2ecf20Sopenharmony_ci				xrep_findroot_agfl_walk, &agbno);
6998c2ecf20Sopenharmony_ci		if (error == -ECANCELED)
7008c2ecf20Sopenharmony_ci			return 0;
7018c2ecf20Sopenharmony_ci		if (error)
7028c2ecf20Sopenharmony_ci			return error;
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	/*
7068c2ecf20Sopenharmony_ci	 * Read the buffer into memory so that we can see if it's a match for
7078c2ecf20Sopenharmony_ci	 * our btree type.  We have no clue if it is beforehand, and we want to
7088c2ecf20Sopenharmony_ci	 * avoid xfs_trans_read_buf's behavior of dumping the DONE state (which
7098c2ecf20Sopenharmony_ci	 * will cause needless disk reads in subsequent calls to this function)
7108c2ecf20Sopenharmony_ci	 * and logging metadata verifier failures.
7118c2ecf20Sopenharmony_ci	 *
7128c2ecf20Sopenharmony_ci	 * Therefore, pass in NULL buffer ops.  If the buffer was already in
7138c2ecf20Sopenharmony_ci	 * memory from some other caller it will already have b_ops assigned.
7148c2ecf20Sopenharmony_ci	 * If it was in memory from a previous unsuccessful findroot_block
7158c2ecf20Sopenharmony_ci	 * call, the buffer won't have b_ops but it should be clean and ready
7168c2ecf20Sopenharmony_ci	 * for us to try to verify if the read call succeeds.  The same applies
7178c2ecf20Sopenharmony_ci	 * if the buffer wasn't in memory at all.
7188c2ecf20Sopenharmony_ci	 *
7198c2ecf20Sopenharmony_ci	 * Note: If we never match a btree type with this buffer, it will be
7208c2ecf20Sopenharmony_ci	 * left in memory with NULL b_ops.  This shouldn't be a problem unless
7218c2ecf20Sopenharmony_ci	 * the buffer gets written.
7228c2ecf20Sopenharmony_ci	 */
7238c2ecf20Sopenharmony_ci	error = xfs_trans_read_buf(mp, ri->sc->tp, mp->m_ddev_targp, daddr,
7248c2ecf20Sopenharmony_ci			mp->m_bsize, 0, &bp, NULL);
7258c2ecf20Sopenharmony_ci	if (error)
7268c2ecf20Sopenharmony_ci		return error;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	/* Ensure the block magic matches the btree type we're looking for. */
7298c2ecf20Sopenharmony_ci	btblock = XFS_BUF_TO_BLOCK(bp);
7308c2ecf20Sopenharmony_ci	ASSERT(fab->buf_ops->magic[1] != 0);
7318c2ecf20Sopenharmony_ci	if (btblock->bb_magic != fab->buf_ops->magic[1])
7328c2ecf20Sopenharmony_ci		goto out;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	/*
7358c2ecf20Sopenharmony_ci	 * If the buffer already has ops applied and they're not the ones for
7368c2ecf20Sopenharmony_ci	 * this btree type, we know this block doesn't match the btree and we
7378c2ecf20Sopenharmony_ci	 * can bail out.
7388c2ecf20Sopenharmony_ci	 *
7398c2ecf20Sopenharmony_ci	 * If the buffer ops match ours, someone else has already validated
7408c2ecf20Sopenharmony_ci	 * the block for us, so we can move on to checking if this is a root
7418c2ecf20Sopenharmony_ci	 * block candidate.
7428c2ecf20Sopenharmony_ci	 *
7438c2ecf20Sopenharmony_ci	 * If the buffer does not have ops, nobody has successfully validated
7448c2ecf20Sopenharmony_ci	 * the contents and the buffer cannot be dirty.  If the magic, uuid,
7458c2ecf20Sopenharmony_ci	 * and structure match this btree type then we'll move on to checking
7468c2ecf20Sopenharmony_ci	 * if it's a root block candidate.  If there is no match, bail out.
7478c2ecf20Sopenharmony_ci	 */
7488c2ecf20Sopenharmony_ci	if (bp->b_ops) {
7498c2ecf20Sopenharmony_ci		if (bp->b_ops != fab->buf_ops)
7508c2ecf20Sopenharmony_ci			goto out;
7518c2ecf20Sopenharmony_ci	} else {
7528c2ecf20Sopenharmony_ci		ASSERT(!xfs_trans_buf_is_dirty(bp));
7538c2ecf20Sopenharmony_ci		if (!uuid_equal(&btblock->bb_u.s.bb_uuid,
7548c2ecf20Sopenharmony_ci				&mp->m_sb.sb_meta_uuid))
7558c2ecf20Sopenharmony_ci			goto out;
7568c2ecf20Sopenharmony_ci		/*
7578c2ecf20Sopenharmony_ci		 * Read verifiers can reference b_ops, so we set the pointer
7588c2ecf20Sopenharmony_ci		 * here.  If the verifier fails we'll reset the buffer state
7598c2ecf20Sopenharmony_ci		 * to what it was before we touched the buffer.
7608c2ecf20Sopenharmony_ci		 */
7618c2ecf20Sopenharmony_ci		bp->b_ops = fab->buf_ops;
7628c2ecf20Sopenharmony_ci		fab->buf_ops->verify_read(bp);
7638c2ecf20Sopenharmony_ci		if (bp->b_error) {
7648c2ecf20Sopenharmony_ci			bp->b_ops = NULL;
7658c2ecf20Sopenharmony_ci			bp->b_error = 0;
7668c2ecf20Sopenharmony_ci			goto out;
7678c2ecf20Sopenharmony_ci		}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci		/*
7708c2ecf20Sopenharmony_ci		 * Some read verifiers will (re)set b_ops, so we must be
7718c2ecf20Sopenharmony_ci		 * careful not to change b_ops after running the verifier.
7728c2ecf20Sopenharmony_ci		 */
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	/*
7768c2ecf20Sopenharmony_ci	 * This block passes the magic/uuid and verifier tests for this btree
7778c2ecf20Sopenharmony_ci	 * type.  We don't need the caller to try the other tree types.
7788c2ecf20Sopenharmony_ci	 */
7798c2ecf20Sopenharmony_ci	*done_with_block = true;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	/*
7828c2ecf20Sopenharmony_ci	 * Compare this btree block's level to the height of the current
7838c2ecf20Sopenharmony_ci	 * candidate root block.
7848c2ecf20Sopenharmony_ci	 *
7858c2ecf20Sopenharmony_ci	 * If the level matches the root we found previously, throw away both
7868c2ecf20Sopenharmony_ci	 * blocks because there can't be two candidate roots.
7878c2ecf20Sopenharmony_ci	 *
7888c2ecf20Sopenharmony_ci	 * If level is lower in the tree than the root we found previously,
7898c2ecf20Sopenharmony_ci	 * ignore this block.
7908c2ecf20Sopenharmony_ci	 */
7918c2ecf20Sopenharmony_ci	block_level = xfs_btree_get_level(btblock);
7928c2ecf20Sopenharmony_ci	if (block_level + 1 == fab->height) {
7938c2ecf20Sopenharmony_ci		fab->root = NULLAGBLOCK;
7948c2ecf20Sopenharmony_ci		goto out;
7958c2ecf20Sopenharmony_ci	} else if (block_level < fab->height) {
7968c2ecf20Sopenharmony_ci		goto out;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	/*
8008c2ecf20Sopenharmony_ci	 * This is the highest block in the tree that we've found so far.
8018c2ecf20Sopenharmony_ci	 * Update the btree height to reflect what we've learned from this
8028c2ecf20Sopenharmony_ci	 * block.
8038c2ecf20Sopenharmony_ci	 */
8048c2ecf20Sopenharmony_ci	fab->height = block_level + 1;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	/*
8078c2ecf20Sopenharmony_ci	 * If this block doesn't have sibling pointers, then it's the new root
8088c2ecf20Sopenharmony_ci	 * block candidate.  Otherwise, the root will be found farther up the
8098c2ecf20Sopenharmony_ci	 * tree.
8108c2ecf20Sopenharmony_ci	 */
8118c2ecf20Sopenharmony_ci	if (btblock->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) &&
8128c2ecf20Sopenharmony_ci	    btblock->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK))
8138c2ecf20Sopenharmony_ci		fab->root = agbno;
8148c2ecf20Sopenharmony_ci	else
8158c2ecf20Sopenharmony_ci		fab->root = NULLAGBLOCK;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	trace_xrep_findroot_block(mp, ri->sc->sa.agno, agbno,
8188c2ecf20Sopenharmony_ci			be32_to_cpu(btblock->bb_magic), fab->height - 1);
8198c2ecf20Sopenharmony_ciout:
8208c2ecf20Sopenharmony_ci	xfs_trans_brelse(ri->sc->tp, bp);
8218c2ecf20Sopenharmony_ci	return error;
8228c2ecf20Sopenharmony_ci}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci/*
8258c2ecf20Sopenharmony_ci * Do any of the blocks in this rmap record match one of the btrees we're
8268c2ecf20Sopenharmony_ci * looking for?
8278c2ecf20Sopenharmony_ci */
8288c2ecf20Sopenharmony_ciSTATIC int
8298c2ecf20Sopenharmony_cixrep_findroot_rmap(
8308c2ecf20Sopenharmony_ci	struct xfs_btree_cur		*cur,
8318c2ecf20Sopenharmony_ci	struct xfs_rmap_irec		*rec,
8328c2ecf20Sopenharmony_ci	void				*priv)
8338c2ecf20Sopenharmony_ci{
8348c2ecf20Sopenharmony_ci	struct xrep_findroot		*ri = priv;
8358c2ecf20Sopenharmony_ci	struct xrep_find_ag_btree	*fab;
8368c2ecf20Sopenharmony_ci	xfs_agblock_t			b;
8378c2ecf20Sopenharmony_ci	bool				done;
8388c2ecf20Sopenharmony_ci	int				error = 0;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	/* Ignore anything that isn't AG metadata. */
8418c2ecf20Sopenharmony_ci	if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner))
8428c2ecf20Sopenharmony_ci		return 0;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	/* Otherwise scan each block + btree type. */
8458c2ecf20Sopenharmony_ci	for (b = 0; b < rec->rm_blockcount; b++) {
8468c2ecf20Sopenharmony_ci		done = false;
8478c2ecf20Sopenharmony_ci		for (fab = ri->btree_info; fab->buf_ops; fab++) {
8488c2ecf20Sopenharmony_ci			if (rec->rm_owner != fab->rmap_owner)
8498c2ecf20Sopenharmony_ci				continue;
8508c2ecf20Sopenharmony_ci			error = xrep_findroot_block(ri, fab,
8518c2ecf20Sopenharmony_ci					rec->rm_owner, rec->rm_startblock + b,
8528c2ecf20Sopenharmony_ci					&done);
8538c2ecf20Sopenharmony_ci			if (error)
8548c2ecf20Sopenharmony_ci				return error;
8558c2ecf20Sopenharmony_ci			if (done)
8568c2ecf20Sopenharmony_ci				break;
8578c2ecf20Sopenharmony_ci		}
8588c2ecf20Sopenharmony_ci	}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	return 0;
8618c2ecf20Sopenharmony_ci}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci/* Find the roots of the per-AG btrees described in btree_info. */
8648c2ecf20Sopenharmony_ciint
8658c2ecf20Sopenharmony_cixrep_find_ag_btree_roots(
8668c2ecf20Sopenharmony_ci	struct xfs_scrub		*sc,
8678c2ecf20Sopenharmony_ci	struct xfs_buf			*agf_bp,
8688c2ecf20Sopenharmony_ci	struct xrep_find_ag_btree	*btree_info,
8698c2ecf20Sopenharmony_ci	struct xfs_buf			*agfl_bp)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	struct xfs_mount		*mp = sc->mp;
8728c2ecf20Sopenharmony_ci	struct xrep_findroot		ri;
8738c2ecf20Sopenharmony_ci	struct xrep_find_ag_btree	*fab;
8748c2ecf20Sopenharmony_ci	struct xfs_btree_cur		*cur;
8758c2ecf20Sopenharmony_ci	int				error;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	ASSERT(xfs_buf_islocked(agf_bp));
8788c2ecf20Sopenharmony_ci	ASSERT(agfl_bp == NULL || xfs_buf_islocked(agfl_bp));
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	ri.sc = sc;
8818c2ecf20Sopenharmony_ci	ri.btree_info = btree_info;
8828c2ecf20Sopenharmony_ci	ri.agf = agf_bp->b_addr;
8838c2ecf20Sopenharmony_ci	ri.agfl_bp = agfl_bp;
8848c2ecf20Sopenharmony_ci	for (fab = btree_info; fab->buf_ops; fab++) {
8858c2ecf20Sopenharmony_ci		ASSERT(agfl_bp || fab->rmap_owner != XFS_RMAP_OWN_AG);
8868c2ecf20Sopenharmony_ci		ASSERT(XFS_RMAP_NON_INODE_OWNER(fab->rmap_owner));
8878c2ecf20Sopenharmony_ci		fab->root = NULLAGBLOCK;
8888c2ecf20Sopenharmony_ci		fab->height = 0;
8898c2ecf20Sopenharmony_ci	}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
8928c2ecf20Sopenharmony_ci	error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri);
8938c2ecf20Sopenharmony_ci	xfs_btree_del_cursor(cur, error);
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	return error;
8968c2ecf20Sopenharmony_ci}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci/* Force a quotacheck the next time we mount. */
8998c2ecf20Sopenharmony_civoid
9008c2ecf20Sopenharmony_cixrep_force_quotacheck(
9018c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc,
9028c2ecf20Sopenharmony_ci	xfs_dqtype_t		type)
9038c2ecf20Sopenharmony_ci{
9048c2ecf20Sopenharmony_ci	uint			flag;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	flag = xfs_quota_chkd_flag(type);
9078c2ecf20Sopenharmony_ci	if (!(flag & sc->mp->m_qflags))
9088c2ecf20Sopenharmony_ci		return;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	sc->mp->m_qflags &= ~flag;
9118c2ecf20Sopenharmony_ci	spin_lock(&sc->mp->m_sb_lock);
9128c2ecf20Sopenharmony_ci	sc->mp->m_sb.sb_qflags &= ~flag;
9138c2ecf20Sopenharmony_ci	spin_unlock(&sc->mp->m_sb_lock);
9148c2ecf20Sopenharmony_ci	xfs_log_sb(sc->tp);
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci/*
9188c2ecf20Sopenharmony_ci * Attach dquots to this inode, or schedule quotacheck to fix them.
9198c2ecf20Sopenharmony_ci *
9208c2ecf20Sopenharmony_ci * This function ensures that the appropriate dquots are attached to an inode.
9218c2ecf20Sopenharmony_ci * We cannot allow the dquot code to allocate an on-disk dquot block here
9228c2ecf20Sopenharmony_ci * because we're already in transaction context with the inode locked.  The
9238c2ecf20Sopenharmony_ci * on-disk dquot should already exist anyway.  If the quota code signals
9248c2ecf20Sopenharmony_ci * corruption or missing quota information, schedule quotacheck, which will
9258c2ecf20Sopenharmony_ci * repair corruptions in the quota metadata.
9268c2ecf20Sopenharmony_ci */
9278c2ecf20Sopenharmony_ciint
9288c2ecf20Sopenharmony_cixrep_ino_dqattach(
9298c2ecf20Sopenharmony_ci	struct xfs_scrub	*sc)
9308c2ecf20Sopenharmony_ci{
9318c2ecf20Sopenharmony_ci	int			error;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	error = xfs_qm_dqattach_locked(sc->ip, false);
9348c2ecf20Sopenharmony_ci	switch (error) {
9358c2ecf20Sopenharmony_ci	case -EFSBADCRC:
9368c2ecf20Sopenharmony_ci	case -EFSCORRUPTED:
9378c2ecf20Sopenharmony_ci	case -ENOENT:
9388c2ecf20Sopenharmony_ci		xfs_err_ratelimited(sc->mp,
9398c2ecf20Sopenharmony_ci"inode %llu repair encountered quota error %d, quotacheck forced.",
9408c2ecf20Sopenharmony_ci				(unsigned long long)sc->ip->i_ino, error);
9418c2ecf20Sopenharmony_ci		if (XFS_IS_UQUOTA_ON(sc->mp) && !sc->ip->i_udquot)
9428c2ecf20Sopenharmony_ci			xrep_force_quotacheck(sc, XFS_DQTYPE_USER);
9438c2ecf20Sopenharmony_ci		if (XFS_IS_GQUOTA_ON(sc->mp) && !sc->ip->i_gdquot)
9448c2ecf20Sopenharmony_ci			xrep_force_quotacheck(sc, XFS_DQTYPE_GROUP);
9458c2ecf20Sopenharmony_ci		if (XFS_IS_PQUOTA_ON(sc->mp) && !sc->ip->i_pdquot)
9468c2ecf20Sopenharmony_ci			xrep_force_quotacheck(sc, XFS_DQTYPE_PROJ);
9478c2ecf20Sopenharmony_ci		/* fall through */
9488c2ecf20Sopenharmony_ci	case -ESRCH:
9498c2ecf20Sopenharmony_ci		error = 0;
9508c2ecf20Sopenharmony_ci		break;
9518c2ecf20Sopenharmony_ci	default:
9528c2ecf20Sopenharmony_ci		break;
9538c2ecf20Sopenharmony_ci	}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	return error;
9568c2ecf20Sopenharmony_ci}
957