| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- /* SPDX-License-Identifier: GPL-2.0-or-later */
- /*
- * Copyright (c) 2023-2024 Oracle. All Rights Reserved.
- * Author: Darrick J. Wong <djwong@kernel.org>
- */
- #ifndef __XFS_SCRUB_DIRTREE_H__
- #define __XFS_SCRUB_DIRTREE_H__
- /*
- * Each of these represents one parent pointer path step in a chain going
- * up towards the directory tree root. These are stored inside an xfarray.
- */
- struct xchk_dirpath_step {
- /* Directory entry name associated with this parent link. */
- xfblob_cookie name_cookie;
- unsigned int name_len;
- /* Handle of the parent directory. */
- struct xfs_parent_rec pptr_rec;
- };
- enum xchk_dirpath_outcome {
- XCHK_DIRPATH_SCANNING = 0, /* still being put together */
- XCHK_DIRPATH_DELETE, /* delete this path */
- XCHK_DIRPATH_CORRUPT, /* corruption detected in path */
- XCHK_DIRPATH_LOOP, /* cycle detected further up */
- XCHK_DIRPATH_STALE, /* path is stale */
- XCHK_DIRPATH_OK, /* path reaches the root */
- XREP_DIRPATH_DELETING, /* path is being deleted */
- XREP_DIRPATH_DELETED, /* path has been deleted */
- XREP_DIRPATH_ADOPTING, /* path is being adopted */
- XREP_DIRPATH_ADOPTED, /* path has been adopted */
- };
- /*
- * Each of these represents one parent pointer path out of the directory being
- * scanned. These exist in-core, and hopefully there aren't more than a
- * handful of them.
- */
- struct xchk_dirpath {
- struct list_head list;
- /* Index of the first step in this path. */
- xfarray_idx_t first_step;
- /* Index of the second step in this path. */
- xfarray_idx_t second_step;
- /* Inodes seen while walking this path. */
- struct xino_bitmap seen_inodes;
- /* Number of steps in this path. */
- unsigned int nr_steps;
- /* Which path is this? */
- unsigned int path_nr;
- /* What did we conclude from following this path? */
- enum xchk_dirpath_outcome outcome;
- };
- struct xchk_dirtree_outcomes {
- /* Number of XCHK_DIRPATH_DELETE */
- unsigned int bad;
- /* Number of XCHK_DIRPATH_CORRUPT or XCHK_DIRPATH_LOOP */
- unsigned int suspect;
- /* Number of XCHK_DIRPATH_OK */
- unsigned int good;
- /* Directory needs to be added to lost+found */
- bool needs_adoption;
- };
- struct xchk_dirtree {
- struct xfs_scrub *sc;
- /* Root inode that we're looking for. */
- xfs_ino_t root_ino;
- /*
- * This is the inode that we're scanning. The live update hook can
- * continue to be called after xchk_teardown drops sc->ip but before
- * it calls buf_cleanup, so we keep a copy.
- */
- xfs_ino_t scan_ino;
- /*
- * If we start deleting redundant paths to this subdirectory, this is
- * the inode number of the surviving parent and the dotdot entry will
- * be set to this value. If the value is NULLFSINO, then use @root_ino
- * as a stand-in until the orphanage can adopt the subdirectory.
- */
- xfs_ino_t parent_ino;
- /* Scratch buffer for scanning pptr xattrs */
- struct xfs_parent_rec pptr_rec;
- struct xfs_da_args pptr_args;
- /* Name buffer */
- struct xfs_name xname;
- char namebuf[MAXNAMELEN];
- /* Information for reparenting this directory. */
- struct xrep_adoption adoption;
- /*
- * Hook into directory updates so that we can receive live updates
- * from other writer threads.
- */
- struct xfs_dir_hook dhook;
- /* Parent pointer update arguments. */
- struct xfs_parent_args ppargs;
- /* lock for everything below here */
- struct mutex lock;
- /* buffer for the live update functions to use for dirent names */
- struct xfs_name hook_xname;
- unsigned char hook_namebuf[MAXNAMELEN];
- /*
- * All path steps observed during this scan. Each of the path
- * steps for a particular pathwalk are recorded in sequential
- * order in the xfarray. A pathwalk ends either with a step
- * pointing to the root directory (success) or pointing to NULLFSINO
- * (loop detected, empty dir detected, etc).
- */
- struct xfarray *path_steps;
- /* All names observed during this scan. */
- struct xfblob *path_names;
- /* All paths being tracked by this scanner. */
- struct list_head path_list;
- /* Number of paths in path_list. */
- unsigned int nr_paths;
- /* Number of parents found by a pptr scan. */
- unsigned int parents_found;
- /* Have the path data been invalidated by a concurrent update? */
- bool stale:1;
- /* Has the scan been aborted? */
- bool aborted:1;
- };
- #define xchk_dirtree_for_each_path_safe(dl, path, n) \
- list_for_each_entry_safe((path), (n), &(dl)->path_list, list)
- #define xchk_dirtree_for_each_path(dl, path) \
- list_for_each_entry((path), &(dl)->path_list, list)
- static inline bool
- xchk_dirtree_parentless(const struct xchk_dirtree *dl)
- {
- struct xfs_scrub *sc = dl->sc;
- if (sc->ip == sc->mp->m_rootip)
- return true;
- if (VFS_I(sc->ip)->i_nlink == 0)
- return true;
- return false;
- }
- int xchk_dirtree_find_paths_to_root(struct xchk_dirtree *dl);
- int xchk_dirpath_append(struct xchk_dirtree *dl, struct xfs_inode *ip,
- struct xchk_dirpath *path, const struct xfs_name *name,
- const struct xfs_parent_rec *pptr);
- void xchk_dirtree_evaluate(struct xchk_dirtree *dl,
- struct xchk_dirtree_outcomes *oc);
- #endif /* __XFS_SCRUB_DIRTREE_H__ */
|