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
xchk_nlink_total(struct xfs_inode * ip,const struct xchk_nlink * live)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