^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_inode.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "xfs_icache.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "xfs_dir2.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "xfs_dir2_priv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "scrub/scrub.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "scrub/common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* Set us up to scrub parents. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) xchk_setup_parent(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct xfs_scrub *sc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct xfs_inode *ip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) return xchk_setup_inode_contents(sc, ip, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /* Parent pointers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* Look for an entry in a parent pointing to this inode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct xchk_parent_ctx {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct dir_context dc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct xfs_scrub *sc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) xfs_ino_t ino;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) xfs_nlink_t nlink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) bool cancelled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /* Look for a single entry in a directory pointing to an inode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) STATIC int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) xchk_parent_actor(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct dir_context *dc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) int namelen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) loff_t pos,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) u64 ino,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) unsigned type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct xchk_parent_ctx *spc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) int error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) spc = container_of(dc, struct xchk_parent_ctx, dc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (spc->ino == ino)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) spc->nlink++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * If we're facing a fatal signal, bail out. Store the cancellation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * status separately because the VFS readdir code squashes error codes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * into short directory reads.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (xchk_should_terminate(spc->sc, &error))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) spc->cancelled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* Count the number of dentries in the parent dir that point to this inode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) STATIC int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) xchk_parent_count_parent_dentries(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct xfs_scrub *sc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct xfs_inode *parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) xfs_nlink_t *nlink)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct xchk_parent_ctx spc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .dc.actor = xchk_parent_actor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .ino = sc->ip->i_ino,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .sc = sc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) size_t bufsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) loff_t oldpos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) uint lock_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * If there are any blocks, read-ahead block 0 as we're almost
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * certain to have the next operation be a read there. This is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * how we guarantee that the parent's extent map has been loaded,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * if there is one.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) lock_mode = xfs_ilock_data_map_shared(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (parent->i_df.if_nextents > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) error = xfs_dir3_data_readahead(parent, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) xfs_iunlock(parent, lock_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * Iterate the parent dir to confirm that there is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * exactly one entry pointing back to the inode being
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * scanned.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) bufsize = (size_t)min_t(loff_t, XFS_READDIR_BUFSIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) parent->i_d.di_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) oldpos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) while (true) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) error = xfs_readdir(sc->tp, parent, &spc.dc, bufsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (spc.cancelled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) error = -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (oldpos == spc.dc.pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) oldpos = spc.dc.pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) *nlink = spc.nlink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return error;
^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) * Given the inode number of the alleged parent of the inode being
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * scrubbed, try to validate that the parent has exactly one directory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * entry pointing back to the inode being scrubbed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) STATIC int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) xchk_parent_validate(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct xfs_scrub *sc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) xfs_ino_t dnum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) bool *try_again)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) struct xfs_mount *mp = sc->mp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct xfs_inode *dp = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) xfs_nlink_t expected_nlink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) xfs_nlink_t nlink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) int error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) *try_again = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* '..' must not point to ourselves. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (sc->ip->i_ino == dnum) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * If we're an unlinked directory, the parent /won't/ have a link
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * to us. Otherwise, it should have one link.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) expected_nlink = VFS_I(sc->ip)->i_nlink == 0 ? 0 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * Grab this parent inode. We release the inode before we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * cancel the scrub transaction. Since we're don't know a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * priori that releasing the inode won't trigger eofblocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * cleanup (which allocates what would be a nested transaction)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * if the parent pointer erroneously points to a file, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * can't use DONTCACHE here because DONTCACHE inodes can trigger
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * immediate inactive cleanup of the inode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * If _iget returns -EINVAL then the parent inode number is garbage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * and the directory is corrupt. If the _iget returns -EFSCORRUPTED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * or -EFSBADCRC then the parent is corrupt which is a cross
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * referencing error. Any other error is an operational error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) error = xfs_iget(mp, sc->tp, dnum, XFS_IGET_UNTRUSTED, 0, &dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (error == -EINVAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) error = -EFSCORRUPTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (dp == sc->ip || !S_ISDIR(VFS_I(dp)->i_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) goto out_rele;
^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) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * We prefer to keep the inode locked while we lock and search
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * its alleged parent for a forward reference. If we can grab
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * the iolock, validate the pointers and we're done. We must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * use nowait here to avoid an ABBA deadlock on the parent and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * the child inodes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (xfs_ilock_nowait(dp, XFS_IOLOCK_SHARED)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) error = xchk_parent_count_parent_dentries(sc, dp, &nlink);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) &error))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (nlink != expected_nlink)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * The game changes if we get here. We failed to lock the parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * so we're going to try to verify both pointers while only holding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * one lock so as to avoid deadlocking with something that's actually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * trying to traverse down the directory tree.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) xfs_iunlock(sc->ip, sc->ilock_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) sc->ilock_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) error = xchk_ilock_inverted(dp, XFS_IOLOCK_SHARED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) goto out_rele;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /* Go looking for our dentry. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) error = xchk_parent_count_parent_dentries(sc, dp, &nlink);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /* Drop the parent lock, relock this inode. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) xfs_iunlock(dp, XFS_IOLOCK_SHARED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) error = xchk_ilock_inverted(sc->ip, XFS_IOLOCK_EXCL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) goto out_rele;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) sc->ilock_flags = XFS_IOLOCK_EXCL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * If we're an unlinked directory, the parent /won't/ have a link
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * to us. Otherwise, it should have one link. We have to re-set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * it here because we dropped the lock on sc->ip.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) expected_nlink = VFS_I(sc->ip)->i_nlink == 0 ? 0 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) /* Look up '..' to see if the inode changed. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) error = xfs_dir_lookup(sc->tp, sc->ip, &xfs_name_dotdot, &dnum, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) goto out_rele;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /* Drat, parent changed. Try again! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (dnum != dp->i_ino) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) xfs_irele(dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) *try_again = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) xfs_irele(dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * '..' didn't change, so check that there was only one entry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) * for us in the parent.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (nlink != expected_nlink)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) out_unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) xfs_iunlock(dp, XFS_IOLOCK_SHARED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) out_rele:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) xfs_irele(dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /* Scrub a parent pointer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) xchk_parent(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct xfs_scrub *sc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) struct xfs_mount *mp = sc->mp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) xfs_ino_t dnum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) bool try_again;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int tries = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) int error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * If we're a directory, check that the '..' link points up to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) * a directory that has one entry pointing to us.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (!S_ISDIR(VFS_I(sc->ip)->i_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /* We're not a special inode, are we? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (!xfs_verify_dir_ino(mp, sc->ip->i_ino)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) * The VFS grabs a read or write lock via i_rwsem before it reads
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) * or writes to a directory. If we've gotten this far we've
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * already obtained IOLOCK_EXCL, which (since 4.10) is the same as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * getting a write lock on i_rwsem. Therefore, it is safe for us
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) * to drop the ILOCK here in order to do directory lookups.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) sc->ilock_flags &= ~(XFS_ILOCK_EXCL | XFS_MMAPLOCK_EXCL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) xfs_iunlock(sc->ip, XFS_ILOCK_EXCL | XFS_MMAPLOCK_EXCL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) /* Look up '..' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) error = xfs_dir_lookup(sc->tp, sc->ip, &xfs_name_dotdot, &dnum, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (!xfs_verify_dir_ino(mp, dnum)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) /* Is this the root dir? Then '..' must point to itself. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (sc->ip == mp->m_rootip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) if (sc->ip->i_ino != mp->m_sb.sb_rootino ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) sc->ip->i_ino != dnum)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) error = xchk_parent_validate(sc, dnum, &try_again);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) } while (try_again && ++tries < 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) * We gave it our best shot but failed, so mark this scrub
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) * incomplete. Userspace can decide if it wants to try again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (try_again && tries == 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) xchk_set_incomplete(sc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) * If we failed to lock the parent inode even after a retry, just mark
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) * this scrub incomplete and return.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if ((sc->flags & XCHK_TRY_HARDER) && error == -EDEADLOCK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) error = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) xchk_set_incomplete(sc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }