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