// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2022-2023 Oracle. All Rights Reserved. * Author: Darrick J. Wong <[email protected]> */ #include "xfs.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_inode.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_trace.h" #include "xfs_bmap.h" #include "xfs_trans.h" #include "xfs_error.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/readdir.h" /* Call a function for every entry in a shortform directory. */ STATIC int xchk_dir_walk_sf( struct xfs_scrub *sc, struct xfs_inode *dp, xchk_dirent_fn dirent_fn, void *priv) { … } /* Call a function for every entry in a block directory. */ STATIC int xchk_dir_walk_block( struct xfs_scrub *sc, struct xfs_inode *dp, xchk_dirent_fn dirent_fn, void *priv) { … } /* Read a leaf-format directory buffer. */ STATIC int xchk_read_leaf_dir_buf( struct xfs_trans *tp, struct xfs_inode *dp, struct xfs_da_geometry *geo, xfs_dir2_off_t *curoff, struct xfs_buf **bpp) { … } /* Call a function for every entry in a leaf directory. */ STATIC int xchk_dir_walk_leaf( struct xfs_scrub *sc, struct xfs_inode *dp, xchk_dirent_fn dirent_fn, void *priv) { … } /* * Call a function for every entry in a directory. * * Callers must hold the ILOCK. File types are XFS_DIR3_FT_*. */ int xchk_dir_walk( struct xfs_scrub *sc, struct xfs_inode *dp, xchk_dirent_fn dirent_fn, void *priv) { … } /* * Look up the inode number for an exact name in a directory. * * Callers must hold the ILOCK. File types are XFS_DIR3_FT_*. Names are not * checked for correctness. */ int xchk_dir_lookup( struct xfs_scrub *sc, struct xfs_inode *dp, const struct xfs_name *name, xfs_ino_t *ino) { … } /* * Try to grab the IOLOCK and ILOCK of sc->ip and ip, returning @ip's lock * state. The caller may have a transaction, so we must use trylock for both * IOLOCKs. */ static inline unsigned int xchk_dir_trylock_both( struct xfs_scrub *sc, struct xfs_inode *ip) { … } /* * Try for a limited time to grab the IOLOCK and ILOCK of both the scrub target * (@sc->ip) and the inode at the other end (@ip) of a directory or parent * pointer link so that we can check that link. * * We do not know ahead of time that the directory tree is /not/ corrupt, so we * cannot use the "lock two inode" functions because we do not know that there * is not a racing thread trying to take the locks in opposite order. First * take IOLOCK_EXCL of the scrub target, and then try to take IOLOCK_SHARED * of @ip to synchronize with the VFS. Next, take ILOCK_EXCL of the scrub * target and @ip to synchronize with XFS. * * If the trylocks succeed, *lockmode will be set to the locks held for @ip; * @sc->ilock_flags will be set for the locks held for @sc->ip; and zero will * be returned. If not, returns -EDEADLOCK to try again; or -ETIMEDOUT if * XCHK_TRY_HARDER was set. Returns -EINTR if the process has been killed. */ int xchk_dir_trylock_for_pptrs( struct xfs_scrub *sc, struct xfs_inode *ip, unsigned int *lockmode) { … }