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