1f1184081SDarrick J. Wong /* SPDX-License-Identifier: GPL-2.0-or-later */ 2f1184081SDarrick J. Wong /* 3f1184081SDarrick J. Wong * Copyright (c) 2021-2024 Oracle. All Rights Reserved. 4f1184081SDarrick J. Wong * Author: Darrick J. Wong <djwong@kernel.org> 5f1184081SDarrick J. Wong */ 6f1184081SDarrick J. Wong #ifndef __XFS_SCRUB_NLINKS_H__ 7f1184081SDarrick J. Wong #define __XFS_SCRUB_NLINKS_H__ 8f1184081SDarrick J. Wong 9f1184081SDarrick J. Wong /* Live link count control structure. */ 10f1184081SDarrick J. Wong struct xchk_nlink_ctrs { 11f1184081SDarrick J. Wong struct xfs_scrub *sc; 12f1184081SDarrick J. Wong 13f1184081SDarrick J. Wong /* Shadow link count data and its mutex. */ 14f1184081SDarrick J. Wong struct xfarray *nlinks; 15f1184081SDarrick J. Wong struct mutex lock; 16f1184081SDarrick J. Wong 17f1184081SDarrick J. Wong /* 18f1184081SDarrick J. Wong * The collection step uses a separate iscan context from the compare 19f1184081SDarrick J. Wong * step because the collection iscan coordinates live updates to the 20f1184081SDarrick J. Wong * observation data while this scanner is running. The compare iscan 21f1184081SDarrick J. Wong * is secondary and can be reinitialized as needed. 22f1184081SDarrick J. Wong */ 23f1184081SDarrick J. Wong struct xchk_iscan collect_iscan; 24f1184081SDarrick J. Wong struct xchk_iscan compare_iscan; 2586a1746eSDarrick J. Wong 2686a1746eSDarrick J. Wong /* 2786a1746eSDarrick J. Wong * Hook into directory updates so that we can receive live updates 2886a1746eSDarrick J. Wong * from other writer threads. 2986a1746eSDarrick J. Wong */ 3086a1746eSDarrick J. Wong struct xfs_dir_hook dhook; 31*e6c9e75fSDarrick J. Wong 32*e6c9e75fSDarrick J. Wong /* Orphanage reparenting request. */ 33*e6c9e75fSDarrick J. Wong struct xrep_adoption adoption; 34*e6c9e75fSDarrick J. Wong 35*e6c9e75fSDarrick J. Wong /* Directory entry name, plus the trailing null. */ 36*e6c9e75fSDarrick J. Wong struct xfs_name xname; 37*e6c9e75fSDarrick J. Wong char namebuf[MAXNAMELEN]; 38f1184081SDarrick J. Wong }; 39f1184081SDarrick J. Wong 40f1184081SDarrick J. Wong /* 41f1184081SDarrick J. Wong * In-core link counts for a given inode in the filesystem. 42f1184081SDarrick J. Wong * 43f1184081SDarrick J. Wong * For an empty rootdir, the directory entries and the field to which they are 44f1184081SDarrick J. Wong * accounted are as follows: 45f1184081SDarrick J. Wong * 46f1184081SDarrick J. Wong * Root directory: 47f1184081SDarrick J. Wong * 48f1184081SDarrick J. Wong * . points to self (root.child) 49f1184081SDarrick J. Wong * .. points to self (root.parent) 50f1184081SDarrick J. Wong * f1 points to a child file (f1.parent) 51f1184081SDarrick J. Wong * d1 points to a child dir (d1.parent, root.child) 52f1184081SDarrick J. Wong * 53f1184081SDarrick J. Wong * Subdirectory d1: 54f1184081SDarrick J. Wong * 55f1184081SDarrick J. Wong * . points to self (d1.child) 56f1184081SDarrick J. Wong * .. points to root dir (root.backref) 57f1184081SDarrick J. Wong * f2 points to child file (f2.parent) 58f1184081SDarrick J. Wong * f3 points to root.f1 (f1.parent) 59f1184081SDarrick J. Wong * 60f1184081SDarrick J. Wong * root.nlink == 3 (root.dot, root.dotdot, root.d1) 61f1184081SDarrick J. Wong * d1.nlink == 2 (root.d1, d1.dot) 62f1184081SDarrick J. Wong * f1.nlink == 2 (root.f1, d1.f3) 63f1184081SDarrick J. Wong * f2.nlink == 1 (d1.f2) 64f1184081SDarrick J. Wong */ 65f1184081SDarrick J. Wong struct xchk_nlink { 66f1184081SDarrick J. Wong /* Count of forward links from parent directories to this file. */ 67f1184081SDarrick J. Wong xfs_nlink_t parents; 68f1184081SDarrick J. Wong 69f1184081SDarrick J. Wong /* 70f1184081SDarrick J. Wong * Count of back links to this parent directory from child 71f1184081SDarrick J. Wong * subdirectories. 72f1184081SDarrick J. Wong */ 73f1184081SDarrick J. Wong xfs_nlink_t backrefs; 74f1184081SDarrick J. Wong 75f1184081SDarrick J. Wong /* 76f1184081SDarrick J. Wong * Count of forward links from this directory to all child files and 77f1184081SDarrick J. Wong * the number of dot entries. Should be zero for non-directories. 78f1184081SDarrick J. Wong */ 79f1184081SDarrick J. Wong xfs_nlink_t children; 80f1184081SDarrick J. Wong 81f1184081SDarrick J. Wong /* Record state flags */ 82f1184081SDarrick J. Wong unsigned int flags; 83f1184081SDarrick J. Wong }; 84f1184081SDarrick J. Wong 85f1184081SDarrick J. Wong /* 86f1184081SDarrick J. Wong * This incore link count has been written at least once. We never want to 87f1184081SDarrick J. Wong * store an xchk_nlink that looks uninitialized. 88f1184081SDarrick J. Wong */ 89f1184081SDarrick J. Wong #define XCHK_NLINK_WRITTEN (1U << 0) 90f1184081SDarrick J. Wong 916b631c60SDarrick J. Wong /* Already checked this link count record. */ 92f1184081SDarrick J. Wong #define XCHK_NLINK_COMPARE_SCANNED (1U << 1) 93f1184081SDarrick J. Wong 946b631c60SDarrick J. Wong /* Already made a repair with this link count record. */ 956b631c60SDarrick J. Wong #define XREP_NLINK_DIRTY (1U << 2) 966b631c60SDarrick J. Wong 97f1184081SDarrick J. Wong /* Compute total link count, using large enough variables to detect overflow. */ 98f1184081SDarrick J. Wong static inline uint64_t 99f1184081SDarrick J. Wong xchk_nlink_total(struct xfs_inode *ip, const struct xchk_nlink *live) 100f1184081SDarrick J. Wong { 101f1184081SDarrick J. Wong uint64_t ret = live->parents; 102f1184081SDarrick J. Wong 103f1184081SDarrick J. Wong /* Add one link count for the dot entry of any linked directory. */ 104f1184081SDarrick J. Wong if (ip && S_ISDIR(VFS_I(ip)->i_mode) && VFS_I(ip)->i_nlink) 105f1184081SDarrick J. Wong ret++; 106f1184081SDarrick J. Wong return ret + live->children; 107f1184081SDarrick J. Wong } 108f1184081SDarrick J. Wong 109f1184081SDarrick J. Wong #endif /* __XFS_SCRUB_NLINKS_H__ */ 110