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 /* Orphanage reparenting request. */ 33 struct xrep_adoption adoption; 34 35 /* Directory entry name, plus the trailing null. */ 36 struct xfs_name xname; 37 char namebuf[MAXNAMELEN]; 38 }; 39 40 /* 41 * In-core link counts for a given inode in the filesystem. 42 * 43 * For an empty rootdir, the directory entries and the field to which they are 44 * accounted are as follows: 45 * 46 * Root directory: 47 * 48 * . points to self (root.child) 49 * .. points to self (root.parent) 50 * f1 points to a child file (f1.parent) 51 * d1 points to a child dir (d1.parent, root.child) 52 * 53 * Subdirectory d1: 54 * 55 * . points to self (d1.child) 56 * .. points to root dir (root.backref) 57 * f2 points to child file (f2.parent) 58 * f3 points to root.f1 (f1.parent) 59 * 60 * root.nlink == 3 (root.dot, root.dotdot, root.d1) 61 * d1.nlink == 2 (root.d1, d1.dot) 62 * f1.nlink == 2 (root.f1, d1.f3) 63 * f2.nlink == 1 (d1.f2) 64 */ 65 struct xchk_nlink { 66 /* Count of forward links from parent directories to this file. */ 67 xfs_nlink_t parents; 68 69 /* 70 * Count of back links to this parent directory from child 71 * subdirectories. 72 */ 73 xfs_nlink_t backrefs; 74 75 /* 76 * Count of forward links from this directory to all child files and 77 * the number of dot entries. Should be zero for non-directories. 78 */ 79 xfs_nlink_t children; 80 81 /* Record state flags */ 82 unsigned int flags; 83 }; 84 85 /* 86 * This incore link count has been written at least once. We never want to 87 * store an xchk_nlink that looks uninitialized. 88 */ 89 #define XCHK_NLINK_WRITTEN (1U << 0) 90 91 /* Already checked this link count record. */ 92 #define XCHK_NLINK_COMPARE_SCANNED (1U << 1) 93 94 /* Already made a repair with this link count record. */ 95 #define XREP_NLINK_DIRTY (1U << 2) 96 97 /* Compute total link count, using large enough variables to detect overflow. */ 98 static inline uint64_t 99 xchk_nlink_total(struct xfs_inode *ip, const struct xchk_nlink *live) 100 { 101 uint64_t ret = live->parents; 102 103 /* Add one link count for the dot entry of any linked directory. */ 104 if (ip && S_ISDIR(VFS_I(ip)->i_mode) && VFS_I(ip)->i_nlink) 105 ret++; 106 return ret + live->children; 107 } 108 109 #endif /* __XFS_SCRUB_NLINKS_H__ */ 110