xref: /linux/fs/xfs/scrub/dirtree.h (revision da5b2ad1c2f18834cb1ce429e2e5a5cf5cbdf21b)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Copyright (c) 2023-2024 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <djwong@kernel.org>
5  */
6 #ifndef __XFS_SCRUB_DIRTREE_H__
7 #define __XFS_SCRUB_DIRTREE_H__
8 
9 /*
10  * Each of these represents one parent pointer path step in a chain going
11  * up towards the directory tree root.  These are stored inside an xfarray.
12  */
13 struct xchk_dirpath_step {
14 	/* Directory entry name associated with this parent link. */
15 	xfblob_cookie		name_cookie;
16 	unsigned int		name_len;
17 
18 	/* Handle of the parent directory. */
19 	struct xfs_parent_rec	pptr_rec;
20 };
21 
22 enum xchk_dirpath_outcome {
23 	XCHK_DIRPATH_SCANNING = 0,	/* still being put together */
24 	XCHK_DIRPATH_DELETE,		/* delete this path */
25 	XCHK_DIRPATH_CORRUPT,		/* corruption detected in path */
26 	XCHK_DIRPATH_LOOP,		/* cycle detected further up */
27 	XCHK_DIRPATH_STALE,		/* path is stale */
28 	XCHK_DIRPATH_OK,		/* path reaches the root */
29 
30 	XREP_DIRPATH_DELETING,		/* path is being deleted */
31 	XREP_DIRPATH_DELETED,		/* path has been deleted */
32 	XREP_DIRPATH_ADOPTING,		/* path is being adopted */
33 	XREP_DIRPATH_ADOPTED,		/* path has been adopted */
34 };
35 
36 /*
37  * Each of these represents one parent pointer path out of the directory being
38  * scanned.  These exist in-core, and hopefully there aren't more than a
39  * handful of them.
40  */
41 struct xchk_dirpath {
42 	struct list_head	list;
43 
44 	/* Index of the first step in this path. */
45 	xfarray_idx_t		first_step;
46 
47 	/* Index of the second step in this path. */
48 	xfarray_idx_t		second_step;
49 
50 	/* Inodes seen while walking this path. */
51 	struct xino_bitmap	seen_inodes;
52 
53 	/* Number of steps in this path. */
54 	unsigned int		nr_steps;
55 
56 	/* Which path is this? */
57 	unsigned int		path_nr;
58 
59 	/* What did we conclude from following this path? */
60 	enum xchk_dirpath_outcome outcome;
61 };
62 
63 struct xchk_dirtree_outcomes {
64 	/* Number of XCHK_DIRPATH_DELETE */
65 	unsigned int		bad;
66 
67 	/* Number of XCHK_DIRPATH_CORRUPT or XCHK_DIRPATH_LOOP */
68 	unsigned int		suspect;
69 
70 	/* Number of XCHK_DIRPATH_OK */
71 	unsigned int		good;
72 
73 	/* Directory needs to be added to lost+found */
74 	bool			needs_adoption;
75 };
76 
77 struct xchk_dirtree {
78 	struct xfs_scrub	*sc;
79 
80 	/* Root inode that we're looking for. */
81 	xfs_ino_t		root_ino;
82 
83 	/*
84 	 * This is the inode that we're scanning.  The live update hook can
85 	 * continue to be called after xchk_teardown drops sc->ip but before
86 	 * it calls buf_cleanup, so we keep a copy.
87 	 */
88 	xfs_ino_t		scan_ino;
89 
90 	/*
91 	 * If we start deleting redundant paths to this subdirectory, this is
92 	 * the inode number of the surviving parent and the dotdot entry will
93 	 * be set to this value.  If the value is NULLFSINO, then use @root_ino
94 	 * as a stand-in until the orphanage can adopt the subdirectory.
95 	 */
96 	xfs_ino_t		parent_ino;
97 
98 	/* Scratch buffer for scanning pptr xattrs */
99 	struct xfs_parent_rec	pptr_rec;
100 	struct xfs_da_args	pptr_args;
101 
102 	/* Name buffer */
103 	struct xfs_name		xname;
104 	char			namebuf[MAXNAMELEN];
105 
106 	/* Information for reparenting this directory. */
107 	struct xrep_adoption	adoption;
108 
109 	/*
110 	 * Hook into directory updates so that we can receive live updates
111 	 * from other writer threads.
112 	 */
113 	struct xfs_dir_hook	dhook;
114 
115 	/* Parent pointer update arguments. */
116 	struct xfs_parent_args	ppargs;
117 
118 	/* lock for everything below here */
119 	struct mutex		lock;
120 
121 	/* buffer for the live update functions to use for dirent names */
122 	struct xfs_name		hook_xname;
123 	unsigned char		hook_namebuf[MAXNAMELEN];
124 
125 	/*
126 	 * All path steps observed during this scan.  Each of the path
127 	 * steps for a particular pathwalk are recorded in sequential
128 	 * order in the xfarray.  A pathwalk ends either with a step
129 	 * pointing to the root directory (success) or pointing to NULLFSINO
130 	 * (loop detected, empty dir detected, etc).
131 	 */
132 	struct xfarray		*path_steps;
133 
134 	/* All names observed during this scan. */
135 	struct xfblob		*path_names;
136 
137 	/* All paths being tracked by this scanner. */
138 	struct list_head	path_list;
139 
140 	/* Number of paths in path_list. */
141 	unsigned int		nr_paths;
142 
143 	/* Number of parents found by a pptr scan. */
144 	unsigned int		parents_found;
145 
146 	/* Have the path data been invalidated by a concurrent update? */
147 	bool			stale:1;
148 
149 	/* Has the scan been aborted? */
150 	bool			aborted:1;
151 };
152 
153 #define xchk_dirtree_for_each_path_safe(dl, path, n) \
154 	list_for_each_entry_safe((path), (n), &(dl)->path_list, list)
155 
156 #define xchk_dirtree_for_each_path(dl, path) \
157 	list_for_each_entry((path), &(dl)->path_list, list)
158 
159 static inline bool
160 xchk_dirtree_parentless(const struct xchk_dirtree *dl)
161 {
162 	struct xfs_scrub	*sc = dl->sc;
163 
164 	if (sc->ip == sc->mp->m_rootip)
165 		return true;
166 	if (VFS_I(sc->ip)->i_nlink == 0)
167 		return true;
168 	return false;
169 }
170 
171 int xchk_dirtree_find_paths_to_root(struct xchk_dirtree *dl);
172 int xchk_dirpath_append(struct xchk_dirtree *dl, struct xfs_inode *ip,
173 		struct xchk_dirpath *path, const struct xfs_name *name,
174 		const struct xfs_parent_rec *pptr);
175 void xchk_dirtree_evaluate(struct xchk_dirtree *dl,
176 		struct xchk_dirtree_outcomes *oc);
177 
178 #endif /* __XFS_SCRUB_DIRTREE_H__ */
179