162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 462306a36Sopenharmony_ci * Author: Darrick J. Wong <djwong@kernel.org> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "xfs.h" 762306a36Sopenharmony_ci#include "xfs_fs.h" 862306a36Sopenharmony_ci#include "xfs_shared.h" 962306a36Sopenharmony_ci#include "xfs_format.h" 1062306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1162306a36Sopenharmony_ci#include "xfs_mount.h" 1262306a36Sopenharmony_ci#include "xfs_btree.h" 1362306a36Sopenharmony_ci#include "xfs_log_format.h" 1462306a36Sopenharmony_ci#include "xfs_trans.h" 1562306a36Sopenharmony_ci#include "xfs_sb.h" 1662306a36Sopenharmony_ci#include "xfs_inode.h" 1762306a36Sopenharmony_ci#include "xfs_alloc.h" 1862306a36Sopenharmony_ci#include "xfs_alloc_btree.h" 1962306a36Sopenharmony_ci#include "xfs_ialloc.h" 2062306a36Sopenharmony_ci#include "xfs_ialloc_btree.h" 2162306a36Sopenharmony_ci#include "xfs_rmap.h" 2262306a36Sopenharmony_ci#include "xfs_rmap_btree.h" 2362306a36Sopenharmony_ci#include "xfs_refcount_btree.h" 2462306a36Sopenharmony_ci#include "xfs_extent_busy.h" 2562306a36Sopenharmony_ci#include "xfs_ag.h" 2662306a36Sopenharmony_ci#include "xfs_ag_resv.h" 2762306a36Sopenharmony_ci#include "xfs_quota.h" 2862306a36Sopenharmony_ci#include "xfs_qm.h" 2962306a36Sopenharmony_ci#include "xfs_defer.h" 3062306a36Sopenharmony_ci#include "scrub/scrub.h" 3162306a36Sopenharmony_ci#include "scrub/common.h" 3262306a36Sopenharmony_ci#include "scrub/trace.h" 3362306a36Sopenharmony_ci#include "scrub/repair.h" 3462306a36Sopenharmony_ci#include "scrub/bitmap.h" 3562306a36Sopenharmony_ci#include "scrub/stats.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * Attempt to repair some metadata, if the metadata is corrupt and userspace 3962306a36Sopenharmony_ci * told us to fix it. This function returns -EAGAIN to mean "re-run scrub", 4062306a36Sopenharmony_ci * and will set *fixed to true if it thinks it repaired anything. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ciint 4362306a36Sopenharmony_cixrep_attempt( 4462306a36Sopenharmony_ci struct xfs_scrub *sc, 4562306a36Sopenharmony_ci struct xchk_stats_run *run) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci u64 repair_start; 4862306a36Sopenharmony_ci int error = 0; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci trace_xrep_attempt(XFS_I(file_inode(sc->file)), sc->sm, error); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci xchk_ag_btcur_free(&sc->sa); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* Repair whatever's broken. */ 5562306a36Sopenharmony_ci ASSERT(sc->ops->repair); 5662306a36Sopenharmony_ci run->repair_attempted = true; 5762306a36Sopenharmony_ci repair_start = xchk_stats_now(); 5862306a36Sopenharmony_ci error = sc->ops->repair(sc); 5962306a36Sopenharmony_ci trace_xrep_done(XFS_I(file_inode(sc->file)), sc->sm, error); 6062306a36Sopenharmony_ci run->repair_ns += xchk_stats_elapsed_ns(repair_start); 6162306a36Sopenharmony_ci switch (error) { 6262306a36Sopenharmony_ci case 0: 6362306a36Sopenharmony_ci /* 6462306a36Sopenharmony_ci * Repair succeeded. Commit the fixes and perform a second 6562306a36Sopenharmony_ci * scrub so that we can tell userspace if we fixed the problem. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci sc->sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT; 6862306a36Sopenharmony_ci sc->flags |= XREP_ALREADY_FIXED; 6962306a36Sopenharmony_ci run->repair_succeeded = true; 7062306a36Sopenharmony_ci return -EAGAIN; 7162306a36Sopenharmony_ci case -ECHRNG: 7262306a36Sopenharmony_ci sc->flags |= XCHK_NEED_DRAIN; 7362306a36Sopenharmony_ci run->retries++; 7462306a36Sopenharmony_ci return -EAGAIN; 7562306a36Sopenharmony_ci case -EDEADLOCK: 7662306a36Sopenharmony_ci /* Tell the caller to try again having grabbed all the locks. */ 7762306a36Sopenharmony_ci if (!(sc->flags & XCHK_TRY_HARDER)) { 7862306a36Sopenharmony_ci sc->flags |= XCHK_TRY_HARDER; 7962306a36Sopenharmony_ci run->retries++; 8062306a36Sopenharmony_ci return -EAGAIN; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci /* 8362306a36Sopenharmony_ci * We tried harder but still couldn't grab all the resources 8462306a36Sopenharmony_ci * we needed to fix it. The corruption has not been fixed, 8562306a36Sopenharmony_ci * so exit to userspace with the scan's output flags unchanged. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci default: 8962306a36Sopenharmony_ci /* 9062306a36Sopenharmony_ci * EAGAIN tells the caller to re-scrub, so we cannot return 9162306a36Sopenharmony_ci * that here. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ci ASSERT(error != -EAGAIN); 9462306a36Sopenharmony_ci return error; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* 9962306a36Sopenharmony_ci * Complain about unfixable problems in the filesystem. We don't log 10062306a36Sopenharmony_ci * corruptions when IFLAG_REPAIR wasn't set on the assumption that the driver 10162306a36Sopenharmony_ci * program is xfs_scrub, which will call back with IFLAG_REPAIR set if the 10262306a36Sopenharmony_ci * administrator isn't running xfs_scrub in no-repairs mode. 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * Use this helper function because _ratelimited silently declares a static 10562306a36Sopenharmony_ci * structure to track rate limiting information. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_civoid 10862306a36Sopenharmony_cixrep_failure( 10962306a36Sopenharmony_ci struct xfs_mount *mp) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci xfs_alert_ratelimited(mp, 11262306a36Sopenharmony_ci"Corruption not fixed during online repair. Unmount and run xfs_repair."); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* 11662306a36Sopenharmony_ci * Repair probe -- userspace uses this to probe if we're willing to repair a 11762306a36Sopenharmony_ci * given mountpoint. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ciint 12062306a36Sopenharmony_cixrep_probe( 12162306a36Sopenharmony_ci struct xfs_scrub *sc) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci int error = 0; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (xchk_should_terminate(sc, &error)) 12662306a36Sopenharmony_ci return error; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return 0; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* 13262306a36Sopenharmony_ci * Roll a transaction, keeping the AG headers locked and reinitializing 13362306a36Sopenharmony_ci * the btree cursors. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ciint 13662306a36Sopenharmony_cixrep_roll_ag_trans( 13762306a36Sopenharmony_ci struct xfs_scrub *sc) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci int error; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * Keep the AG header buffers locked while we roll the transaction. 14362306a36Sopenharmony_ci * Ensure that both AG buffers are dirty and held when we roll the 14462306a36Sopenharmony_ci * transaction so that they move forward in the log without losing the 14562306a36Sopenharmony_ci * bli (and hence the bli type) when the transaction commits. 14662306a36Sopenharmony_ci * 14762306a36Sopenharmony_ci * Normal code would never hold clean buffers across a roll, but repair 14862306a36Sopenharmony_ci * needs both buffers to maintain a total lock on the AG. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci if (sc->sa.agi_bp) { 15162306a36Sopenharmony_ci xfs_ialloc_log_agi(sc->tp, sc->sa.agi_bp, XFS_AGI_MAGICNUM); 15262306a36Sopenharmony_ci xfs_trans_bhold(sc->tp, sc->sa.agi_bp); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (sc->sa.agf_bp) { 15662306a36Sopenharmony_ci xfs_alloc_log_agf(sc->tp, sc->sa.agf_bp, XFS_AGF_MAGICNUM); 15762306a36Sopenharmony_ci xfs_trans_bhold(sc->tp, sc->sa.agf_bp); 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* 16162306a36Sopenharmony_ci * Roll the transaction. We still hold the AG header buffers locked 16262306a36Sopenharmony_ci * regardless of whether or not that succeeds. On failure, the buffers 16362306a36Sopenharmony_ci * will be released during teardown on our way out of the kernel. If 16462306a36Sopenharmony_ci * successful, join the buffers to the new transaction and move on. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci error = xfs_trans_roll(&sc->tp); 16762306a36Sopenharmony_ci if (error) 16862306a36Sopenharmony_ci return error; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Join the AG headers to the new transaction. */ 17162306a36Sopenharmony_ci if (sc->sa.agi_bp) 17262306a36Sopenharmony_ci xfs_trans_bjoin(sc->tp, sc->sa.agi_bp); 17362306a36Sopenharmony_ci if (sc->sa.agf_bp) 17462306a36Sopenharmony_ci xfs_trans_bjoin(sc->tp, sc->sa.agf_bp); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci return 0; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* Finish all deferred work attached to the repair transaction. */ 18062306a36Sopenharmony_ciint 18162306a36Sopenharmony_cixrep_defer_finish( 18262306a36Sopenharmony_ci struct xfs_scrub *sc) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci int error; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* 18762306a36Sopenharmony_ci * Keep the AG header buffers locked while we complete deferred work 18862306a36Sopenharmony_ci * items. Ensure that both AG buffers are dirty and held when we roll 18962306a36Sopenharmony_ci * the transaction so that they move forward in the log without losing 19062306a36Sopenharmony_ci * the bli (and hence the bli type) when the transaction commits. 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * Normal code would never hold clean buffers across a roll, but repair 19362306a36Sopenharmony_ci * needs both buffers to maintain a total lock on the AG. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ci if (sc->sa.agi_bp) { 19662306a36Sopenharmony_ci xfs_ialloc_log_agi(sc->tp, sc->sa.agi_bp, XFS_AGI_MAGICNUM); 19762306a36Sopenharmony_ci xfs_trans_bhold(sc->tp, sc->sa.agi_bp); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (sc->sa.agf_bp) { 20162306a36Sopenharmony_ci xfs_alloc_log_agf(sc->tp, sc->sa.agf_bp, XFS_AGF_MAGICNUM); 20262306a36Sopenharmony_ci xfs_trans_bhold(sc->tp, sc->sa.agf_bp); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* 20662306a36Sopenharmony_ci * Finish all deferred work items. We still hold the AG header buffers 20762306a36Sopenharmony_ci * locked regardless of whether or not that succeeds. On failure, the 20862306a36Sopenharmony_ci * buffers will be released during teardown on our way out of the 20962306a36Sopenharmony_ci * kernel. If successful, join the buffers to the new transaction 21062306a36Sopenharmony_ci * and move on. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci error = xfs_defer_finish(&sc->tp); 21362306a36Sopenharmony_ci if (error) 21462306a36Sopenharmony_ci return error; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* 21762306a36Sopenharmony_ci * Release the hold that we set above because defer_finish won't do 21862306a36Sopenharmony_ci * that for us. The defer roll code redirties held buffers after each 21962306a36Sopenharmony_ci * roll, so the AG header buffers should be ready for logging. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci if (sc->sa.agi_bp) 22262306a36Sopenharmony_ci xfs_trans_bhold_release(sc->tp, sc->sa.agi_bp); 22362306a36Sopenharmony_ci if (sc->sa.agf_bp) 22462306a36Sopenharmony_ci xfs_trans_bhold_release(sc->tp, sc->sa.agf_bp); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return 0; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* 23062306a36Sopenharmony_ci * Does the given AG have enough space to rebuild a btree? Neither AG 23162306a36Sopenharmony_ci * reservation can be critical, and we must have enough space (factoring 23262306a36Sopenharmony_ci * in AG reservations) to construct a whole btree. 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_cibool 23562306a36Sopenharmony_cixrep_ag_has_space( 23662306a36Sopenharmony_ci struct xfs_perag *pag, 23762306a36Sopenharmony_ci xfs_extlen_t nr_blocks, 23862306a36Sopenharmony_ci enum xfs_ag_resv_type type) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci return !xfs_ag_resv_critical(pag, XFS_AG_RESV_RMAPBT) && 24162306a36Sopenharmony_ci !xfs_ag_resv_critical(pag, XFS_AG_RESV_METADATA) && 24262306a36Sopenharmony_ci pag->pagf_freeblks > xfs_ag_resv_needed(pag, type) + nr_blocks; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/* 24662306a36Sopenharmony_ci * Figure out how many blocks to reserve for an AG repair. We calculate the 24762306a36Sopenharmony_ci * worst case estimate for the number of blocks we'd need to rebuild one of 24862306a36Sopenharmony_ci * any type of per-AG btree. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_cixfs_extlen_t 25162306a36Sopenharmony_cixrep_calc_ag_resblks( 25262306a36Sopenharmony_ci struct xfs_scrub *sc) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct xfs_mount *mp = sc->mp; 25562306a36Sopenharmony_ci struct xfs_scrub_metadata *sm = sc->sm; 25662306a36Sopenharmony_ci struct xfs_perag *pag; 25762306a36Sopenharmony_ci struct xfs_buf *bp; 25862306a36Sopenharmony_ci xfs_agino_t icount = NULLAGINO; 25962306a36Sopenharmony_ci xfs_extlen_t aglen = NULLAGBLOCK; 26062306a36Sopenharmony_ci xfs_extlen_t usedlen; 26162306a36Sopenharmony_ci xfs_extlen_t freelen; 26262306a36Sopenharmony_ci xfs_extlen_t bnobt_sz; 26362306a36Sopenharmony_ci xfs_extlen_t inobt_sz; 26462306a36Sopenharmony_ci xfs_extlen_t rmapbt_sz; 26562306a36Sopenharmony_ci xfs_extlen_t refcbt_sz; 26662306a36Sopenharmony_ci int error; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!(sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)) 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci pag = xfs_perag_get(mp, sm->sm_agno); 27262306a36Sopenharmony_ci if (xfs_perag_initialised_agi(pag)) { 27362306a36Sopenharmony_ci /* Use in-core icount if possible. */ 27462306a36Sopenharmony_ci icount = pag->pagi_count; 27562306a36Sopenharmony_ci } else { 27662306a36Sopenharmony_ci /* Try to get the actual counters from disk. */ 27762306a36Sopenharmony_ci error = xfs_ialloc_read_agi(pag, NULL, &bp); 27862306a36Sopenharmony_ci if (!error) { 27962306a36Sopenharmony_ci icount = pag->pagi_count; 28062306a36Sopenharmony_ci xfs_buf_relse(bp); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Now grab the block counters from the AGF. */ 28562306a36Sopenharmony_ci error = xfs_alloc_read_agf(pag, NULL, 0, &bp); 28662306a36Sopenharmony_ci if (error) { 28762306a36Sopenharmony_ci aglen = pag->block_count; 28862306a36Sopenharmony_ci freelen = aglen; 28962306a36Sopenharmony_ci usedlen = aglen; 29062306a36Sopenharmony_ci } else { 29162306a36Sopenharmony_ci struct xfs_agf *agf = bp->b_addr; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci aglen = be32_to_cpu(agf->agf_length); 29462306a36Sopenharmony_ci freelen = be32_to_cpu(agf->agf_freeblks); 29562306a36Sopenharmony_ci usedlen = aglen - freelen; 29662306a36Sopenharmony_ci xfs_buf_relse(bp); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* If the icount is impossible, make some worst-case assumptions. */ 30062306a36Sopenharmony_ci if (icount == NULLAGINO || 30162306a36Sopenharmony_ci !xfs_verify_agino(pag, icount)) { 30262306a36Sopenharmony_ci icount = pag->agino_max - pag->agino_min + 1; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* If the block counts are impossible, make worst-case assumptions. */ 30662306a36Sopenharmony_ci if (aglen == NULLAGBLOCK || 30762306a36Sopenharmony_ci aglen != pag->block_count || 30862306a36Sopenharmony_ci freelen >= aglen) { 30962306a36Sopenharmony_ci aglen = pag->block_count; 31062306a36Sopenharmony_ci freelen = aglen; 31162306a36Sopenharmony_ci usedlen = aglen; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci xfs_perag_put(pag); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci trace_xrep_calc_ag_resblks(mp, sm->sm_agno, icount, aglen, 31662306a36Sopenharmony_ci freelen, usedlen); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* 31962306a36Sopenharmony_ci * Figure out how many blocks we'd need worst case to rebuild 32062306a36Sopenharmony_ci * each type of btree. Note that we can only rebuild the 32162306a36Sopenharmony_ci * bnobt/cntbt or inobt/finobt as pairs. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci bnobt_sz = 2 * xfs_allocbt_calc_size(mp, freelen); 32462306a36Sopenharmony_ci if (xfs_has_sparseinodes(mp)) 32562306a36Sopenharmony_ci inobt_sz = xfs_iallocbt_calc_size(mp, icount / 32662306a36Sopenharmony_ci XFS_INODES_PER_HOLEMASK_BIT); 32762306a36Sopenharmony_ci else 32862306a36Sopenharmony_ci inobt_sz = xfs_iallocbt_calc_size(mp, icount / 32962306a36Sopenharmony_ci XFS_INODES_PER_CHUNK); 33062306a36Sopenharmony_ci if (xfs_has_finobt(mp)) 33162306a36Sopenharmony_ci inobt_sz *= 2; 33262306a36Sopenharmony_ci if (xfs_has_reflink(mp)) 33362306a36Sopenharmony_ci refcbt_sz = xfs_refcountbt_calc_size(mp, usedlen); 33462306a36Sopenharmony_ci else 33562306a36Sopenharmony_ci refcbt_sz = 0; 33662306a36Sopenharmony_ci if (xfs_has_rmapbt(mp)) { 33762306a36Sopenharmony_ci /* 33862306a36Sopenharmony_ci * Guess how many blocks we need to rebuild the rmapbt. 33962306a36Sopenharmony_ci * For non-reflink filesystems we can't have more records than 34062306a36Sopenharmony_ci * used blocks. However, with reflink it's possible to have 34162306a36Sopenharmony_ci * more than one rmap record per AG block. We don't know how 34262306a36Sopenharmony_ci * many rmaps there could be in the AG, so we start off with 34362306a36Sopenharmony_ci * what we hope is an generous over-estimation. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci if (xfs_has_reflink(mp)) 34662306a36Sopenharmony_ci rmapbt_sz = xfs_rmapbt_calc_size(mp, 34762306a36Sopenharmony_ci (unsigned long long)aglen * 2); 34862306a36Sopenharmony_ci else 34962306a36Sopenharmony_ci rmapbt_sz = xfs_rmapbt_calc_size(mp, usedlen); 35062306a36Sopenharmony_ci } else { 35162306a36Sopenharmony_ci rmapbt_sz = 0; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci trace_xrep_calc_ag_resblks_btsize(mp, sm->sm_agno, bnobt_sz, 35562306a36Sopenharmony_ci inobt_sz, rmapbt_sz, refcbt_sz); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci return max(max(bnobt_sz, inobt_sz), max(rmapbt_sz, refcbt_sz)); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/* 36162306a36Sopenharmony_ci * Reconstructing per-AG Btrees 36262306a36Sopenharmony_ci * 36362306a36Sopenharmony_ci * When a space btree is corrupt, we don't bother trying to fix it. Instead, 36462306a36Sopenharmony_ci * we scan secondary space metadata to derive the records that should be in 36562306a36Sopenharmony_ci * the damaged btree, initialize a fresh btree root, and insert the records. 36662306a36Sopenharmony_ci * Note that for rebuilding the rmapbt we scan all the primary data to 36762306a36Sopenharmony_ci * generate the new records. 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * However, that leaves the matter of removing all the metadata describing the 37062306a36Sopenharmony_ci * old broken structure. For primary metadata we use the rmap data to collect 37162306a36Sopenharmony_ci * every extent with a matching rmap owner (bitmap); we then iterate all other 37262306a36Sopenharmony_ci * metadata structures with the same rmap owner to collect the extents that 37362306a36Sopenharmony_ci * cannot be removed (sublist). We then subtract sublist from bitmap to 37462306a36Sopenharmony_ci * derive the blocks that were used by the old btree. These blocks can be 37562306a36Sopenharmony_ci * reaped. 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * For rmapbt reconstructions we must use different tactics for extent 37862306a36Sopenharmony_ci * collection. First we iterate all primary metadata (this excludes the old 37962306a36Sopenharmony_ci * rmapbt, obviously) to generate new rmap records. The gaps in the rmap 38062306a36Sopenharmony_ci * records are collected as bitmap. The bnobt records are collected as 38162306a36Sopenharmony_ci * sublist. As with the other btrees we subtract sublist from bitmap, and the 38262306a36Sopenharmony_ci * result (since the rmapbt lives in the free space) are the blocks from the 38362306a36Sopenharmony_ci * old rmapbt. 38462306a36Sopenharmony_ci */ 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci/* Ensure the freelist is the correct size. */ 38762306a36Sopenharmony_ciint 38862306a36Sopenharmony_cixrep_fix_freelist( 38962306a36Sopenharmony_ci struct xfs_scrub *sc, 39062306a36Sopenharmony_ci bool can_shrink) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct xfs_alloc_arg args = {0}; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci args.mp = sc->mp; 39562306a36Sopenharmony_ci args.tp = sc->tp; 39662306a36Sopenharmony_ci args.agno = sc->sa.pag->pag_agno; 39762306a36Sopenharmony_ci args.alignment = 1; 39862306a36Sopenharmony_ci args.pag = sc->sa.pag; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return xfs_alloc_fix_freelist(&args, 40162306a36Sopenharmony_ci can_shrink ? 0 : XFS_ALLOC_FLAG_NOSHRINK); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci/* 40562306a36Sopenharmony_ci * Finding per-AG Btree Roots for AGF/AGI Reconstruction 40662306a36Sopenharmony_ci * 40762306a36Sopenharmony_ci * If the AGF or AGI become slightly corrupted, it may be necessary to rebuild 40862306a36Sopenharmony_ci * the AG headers by using the rmap data to rummage through the AG looking for 40962306a36Sopenharmony_ci * btree roots. This is not guaranteed to work if the AG is heavily damaged 41062306a36Sopenharmony_ci * or the rmap data are corrupt. 41162306a36Sopenharmony_ci * 41262306a36Sopenharmony_ci * Callers of xrep_find_ag_btree_roots must lock the AGF and AGFL 41362306a36Sopenharmony_ci * buffers if the AGF is being rebuilt; or the AGF and AGI buffers if the 41462306a36Sopenharmony_ci * AGI is being rebuilt. It must maintain these locks until it's safe for 41562306a36Sopenharmony_ci * other threads to change the btrees' shapes. The caller provides 41662306a36Sopenharmony_ci * information about the btrees to look for by passing in an array of 41762306a36Sopenharmony_ci * xrep_find_ag_btree with the (rmap owner, buf_ops, magic) fields set. 41862306a36Sopenharmony_ci * The (root, height) fields will be set on return if anything is found. The 41962306a36Sopenharmony_ci * last element of the array should have a NULL buf_ops to mark the end of the 42062306a36Sopenharmony_ci * array. 42162306a36Sopenharmony_ci * 42262306a36Sopenharmony_ci * For every rmapbt record matching any of the rmap owners in btree_info, 42362306a36Sopenharmony_ci * read each block referenced by the rmap record. If the block is a btree 42462306a36Sopenharmony_ci * block from this filesystem matching any of the magic numbers and has a 42562306a36Sopenharmony_ci * level higher than what we've already seen, remember the block and the 42662306a36Sopenharmony_ci * height of the tree required to have such a block. When the call completes, 42762306a36Sopenharmony_ci * we return the highest block we've found for each btree description; those 42862306a36Sopenharmony_ci * should be the roots. 42962306a36Sopenharmony_ci */ 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistruct xrep_findroot { 43262306a36Sopenharmony_ci struct xfs_scrub *sc; 43362306a36Sopenharmony_ci struct xfs_buf *agfl_bp; 43462306a36Sopenharmony_ci struct xfs_agf *agf; 43562306a36Sopenharmony_ci struct xrep_find_ag_btree *btree_info; 43662306a36Sopenharmony_ci}; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci/* See if our block is in the AGFL. */ 43962306a36Sopenharmony_ciSTATIC int 44062306a36Sopenharmony_cixrep_findroot_agfl_walk( 44162306a36Sopenharmony_ci struct xfs_mount *mp, 44262306a36Sopenharmony_ci xfs_agblock_t bno, 44362306a36Sopenharmony_ci void *priv) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci xfs_agblock_t *agbno = priv; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci return (*agbno == bno) ? -ECANCELED : 0; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci/* Does this block match the btree information passed in? */ 45162306a36Sopenharmony_ciSTATIC int 45262306a36Sopenharmony_cixrep_findroot_block( 45362306a36Sopenharmony_ci struct xrep_findroot *ri, 45462306a36Sopenharmony_ci struct xrep_find_ag_btree *fab, 45562306a36Sopenharmony_ci uint64_t owner, 45662306a36Sopenharmony_ci xfs_agblock_t agbno, 45762306a36Sopenharmony_ci bool *done_with_block) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct xfs_mount *mp = ri->sc->mp; 46062306a36Sopenharmony_ci struct xfs_buf *bp; 46162306a36Sopenharmony_ci struct xfs_btree_block *btblock; 46262306a36Sopenharmony_ci xfs_daddr_t daddr; 46362306a36Sopenharmony_ci int block_level; 46462306a36Sopenharmony_ci int error = 0; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci daddr = XFS_AGB_TO_DADDR(mp, ri->sc->sa.pag->pag_agno, agbno); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* 46962306a36Sopenharmony_ci * Blocks in the AGFL have stale contents that might just happen to 47062306a36Sopenharmony_ci * have a matching magic and uuid. We don't want to pull these blocks 47162306a36Sopenharmony_ci * in as part of a tree root, so we have to filter out the AGFL stuff 47262306a36Sopenharmony_ci * here. If the AGFL looks insane we'll just refuse to repair. 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ci if (owner == XFS_RMAP_OWN_AG) { 47562306a36Sopenharmony_ci error = xfs_agfl_walk(mp, ri->agf, ri->agfl_bp, 47662306a36Sopenharmony_ci xrep_findroot_agfl_walk, &agbno); 47762306a36Sopenharmony_ci if (error == -ECANCELED) 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci if (error) 48062306a36Sopenharmony_ci return error; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* 48462306a36Sopenharmony_ci * Read the buffer into memory so that we can see if it's a match for 48562306a36Sopenharmony_ci * our btree type. We have no clue if it is beforehand, and we want to 48662306a36Sopenharmony_ci * avoid xfs_trans_read_buf's behavior of dumping the DONE state (which 48762306a36Sopenharmony_ci * will cause needless disk reads in subsequent calls to this function) 48862306a36Sopenharmony_ci * and logging metadata verifier failures. 48962306a36Sopenharmony_ci * 49062306a36Sopenharmony_ci * Therefore, pass in NULL buffer ops. If the buffer was already in 49162306a36Sopenharmony_ci * memory from some other caller it will already have b_ops assigned. 49262306a36Sopenharmony_ci * If it was in memory from a previous unsuccessful findroot_block 49362306a36Sopenharmony_ci * call, the buffer won't have b_ops but it should be clean and ready 49462306a36Sopenharmony_ci * for us to try to verify if the read call succeeds. The same applies 49562306a36Sopenharmony_ci * if the buffer wasn't in memory at all. 49662306a36Sopenharmony_ci * 49762306a36Sopenharmony_ci * Note: If we never match a btree type with this buffer, it will be 49862306a36Sopenharmony_ci * left in memory with NULL b_ops. This shouldn't be a problem unless 49962306a36Sopenharmony_ci * the buffer gets written. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ci error = xfs_trans_read_buf(mp, ri->sc->tp, mp->m_ddev_targp, daddr, 50262306a36Sopenharmony_ci mp->m_bsize, 0, &bp, NULL); 50362306a36Sopenharmony_ci if (error) 50462306a36Sopenharmony_ci return error; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* Ensure the block magic matches the btree type we're looking for. */ 50762306a36Sopenharmony_ci btblock = XFS_BUF_TO_BLOCK(bp); 50862306a36Sopenharmony_ci ASSERT(fab->buf_ops->magic[1] != 0); 50962306a36Sopenharmony_ci if (btblock->bb_magic != fab->buf_ops->magic[1]) 51062306a36Sopenharmony_ci goto out; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci /* 51362306a36Sopenharmony_ci * If the buffer already has ops applied and they're not the ones for 51462306a36Sopenharmony_ci * this btree type, we know this block doesn't match the btree and we 51562306a36Sopenharmony_ci * can bail out. 51662306a36Sopenharmony_ci * 51762306a36Sopenharmony_ci * If the buffer ops match ours, someone else has already validated 51862306a36Sopenharmony_ci * the block for us, so we can move on to checking if this is a root 51962306a36Sopenharmony_ci * block candidate. 52062306a36Sopenharmony_ci * 52162306a36Sopenharmony_ci * If the buffer does not have ops, nobody has successfully validated 52262306a36Sopenharmony_ci * the contents and the buffer cannot be dirty. If the magic, uuid, 52362306a36Sopenharmony_ci * and structure match this btree type then we'll move on to checking 52462306a36Sopenharmony_ci * if it's a root block candidate. If there is no match, bail out. 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_ci if (bp->b_ops) { 52762306a36Sopenharmony_ci if (bp->b_ops != fab->buf_ops) 52862306a36Sopenharmony_ci goto out; 52962306a36Sopenharmony_ci } else { 53062306a36Sopenharmony_ci ASSERT(!xfs_trans_buf_is_dirty(bp)); 53162306a36Sopenharmony_ci if (!uuid_equal(&btblock->bb_u.s.bb_uuid, 53262306a36Sopenharmony_ci &mp->m_sb.sb_meta_uuid)) 53362306a36Sopenharmony_ci goto out; 53462306a36Sopenharmony_ci /* 53562306a36Sopenharmony_ci * Read verifiers can reference b_ops, so we set the pointer 53662306a36Sopenharmony_ci * here. If the verifier fails we'll reset the buffer state 53762306a36Sopenharmony_ci * to what it was before we touched the buffer. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci bp->b_ops = fab->buf_ops; 54062306a36Sopenharmony_ci fab->buf_ops->verify_read(bp); 54162306a36Sopenharmony_ci if (bp->b_error) { 54262306a36Sopenharmony_ci bp->b_ops = NULL; 54362306a36Sopenharmony_ci bp->b_error = 0; 54462306a36Sopenharmony_ci goto out; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* 54862306a36Sopenharmony_ci * Some read verifiers will (re)set b_ops, so we must be 54962306a36Sopenharmony_ci * careful not to change b_ops after running the verifier. 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* 55462306a36Sopenharmony_ci * This block passes the magic/uuid and verifier tests for this btree 55562306a36Sopenharmony_ci * type. We don't need the caller to try the other tree types. 55662306a36Sopenharmony_ci */ 55762306a36Sopenharmony_ci *done_with_block = true; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* 56062306a36Sopenharmony_ci * Compare this btree block's level to the height of the current 56162306a36Sopenharmony_ci * candidate root block. 56262306a36Sopenharmony_ci * 56362306a36Sopenharmony_ci * If the level matches the root we found previously, throw away both 56462306a36Sopenharmony_ci * blocks because there can't be two candidate roots. 56562306a36Sopenharmony_ci * 56662306a36Sopenharmony_ci * If level is lower in the tree than the root we found previously, 56762306a36Sopenharmony_ci * ignore this block. 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_ci block_level = xfs_btree_get_level(btblock); 57062306a36Sopenharmony_ci if (block_level + 1 == fab->height) { 57162306a36Sopenharmony_ci fab->root = NULLAGBLOCK; 57262306a36Sopenharmony_ci goto out; 57362306a36Sopenharmony_ci } else if (block_level < fab->height) { 57462306a36Sopenharmony_ci goto out; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* 57862306a36Sopenharmony_ci * This is the highest block in the tree that we've found so far. 57962306a36Sopenharmony_ci * Update the btree height to reflect what we've learned from this 58062306a36Sopenharmony_ci * block. 58162306a36Sopenharmony_ci */ 58262306a36Sopenharmony_ci fab->height = block_level + 1; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* 58562306a36Sopenharmony_ci * If this block doesn't have sibling pointers, then it's the new root 58662306a36Sopenharmony_ci * block candidate. Otherwise, the root will be found farther up the 58762306a36Sopenharmony_ci * tree. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_ci if (btblock->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) && 59062306a36Sopenharmony_ci btblock->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK)) 59162306a36Sopenharmony_ci fab->root = agbno; 59262306a36Sopenharmony_ci else 59362306a36Sopenharmony_ci fab->root = NULLAGBLOCK; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci trace_xrep_findroot_block(mp, ri->sc->sa.pag->pag_agno, agbno, 59662306a36Sopenharmony_ci be32_to_cpu(btblock->bb_magic), fab->height - 1); 59762306a36Sopenharmony_ciout: 59862306a36Sopenharmony_ci xfs_trans_brelse(ri->sc->tp, bp); 59962306a36Sopenharmony_ci return error; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci/* 60362306a36Sopenharmony_ci * Do any of the blocks in this rmap record match one of the btrees we're 60462306a36Sopenharmony_ci * looking for? 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_ciSTATIC int 60762306a36Sopenharmony_cixrep_findroot_rmap( 60862306a36Sopenharmony_ci struct xfs_btree_cur *cur, 60962306a36Sopenharmony_ci const struct xfs_rmap_irec *rec, 61062306a36Sopenharmony_ci void *priv) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct xrep_findroot *ri = priv; 61362306a36Sopenharmony_ci struct xrep_find_ag_btree *fab; 61462306a36Sopenharmony_ci xfs_agblock_t b; 61562306a36Sopenharmony_ci bool done; 61662306a36Sopenharmony_ci int error = 0; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* Ignore anything that isn't AG metadata. */ 61962306a36Sopenharmony_ci if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner)) 62062306a36Sopenharmony_ci return 0; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* Otherwise scan each block + btree type. */ 62362306a36Sopenharmony_ci for (b = 0; b < rec->rm_blockcount; b++) { 62462306a36Sopenharmony_ci done = false; 62562306a36Sopenharmony_ci for (fab = ri->btree_info; fab->buf_ops; fab++) { 62662306a36Sopenharmony_ci if (rec->rm_owner != fab->rmap_owner) 62762306a36Sopenharmony_ci continue; 62862306a36Sopenharmony_ci error = xrep_findroot_block(ri, fab, 62962306a36Sopenharmony_ci rec->rm_owner, rec->rm_startblock + b, 63062306a36Sopenharmony_ci &done); 63162306a36Sopenharmony_ci if (error) 63262306a36Sopenharmony_ci return error; 63362306a36Sopenharmony_ci if (done) 63462306a36Sopenharmony_ci break; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci return 0; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/* Find the roots of the per-AG btrees described in btree_info. */ 64262306a36Sopenharmony_ciint 64362306a36Sopenharmony_cixrep_find_ag_btree_roots( 64462306a36Sopenharmony_ci struct xfs_scrub *sc, 64562306a36Sopenharmony_ci struct xfs_buf *agf_bp, 64662306a36Sopenharmony_ci struct xrep_find_ag_btree *btree_info, 64762306a36Sopenharmony_ci struct xfs_buf *agfl_bp) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct xfs_mount *mp = sc->mp; 65062306a36Sopenharmony_ci struct xrep_findroot ri; 65162306a36Sopenharmony_ci struct xrep_find_ag_btree *fab; 65262306a36Sopenharmony_ci struct xfs_btree_cur *cur; 65362306a36Sopenharmony_ci int error; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci ASSERT(xfs_buf_islocked(agf_bp)); 65662306a36Sopenharmony_ci ASSERT(agfl_bp == NULL || xfs_buf_islocked(agfl_bp)); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci ri.sc = sc; 65962306a36Sopenharmony_ci ri.btree_info = btree_info; 66062306a36Sopenharmony_ci ri.agf = agf_bp->b_addr; 66162306a36Sopenharmony_ci ri.agfl_bp = agfl_bp; 66262306a36Sopenharmony_ci for (fab = btree_info; fab->buf_ops; fab++) { 66362306a36Sopenharmony_ci ASSERT(agfl_bp || fab->rmap_owner != XFS_RMAP_OWN_AG); 66462306a36Sopenharmony_ci ASSERT(XFS_RMAP_NON_INODE_OWNER(fab->rmap_owner)); 66562306a36Sopenharmony_ci fab->root = NULLAGBLOCK; 66662306a36Sopenharmony_ci fab->height = 0; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag); 67062306a36Sopenharmony_ci error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri); 67162306a36Sopenharmony_ci xfs_btree_del_cursor(cur, error); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci return error; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci/* Force a quotacheck the next time we mount. */ 67762306a36Sopenharmony_civoid 67862306a36Sopenharmony_cixrep_force_quotacheck( 67962306a36Sopenharmony_ci struct xfs_scrub *sc, 68062306a36Sopenharmony_ci xfs_dqtype_t type) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci uint flag; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci flag = xfs_quota_chkd_flag(type); 68562306a36Sopenharmony_ci if (!(flag & sc->mp->m_qflags)) 68662306a36Sopenharmony_ci return; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci mutex_lock(&sc->mp->m_quotainfo->qi_quotaofflock); 68962306a36Sopenharmony_ci sc->mp->m_qflags &= ~flag; 69062306a36Sopenharmony_ci spin_lock(&sc->mp->m_sb_lock); 69162306a36Sopenharmony_ci sc->mp->m_sb.sb_qflags &= ~flag; 69262306a36Sopenharmony_ci spin_unlock(&sc->mp->m_sb_lock); 69362306a36Sopenharmony_ci xfs_log_sb(sc->tp); 69462306a36Sopenharmony_ci mutex_unlock(&sc->mp->m_quotainfo->qi_quotaofflock); 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci/* 69862306a36Sopenharmony_ci * Attach dquots to this inode, or schedule quotacheck to fix them. 69962306a36Sopenharmony_ci * 70062306a36Sopenharmony_ci * This function ensures that the appropriate dquots are attached to an inode. 70162306a36Sopenharmony_ci * We cannot allow the dquot code to allocate an on-disk dquot block here 70262306a36Sopenharmony_ci * because we're already in transaction context with the inode locked. The 70362306a36Sopenharmony_ci * on-disk dquot should already exist anyway. If the quota code signals 70462306a36Sopenharmony_ci * corruption or missing quota information, schedule quotacheck, which will 70562306a36Sopenharmony_ci * repair corruptions in the quota metadata. 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ciint 70862306a36Sopenharmony_cixrep_ino_dqattach( 70962306a36Sopenharmony_ci struct xfs_scrub *sc) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci int error; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci error = xfs_qm_dqattach_locked(sc->ip, false); 71462306a36Sopenharmony_ci switch (error) { 71562306a36Sopenharmony_ci case -EFSBADCRC: 71662306a36Sopenharmony_ci case -EFSCORRUPTED: 71762306a36Sopenharmony_ci case -ENOENT: 71862306a36Sopenharmony_ci xfs_err_ratelimited(sc->mp, 71962306a36Sopenharmony_ci"inode %llu repair encountered quota error %d, quotacheck forced.", 72062306a36Sopenharmony_ci (unsigned long long)sc->ip->i_ino, error); 72162306a36Sopenharmony_ci if (XFS_IS_UQUOTA_ON(sc->mp) && !sc->ip->i_udquot) 72262306a36Sopenharmony_ci xrep_force_quotacheck(sc, XFS_DQTYPE_USER); 72362306a36Sopenharmony_ci if (XFS_IS_GQUOTA_ON(sc->mp) && !sc->ip->i_gdquot) 72462306a36Sopenharmony_ci xrep_force_quotacheck(sc, XFS_DQTYPE_GROUP); 72562306a36Sopenharmony_ci if (XFS_IS_PQUOTA_ON(sc->mp) && !sc->ip->i_pdquot) 72662306a36Sopenharmony_ci xrep_force_quotacheck(sc, XFS_DQTYPE_PROJ); 72762306a36Sopenharmony_ci fallthrough; 72862306a36Sopenharmony_ci case -ESRCH: 72962306a36Sopenharmony_ci error = 0; 73062306a36Sopenharmony_ci break; 73162306a36Sopenharmony_ci default: 73262306a36Sopenharmony_ci break; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return error; 73662306a36Sopenharmony_ci} 737