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