fs/xfs/scrub/dir.c

Source file repositories/reference/linux-study-clean/fs/xfs/scrub/dir.c

File Facts

System
Linux kernel
Corpus path
fs/xfs/scrub/dir.c
Extension
.c
Size
31213 bytes
Lines
1184
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct xchk_dirent {
	/* Cookie for retrieval of the dirent name. */
	xfblob_cookie		name_cookie;

	/* Child inode number. */
	xfs_ino_t		ino;

	/* Length of the pptr name. */
	uint8_t			namelen;
};

struct xchk_dir {
	struct xfs_scrub	*sc;

	/* information for parent pointer validation. */
	struct xfs_parent_rec	pptr_rec;
	struct xfs_da_args	pptr_args;

	/* Fixed-size array of xchk_dirent structures. */
	struct xfarray		*dir_entries;

	/* Blobs containing dirent names. */
	struct xfblob		*dir_names;

	/* If we've cycled the ILOCK, we must revalidate deferred dirents. */
	bool			need_revalidate;

	/* Name buffer for dirent revalidation. */
	struct xfs_name		xname;
	uint8_t			namebuf[MAXNAMELEN];
};

/* Scrub a directory entry. */

/* Check that an inode's mode matches a given XFS_DIR3_FT_* type. */
STATIC void
xchk_dir_check_ftype(
	struct xfs_scrub	*sc,
	xfs_fileoff_t		offset,
	struct xfs_inode	*ip,
	int			ftype)
{
	struct xfs_mount	*mp = sc->mp;

	if (!xfs_has_ftype(mp)) {
		if (ftype != XFS_DIR3_FT_UNKNOWN && ftype != XFS_DIR3_FT_DIR)
			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
		return;
	}

	if (xfs_mode_to_ftype(VFS_I(ip)->i_mode) != ftype)
		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);

	/*
	 * Metadata and regular inodes cannot cross trees.  This property
	 * cannot change without a full inode free and realloc cycle, so it's
	 * safe to check this without holding locks.
	 */
	if (xfs_is_metadir_inode(ip) != xfs_is_metadir_inode(sc->ip))
		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
}

/*
 * Try to lock a child file for checking parent pointers.  Returns the inode
 * flags for the locks we now hold, or zero if we failed.
 */
STATIC unsigned int
xchk_dir_lock_child(
	struct xfs_scrub	*sc,
	struct xfs_inode	*ip)
{
	if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED))
		return 0;

	if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) {
		xfs_iunlock(ip, XFS_IOLOCK_SHARED);
		return 0;
	}

	if (!xfs_inode_has_attr_fork(ip) || !xfs_need_iread_extents(&ip->i_af))
		return XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED;

	xfs_iunlock(ip, XFS_ILOCK_SHARED);

	if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
		xfs_iunlock(ip, XFS_IOLOCK_SHARED);
		return 0;
	}

	return XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL;

Annotation

Implementation Notes