// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2017-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_trans_resv.h" #include "xfs_mount.h" #include "xfs_log_format.h" #include "xfs_trans.h" #include "xfs_inode.h" #include "xfs_icache.h" #include "xfs_dir2.h" #include "xfs_dir2_priv.h" #include "xfs_attr.h" #include "xfs_parent.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/readdir.h" #include "scrub/tempfile.h" #include "scrub/repair.h" #include "scrub/listxattr.h" #include "scrub/xfile.h" #include "scrub/xfarray.h" #include "scrub/xfblob.h" #include "scrub/trace.h" /* Set us up to scrub parents. */ int xchk_setup_parent( struct xfs_scrub *sc) { … } /* Parent pointers */ /* Look for an entry in a parent pointing to this inode. */ struct xchk_parent_ctx { … }; /* Look for a single entry in a directory pointing to an inode. */ STATIC int xchk_parent_actor( struct xfs_scrub *sc, struct xfs_inode *dp, xfs_dir2_dataptr_t dapos, const struct xfs_name *name, xfs_ino_t ino, void *priv) { … } /* * Try to lock a parent directory for checking dirents. Returns the inode * flags for the locks we now hold, or zero if we failed. */ STATIC unsigned int xchk_parent_ilock_dir( struct xfs_inode *dp) { … } /* * Given the inode number of the alleged parent of the inode being scrubbed, * try to validate that the parent has exactly one directory entry pointing * back to the inode being scrubbed. Returns -EAGAIN if we need to revalidate * the dotdot entry. */ STATIC int xchk_parent_validate( struct xfs_scrub *sc, xfs_ino_t parent_ino) { … } /* * Checking of Parent Pointers * =========================== * * On filesystems with directory parent pointers, we check the referential * integrity by visiting each parent pointer of a child file and checking that * the directory referenced by the pointer actually has a dirent pointing * forward to the child file. */ /* Deferred parent pointer entry that we saved for later. */ struct xchk_pptr { … }; struct xchk_pptrs { … }; /* Does this parent pointer match the dotdot entry? */ STATIC int xchk_parent_scan_dotdot( struct xfs_scrub *sc, struct xfs_inode *ip, unsigned int attr_flags, const unsigned char *name, unsigned int namelen, const void *value, unsigned int valuelen, void *priv) { … } /* Look up the dotdot entry so that we can check it as we walk the pptrs. */ STATIC int xchk_parent_pptr_and_dotdot( struct xchk_pptrs *pp) { … } /* * Try to lock a parent directory for checking dirents. Returns the inode * flags for the locks we now hold, or zero if we failed. */ STATIC unsigned int xchk_parent_lock_dir( struct xfs_scrub *sc, struct xfs_inode *dp) { … } /* Check the forward link (dirent) associated with this parent pointer. */ STATIC int xchk_parent_dirent( struct xchk_pptrs *pp, const struct xfs_name *xname, struct xfs_inode *dp) { … } /* Try to grab a parent directory. */ STATIC int xchk_parent_iget( struct xchk_pptrs *pp, const struct xfs_parent_rec *pptr, struct xfs_inode **dpp) { … } /* * Walk an xattr of a file. If this xattr is a parent pointer, follow it up * to a parent directory and check that the parent has a dirent pointing back * to us. */ STATIC int xchk_parent_scan_attr( struct xfs_scrub *sc, struct xfs_inode *ip, unsigned int attr_flags, const unsigned char *name, unsigned int namelen, const void *value, unsigned int valuelen, void *priv) { … } /* * Revalidate a parent pointer that we collected in the past but couldn't check * because of lock contention. Returns 0 if the parent pointer is still valid, * -ENOENT if it has gone away on us, or a negative errno. */ STATIC int xchk_parent_revalidate_pptr( struct xchk_pptrs *pp, const struct xfs_name *xname, struct xfs_parent_rec *pptr) { … } /* * Check a parent pointer the slow way, which means we cycle locks a bunch * and put up with revalidation until we get it done. */ STATIC int xchk_parent_slow_pptr( struct xchk_pptrs *pp, const struct xfs_name *xname, struct xfs_parent_rec *pptr) { … } /* Check all the parent pointers that we deferred the first time around. */ STATIC int xchk_parent_finish_slow_pptrs( struct xchk_pptrs *pp) { … } /* Count the number of parent pointers. */ STATIC int xchk_parent_count_pptr( struct xfs_scrub *sc, struct xfs_inode *ip, unsigned int attr_flags, const unsigned char *name, unsigned int namelen, const void *value, unsigned int valuelen, void *priv) { … } /* * Compare the number of parent pointers to the link count. For * non-directories these should be the same. For unlinked directories the * count should be zero; for linked directories, it should be nonzero. */ STATIC int xchk_parent_count_pptrs( struct xchk_pptrs *pp) { … } /* Check parent pointers of a file. */ STATIC int xchk_parent_pptr( struct xfs_scrub *sc) { … } /* Scrub a parent pointer. */ int xchk_parent( struct xfs_scrub *sc) { … } /* * Decide if this file's extended attributes (and therefore its parent * pointers) have been zapped to satisfy the inode and ifork verifiers. * Checking and repairing should be postponed until the extended attribute * structure is fixed. */ bool xchk_pptr_looks_zapped( struct xfs_inode *ip) { … }