^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2017 Oracle. All Rights Reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author: Darrick J. Wong <darrick.wong@oracle.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include "xfs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include "xfs_fs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include "xfs_shared.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "xfs_format.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "xfs_trans_resv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "xfs_mount.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "xfs_log_format.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "xfs_trans.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "xfs_inode.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "xfs_quota.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "xfs_qm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "xfs_errortag.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "xfs_error.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "xfs_scrub.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "scrub/scrub.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "scrub/common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "scrub/trace.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "scrub/repair.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include "scrub/health.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * Online Scrub and Repair
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * Traditionally, XFS (the kernel driver) did not know how to check or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * repair on-disk data structures. That task was left to the xfs_check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * and xfs_repair tools, both of which require taking the filesystem
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * offline for a thorough but time consuming examination. Online
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * scrub & repair, on the other hand, enables us to check the metadata
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * for obvious errors while carefully stepping around the filesystem's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * ongoing operations, locking rules, etc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * Given that most XFS metadata consist of records stored in a btree,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * most of the checking functions iterate the btree blocks themselves
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * looking for irregularities. When a record block is encountered, each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * record can be checked for obviously bad values. Record values can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * also be cross-referenced against other btrees to look for potential
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * misunderstandings between pieces of metadata.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * It is expected that the checkers responsible for per-AG metadata
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * structures will lock the AG headers (AGI, AGF, AGFL), iterate the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * metadata structure, and perform any relevant cross-referencing before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * unlocking the AG and returning the results to userspace. These
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * scrubbers must not keep an AG locked for too long to avoid tying up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * the block and inode allocators.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * Block maps and b-trees rooted in an inode present a special challenge
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * because they can involve extents from any AG. The general scrubber
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * structure of lock -> check -> xref -> unlock still holds, but AG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * locking order rules /must/ be obeyed to avoid deadlocks. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * ordering rule, of course, is that we must lock in increasing AG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * order. Helper functions are provided to track which AG headers we've
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * already locked. If we detect an imminent locking order violation, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * can signal a potential deadlock, in which case the scrubber can jump
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * out to the top level, lock all the AGs in order, and retry the scrub.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * For file data (directories, extended attributes, symlinks) scrub, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * can simply lock the inode and walk the data. For btree data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * (directories and attributes) we follow the same btree-scrubbing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * strategy outlined previously to check the records.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * We use a bit of trickery with transactions to avoid buffer deadlocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * if there is a cycle in the metadata. The basic problem is that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * travelling down a btree involves locking the current buffer at each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * tree level. If a pointer should somehow point back to a buffer that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * we've already examined, we will deadlock due to the second buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * locking attempt. Note however that grabbing a buffer in transaction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * context links the locked buffer to the transaction. If we try to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * re-grab the buffer in the context of the same transaction, we avoid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * the second lock attempt and continue. Between the verifier and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * scrubber, something will notice that something is amiss and report
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * the corruption. Therefore, each scrubber will allocate an empty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * transaction, attach buffers to it, and cancel the transaction at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * end of the scrub run. Cancelling a non-dirty transaction simply
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * unlocks the buffers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * There are four pieces of data that scrub can communicate to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * userspace. The first is the error code (errno), which can be used to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * communicate operational errors in performing the scrub. There are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * also three flags that can be set in the scrub context. If the data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * structure itself is corrupt, the CORRUPT flag will be set. If
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * the metadata is correct but otherwise suboptimal, the PREEN flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * will be set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * We perform secondary validation of filesystem metadata by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * cross-referencing every record with all other available metadata.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * For example, for block mapping extents, we verify that there are no
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * records in the free space and inode btrees corresponding to that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * space extent and that there is a corresponding entry in the reverse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * mapping btree. Inconsistent metadata is noted by setting the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * XCORRUPT flag; btree query function errors are noted by setting the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * XFAIL flag and deleting the cursor to prevent further attempts to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * cross-reference with a defective btree.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * If a piece of metadata proves corrupt or suboptimal, the userspace
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * program can ask the kernel to apply some tender loving care (TLC) to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * the metadata object by setting the REPAIR flag and re-calling the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * scrub ioctl. "Corruption" is defined by metadata violating the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * on-disk specification; operations cannot continue if the violation is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * left untreated. It is possible for XFS to continue if an object is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * "suboptimal", however performance may be degraded. Repairs are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * usually performed by rebuilding the metadata entirely out of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * redundant metadata. Optimizing, on the other hand, can sometimes be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * done without rebuilding entire structures.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * Generally speaking, the repair code has the following code structure:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * Lock -> scrub -> repair -> commit -> re-lock -> re-scrub -> unlock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * The first check helps us figure out if we need to rebuild or simply
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * optimize the structure so that the rebuild knows what to do. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * second check evaluates the completeness of the repair; that is what
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * is reported to userspace.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * A quick note on symbol prefixes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * - "xfs_" are general XFS symbols.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * - "xchk_" are symbols related to metadata checking.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * - "xrep_" are symbols related to metadata repair.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * - "xfs_scrub_" are symbols that tie online fsck to the rest of XFS.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * Scrub probe -- userspace uses this to probe if we're willing to scrub
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * or repair a given mountpoint. This will be used by xfs_scrub to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * probe the kernel's abilities to scrub (and repair) the metadata. We
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * do this by validating the ioctl inputs from userspace, preparing the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * filesystem for a scrub (or a repair) operation, and immediately
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * returning to userspace. Userspace can use the returned errno and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * structure state to decide (in broad terms) if scrub/repair are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * supported by the running kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) xchk_probe(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct xfs_scrub *sc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) int error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (xchk_should_terminate(sc, &error))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* Scrub setup and teardown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /* Free all the resources and finish the transactions. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) STATIC int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) xchk_teardown(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) struct xfs_scrub *sc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) struct xfs_inode *ip_in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) int error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) xchk_ag_free(sc, &sc->sa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (sc->tp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (error == 0 && (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) error = xfs_trans_commit(sc->tp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) xfs_trans_cancel(sc->tp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) sc->tp = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (sc->ip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (sc->ilock_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) xfs_iunlock(sc->ip, sc->ilock_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (sc->ip != ip_in &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) !xfs_internal_inum(sc->mp, sc->ip->i_ino))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) xfs_irele(sc->ip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) sc->ip = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) sb_end_write(sc->mp->m_super);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (sc->flags & XCHK_REAPING_DISABLED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) xchk_start_reaping(sc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (sc->flags & XCHK_HAS_QUOTAOFFLOCK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) mutex_unlock(&sc->mp->m_quotainfo->qi_quotaofflock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) sc->flags &= ~XCHK_HAS_QUOTAOFFLOCK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (sc->buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) kmem_free(sc->buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) sc->buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) /* Scrubbing dispatch. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static const struct xchk_meta_ops meta_scrub_ops[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) [XFS_SCRUB_TYPE_PROBE] = { /* ioctl presence test */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .type = ST_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .setup = xchk_setup_fs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .scrub = xchk_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .repair = xrep_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) [XFS_SCRUB_TYPE_SB] = { /* superblock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .type = ST_PERAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) .setup = xchk_setup_fs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) .scrub = xchk_superblock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) .repair = xrep_superblock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) [XFS_SCRUB_TYPE_AGF] = { /* agf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) .type = ST_PERAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .setup = xchk_setup_fs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) .scrub = xchk_agf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) .repair = xrep_agf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) [XFS_SCRUB_TYPE_AGFL]= { /* agfl */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) .type = ST_PERAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) .setup = xchk_setup_fs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) .scrub = xchk_agfl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) .repair = xrep_agfl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) [XFS_SCRUB_TYPE_AGI] = { /* agi */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) .type = ST_PERAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) .setup = xchk_setup_fs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) .scrub = xchk_agi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) .repair = xrep_agi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) [XFS_SCRUB_TYPE_BNOBT] = { /* bnobt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) .type = ST_PERAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) .setup = xchk_setup_ag_allocbt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .scrub = xchk_bnobt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) [XFS_SCRUB_TYPE_CNTBT] = { /* cntbt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) .type = ST_PERAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) .setup = xchk_setup_ag_allocbt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) .scrub = xchk_cntbt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) [XFS_SCRUB_TYPE_INOBT] = { /* inobt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) .type = ST_PERAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) .setup = xchk_setup_ag_iallocbt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) .scrub = xchk_inobt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) [XFS_SCRUB_TYPE_FINOBT] = { /* finobt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .type = ST_PERAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) .setup = xchk_setup_ag_iallocbt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) .scrub = xchk_finobt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) .has = xfs_sb_version_hasfinobt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) [XFS_SCRUB_TYPE_RMAPBT] = { /* rmapbt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .type = ST_PERAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) .setup = xchk_setup_ag_rmapbt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) .scrub = xchk_rmapbt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) .has = xfs_sb_version_hasrmapbt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) [XFS_SCRUB_TYPE_REFCNTBT] = { /* refcountbt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) .type = ST_PERAG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) .setup = xchk_setup_ag_refcountbt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) .scrub = xchk_refcountbt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) .has = xfs_sb_version_hasreflink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) [XFS_SCRUB_TYPE_INODE] = { /* inode record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) .type = ST_INODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) .setup = xchk_setup_inode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) .scrub = xchk_inode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) [XFS_SCRUB_TYPE_BMBTD] = { /* inode data fork */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) .type = ST_INODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) .setup = xchk_setup_inode_bmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) .scrub = xchk_bmap_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) [XFS_SCRUB_TYPE_BMBTA] = { /* inode attr fork */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) .type = ST_INODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) .setup = xchk_setup_inode_bmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) .scrub = xchk_bmap_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) [XFS_SCRUB_TYPE_BMBTC] = { /* inode CoW fork */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) .type = ST_INODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) .setup = xchk_setup_inode_bmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) .scrub = xchk_bmap_cow,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) [XFS_SCRUB_TYPE_DIR] = { /* directory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) .type = ST_INODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) .setup = xchk_setup_directory,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) .scrub = xchk_directory,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) [XFS_SCRUB_TYPE_XATTR] = { /* extended attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) .type = ST_INODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) .setup = xchk_setup_xattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) .scrub = xchk_xattr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) [XFS_SCRUB_TYPE_SYMLINK] = { /* symbolic link */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) .type = ST_INODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) .setup = xchk_setup_symlink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) .scrub = xchk_symlink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) [XFS_SCRUB_TYPE_PARENT] = { /* parent pointers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) .type = ST_INODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) .setup = xchk_setup_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) .scrub = xchk_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) [XFS_SCRUB_TYPE_RTBITMAP] = { /* realtime bitmap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) .type = ST_FS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) .setup = xchk_setup_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) .scrub = xchk_rtbitmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) .has = xfs_sb_version_hasrealtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) [XFS_SCRUB_TYPE_RTSUM] = { /* realtime summary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) .type = ST_FS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) .setup = xchk_setup_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) .scrub = xchk_rtsummary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .has = xfs_sb_version_hasrealtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) [XFS_SCRUB_TYPE_UQUOTA] = { /* user quota */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .type = ST_FS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .setup = xchk_setup_quota,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .scrub = xchk_quota,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) [XFS_SCRUB_TYPE_GQUOTA] = { /* group quota */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) .type = ST_FS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) .setup = xchk_setup_quota,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) .scrub = xchk_quota,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) [XFS_SCRUB_TYPE_PQUOTA] = { /* project quota */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) .type = ST_FS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) .setup = xchk_setup_quota,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) .scrub = xchk_quota,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) [XFS_SCRUB_TYPE_FSCOUNTERS] = { /* fs summary counters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) .type = ST_FS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) .setup = xchk_setup_fscounters,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) .scrub = xchk_fscounters,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) .repair = xrep_notsupported,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /* This isn't a stable feature, warn once per day. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) xchk_experimental_warning(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct xfs_mount *mp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) static struct ratelimit_state scrub_warning = RATELIMIT_STATE_INIT(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) "xchk_warning", 86400 * HZ, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) ratelimit_set_flags(&scrub_warning, RATELIMIT_MSG_ON_RELEASE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (__ratelimit(&scrub_warning))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) xfs_alert(mp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) "EXPERIMENTAL online scrub feature in use. Use at your own risk!");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) xchk_validate_inputs(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) struct xfs_mount *mp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) struct xfs_scrub_metadata *sm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) const struct xchk_meta_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) error = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) /* Check our inputs. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (sm->sm_flags & ~XFS_SCRUB_FLAGS_IN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) /* sm_reserved[] must be zero */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (memchr_inv(sm->sm_reserved, 0, sizeof(sm->sm_reserved)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) error = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) /* Do we know about this type of metadata? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (sm->sm_type >= XFS_SCRUB_TYPE_NR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) ops = &meta_scrub_ops[sm->sm_type];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) if (ops->setup == NULL || ops->scrub == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) /* Does this fs even support this type of metadata? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (ops->has && !ops->has(&mp->m_sb))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) error = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) /* restricting fields must be appropriate for type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) switch (ops->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) case ST_NONE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) case ST_FS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) if (sm->sm_ino || sm->sm_gen || sm->sm_agno)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) case ST_PERAG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) if (sm->sm_ino || sm->sm_gen ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) sm->sm_agno >= mp->m_sb.sb_agcount)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) case ST_INODE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (sm->sm_agno || (sm->sm_gen && !sm->sm_ino))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) * We only want to repair read-write v5+ filesystems. Defer the check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) * for ops->repair until after our scrub confirms that we need to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) * perform repairs so that we avoid failing due to not supporting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) * repairing an object that doesn't need repairs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if (sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) error = -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (!xfs_sb_version_hascrc(&mp->m_sb))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) error = -EROFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (mp->m_flags & XFS_MOUNT_RDONLY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) #ifdef CONFIG_XFS_ONLINE_REPAIR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) static inline void xchk_postmortem(struct xfs_scrub *sc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) * Userspace asked us to repair something, we repaired it, rescanned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) * it, and the rescan says it's still broken. Scream about this in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) * the system logs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) if ((sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) (sc->sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) XFS_SCRUB_OFLAG_XCORRUPT)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) xrep_failure(sc->mp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) static inline void xchk_postmortem(struct xfs_scrub *sc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) * Userspace asked us to scrub something, it's broken, and we have no
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) * way of fixing it. Scream in the logs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) if (sc->sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) XFS_SCRUB_OFLAG_XCORRUPT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) xfs_alert_ratelimited(sc->mp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) "Corruption detected during scrub.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) #endif /* CONFIG_XFS_ONLINE_REPAIR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) /* Dispatch metadata scrubbing. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) xfs_scrub_metadata(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) struct xfs_inode *ip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) struct xfs_scrub_metadata *sm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) struct xfs_scrub sc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) .mp = ip->i_mount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) .sm = sm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) .sa = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) .agno = NULLAGNUMBER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) struct xfs_mount *mp = ip->i_mount;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) int error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) BUILD_BUG_ON(sizeof(meta_scrub_ops) !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) (sizeof(struct xchk_meta_ops) * XFS_SCRUB_TYPE_NR));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) trace_xchk_start(ip, sm, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) /* Forbidden if we are shut down or mounted norecovery. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) error = -ESHUTDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) if (XFS_FORCED_SHUTDOWN(mp))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) error = -ENOTRECOVERABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) if (mp->m_flags & XFS_MOUNT_NORECOVERY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) error = xchk_validate_inputs(mp, sm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) xchk_experimental_warning(mp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) sc.ops = &meta_scrub_ops[sm->sm_type];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) sc.sick_mask = xchk_health_mask_for_scrub_type(sm->sm_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) retry_op:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) * If freeze runs concurrently with a scrub, the freeze can be delayed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) * indefinitely as we walk the filesystem and iterate over metadata
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * buffers. Freeze quiesces the log (which waits for the buffer LRU to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) * be emptied) and that won't happen while checking is running.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) sb_start_write(mp->m_super);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) /* Set up for the operation. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) error = sc.ops->setup(&sc, ip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) goto out_teardown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) /* Scrub for errors. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) error = sc.ops->scrub(&sc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (!(sc.flags & XCHK_TRY_HARDER) && error == -EDEADLOCK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) * Scrubbers return -EDEADLOCK to mean 'try harder'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) * Tear down everything we hold, then set up again with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) * preparation for worst-case scenarios.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) error = xchk_teardown(&sc, ip, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) sc.flags |= XCHK_TRY_HARDER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) goto retry_op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) } else if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) goto out_teardown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) xchk_update_health(&sc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) if ((sc.sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) !(sc.flags & XREP_ALREADY_FIXED)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) bool needs_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) /* Let debug users force us into the repair routines. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_FORCE_SCRUB_REPAIR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) sc.sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) needs_fix = (sc.sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) XFS_SCRUB_OFLAG_XCORRUPT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) XFS_SCRUB_OFLAG_PREEN));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) * If userspace asked for a repair but it wasn't necessary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) * report that back to userspace.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (!needs_fix) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) sc.sm->sm_flags |= XFS_SCRUB_OFLAG_NO_REPAIR_NEEDED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) goto out_nofix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) * If it's broken, userspace wants us to fix it, and we haven't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) * already tried to fix it, then attempt a repair.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) error = xrep_attempt(ip, &sc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) if (error == -EAGAIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) * Either the repair function succeeded or it couldn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) * get all the resources it needs; either way, we go
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * back to the beginning and call the scrub function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) error = xchk_teardown(&sc, ip, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) xrep_failure(mp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) goto retry_op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) out_nofix:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) xchk_postmortem(&sc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) out_teardown:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) error = xchk_teardown(&sc, ip, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) trace_xchk_done(ip, sm, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (error == -EFSCORRUPTED || error == -EFSBADCRC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) }