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