xref: /linux/fs/xfs/scrub/nlinks.h (revision e7c3696d4692e8046d25f6e63f983e934e12f2c5)
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