Loading...
Note: File does not exist in v3.1.
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. */
10struct 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 */
58struct 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. */
91static inline uint64_t
92xchk_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__ */