mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 06:43:09 +00:00
xfs: refactor directory tree root predicates
Metadata directory trees make reasoning about the parent of a file more difficult. Traditionally, user files are children of sb_rootino, and metadata files are "children" of the superblock. Now, we add a third possibility -- some metadata files can be children of sb_metadirino, but the classic ones (rt free space data and quotas) are left alone. Let's add some helper functions (instead of open-coding the logic everywhere) to make scrub logic easier to understand. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
be42fc1393
commit
679b098b59
@ -1452,3 +1452,32 @@ xchk_inode_is_allocated(
|
||||
rcu_read_unlock();
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Is this inode a root directory for either tree? */
|
||||
bool
|
||||
xchk_inode_is_dirtree_root(const struct xfs_inode *ip)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
|
||||
return ip == mp->m_rootip ||
|
||||
(xfs_has_metadir(mp) && ip == mp->m_metadirip);
|
||||
}
|
||||
|
||||
/* Does the superblock point down to this inode? */
|
||||
bool
|
||||
xchk_inode_is_sb_rooted(const struct xfs_inode *ip)
|
||||
{
|
||||
return xchk_inode_is_dirtree_root(ip) ||
|
||||
xfs_is_sb_inum(ip->i_mount, ip->i_ino);
|
||||
}
|
||||
|
||||
/* What is the root directory inumber for this inode? */
|
||||
xfs_ino_t
|
||||
xchk_inode_rootdir_inum(const struct xfs_inode *ip)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
|
||||
if (xfs_is_metadir_inode(ip))
|
||||
return mp->m_metadirip->i_ino;
|
||||
return mp->m_rootip->i_ino;
|
||||
}
|
||||
|
@ -242,4 +242,8 @@ void xchk_fsgates_enable(struct xfs_scrub *sc, unsigned int scrub_fshooks);
|
||||
int xchk_inode_is_allocated(struct xfs_scrub *sc, xfs_agino_t agino,
|
||||
bool *inuse);
|
||||
|
||||
bool xchk_inode_is_dirtree_root(const struct xfs_inode *ip);
|
||||
bool xchk_inode_is_sb_rooted(const struct xfs_inode *ip);
|
||||
xfs_ino_t xchk_inode_rootdir_inum(const struct xfs_inode *ip);
|
||||
|
||||
#endif /* __XFS_SCRUB_COMMON_H__ */
|
||||
|
@ -253,7 +253,7 @@ xchk_dir_actor(
|
||||
* If this is ".." in the root inode, check that the inum
|
||||
* matches this dir.
|
||||
*/
|
||||
if (dp->i_ino == mp->m_sb.sb_rootino && ino != dp->i_ino)
|
||||
if (xchk_inode_is_dirtree_root(dp) && ino != dp->i_ino)
|
||||
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
|
||||
}
|
||||
|
||||
|
@ -1270,7 +1270,7 @@ xrep_dir_scan_dirtree(
|
||||
int error;
|
||||
|
||||
/* Roots of directory trees are their own parents. */
|
||||
if (sc->ip == sc->mp->m_rootip)
|
||||
if (xchk_inode_is_dirtree_root(sc->ip))
|
||||
xrep_findparent_scan_found(&rd->pscan, sc->ip->i_ino);
|
||||
|
||||
/*
|
||||
|
@ -917,7 +917,7 @@ xchk_dirtree(
|
||||
* scan, because the hook doesn't detach until after sc->ip gets
|
||||
* released during teardown.
|
||||
*/
|
||||
dl->root_ino = sc->mp->m_rootip->i_ino;
|
||||
dl->root_ino = xchk_inode_rootdir_inum(sc->ip);
|
||||
dl->scan_ino = sc->ip->i_ino;
|
||||
|
||||
trace_xchk_dirtree_start(sc->ip, sc->sm, 0);
|
||||
@ -983,3 +983,16 @@ xchk_dirtree(
|
||||
trace_xchk_dirtree_done(sc->ip, sc->sm, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Does the directory targetted by this scrub have no parents? */
|
||||
bool
|
||||
xchk_dirtree_parentless(const struct xchk_dirtree *dl)
|
||||
{
|
||||
struct xfs_scrub *sc = dl->sc;
|
||||
|
||||
if (xchk_inode_is_dirtree_root(sc->ip))
|
||||
return true;
|
||||
if (VFS_I(sc->ip)->i_nlink == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -156,17 +156,7 @@ struct xchk_dirtree {
|
||||
#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;
|
||||
}
|
||||
bool xchk_dirtree_parentless(const struct xchk_dirtree *dl);
|
||||
|
||||
int xchk_dirtree_find_paths_to_root(struct xchk_dirtree *dl);
|
||||
int xchk_dirpath_append(struct xchk_dirtree *dl, struct xfs_inode *ip,
|
||||
|
@ -362,15 +362,18 @@ xrep_findparent_confirm(
|
||||
};
|
||||
int error;
|
||||
|
||||
/*
|
||||
* The root directory always points to itself. Unlinked dirs can point
|
||||
* anywhere, so we point them at the root dir too.
|
||||
*/
|
||||
if (sc->ip == sc->mp->m_rootip || VFS_I(sc->ip)->i_nlink == 0) {
|
||||
/* The root directory always points to itself. */
|
||||
if (sc->ip == sc->mp->m_rootip) {
|
||||
*parent_ino = sc->mp->m_sb.sb_rootino;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unlinked dirs can point anywhere; point them up to the root dir. */
|
||||
if (VFS_I(sc->ip)->i_nlink == 0) {
|
||||
*parent_ino = xchk_inode_rootdir_inum(sc->ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reject garbage parent inode numbers and self-referential parents. */
|
||||
if (*parent_ino == NULLFSINO)
|
||||
return 0;
|
||||
@ -413,7 +416,7 @@ xrep_findparent_self_reference(
|
||||
return sc->mp->m_sb.sb_rootino;
|
||||
|
||||
if (VFS_I(sc->ip)->i_nlink == 0)
|
||||
return sc->mp->m_sb.sb_rootino;
|
||||
return xchk_inode_rootdir_inum(sc->ip);
|
||||
|
||||
return NULLFSINO;
|
||||
}
|
||||
|
@ -1767,15 +1767,8 @@ xrep_inode_pptr(
|
||||
if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE))
|
||||
return 0;
|
||||
|
||||
/* The root directory doesn't have a parent pointer. */
|
||||
if (ip == mp->m_rootip)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Metadata inodes are rooted in the superblock and do not have any
|
||||
* parents.
|
||||
*/
|
||||
if (xfs_is_internal_inode(ip))
|
||||
/* Children of the superblock do not have parent pointers. */
|
||||
if (xchk_inode_is_sb_rooted(ip))
|
||||
return 0;
|
||||
|
||||
/* Inode already has an attr fork; no further work possible here. */
|
||||
|
@ -279,7 +279,7 @@ xchk_nlinks_collect_dirent(
|
||||
* determine the backref count.
|
||||
*/
|
||||
if (dotdot) {
|
||||
if (dp == sc->mp->m_rootip)
|
||||
if (xchk_inode_is_dirtree_root(dp))
|
||||
error = xchk_nlinks_update_incore(xnc, ino, 1, 0, 0);
|
||||
else if (!xfs_has_parent(sc->mp))
|
||||
error = xchk_nlinks_update_incore(xnc, ino, 0, 1, 0);
|
||||
@ -735,7 +735,7 @@ xchk_nlinks_compare_inode(
|
||||
}
|
||||
}
|
||||
|
||||
if (ip == sc->mp->m_rootip) {
|
||||
if (xchk_inode_is_dirtree_root(ip)) {
|
||||
/*
|
||||
* For the root of a directory tree, both the '.' and '..'
|
||||
* entries should point to the root directory. The dotdot
|
||||
|
@ -60,11 +60,9 @@ xrep_nlinks_is_orphaned(
|
||||
unsigned int actual_nlink,
|
||||
const struct xchk_nlink *obs)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
|
||||
if (obs->parents != 0)
|
||||
return false;
|
||||
if (ip == mp->m_rootip || ip == sc->orphanage)
|
||||
if (xchk_inode_is_dirtree_root(ip) || ip == sc->orphanage)
|
||||
return false;
|
||||
return actual_nlink != 0;
|
||||
}
|
||||
|
@ -295,7 +295,9 @@ xrep_orphanage_can_adopt(
|
||||
return false;
|
||||
if (sc->ip == sc->orphanage)
|
||||
return false;
|
||||
if (xfs_is_sb_inum(sc->mp, sc->ip->i_ino))
|
||||
if (xchk_inode_is_sb_rooted(sc->ip))
|
||||
return false;
|
||||
if (xfs_is_internal_inode(sc->ip))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ xchk_parent_pptr_and_dotdot(
|
||||
}
|
||||
|
||||
/* Is this the root dir? Then '..' must point to itself. */
|
||||
if (sc->ip == sc->mp->m_rootip) {
|
||||
if (xchk_inode_is_dirtree_root(sc->ip)) {
|
||||
if (sc->ip->i_ino != pp->parent_ino)
|
||||
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
|
||||
return 0;
|
||||
@ -711,7 +711,7 @@ xchk_parent_count_pptrs(
|
||||
}
|
||||
|
||||
if (S_ISDIR(VFS_I(sc->ip)->i_mode)) {
|
||||
if (sc->ip == sc->mp->m_rootip)
|
||||
if (xchk_inode_is_dirtree_root(sc->ip))
|
||||
pp->pptrs_found++;
|
||||
|
||||
if (VFS_I(sc->ip)->i_nlink == 0 && pp->pptrs_found > 0)
|
||||
@ -885,10 +885,9 @@ bool
|
||||
xchk_pptr_looks_zapped(
|
||||
struct xfs_inode *ip)
|
||||
{
|
||||
struct xfs_mount *mp = ip->i_mount;
|
||||
struct inode *inode = VFS_I(ip);
|
||||
|
||||
ASSERT(xfs_has_parent(mp));
|
||||
ASSERT(xfs_has_parent(ip->i_mount));
|
||||
|
||||
/*
|
||||
* Temporary files that cannot be linked into the directory tree do not
|
||||
@ -902,15 +901,15 @@ xchk_pptr_looks_zapped(
|
||||
* of a parent pointer scan is always the empty set. It's safe to scan
|
||||
* them even if the attr fork was zapped.
|
||||
*/
|
||||
if (ip == mp->m_rootip)
|
||||
if (xchk_inode_is_dirtree_root(ip))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Metadata inodes are all rooted in the superblock and do not have
|
||||
* any parents. Hence the attr fork will not be initialized, but
|
||||
* there are no parent pointers that might have been zapped.
|
||||
* Metadata inodes that are rooted in the superblock do not have any
|
||||
* parents. Hence the attr fork will not be initialized, but there are
|
||||
* no parent pointers that might have been zapped.
|
||||
*/
|
||||
if (xfs_is_internal_inode(ip))
|
||||
if (xchk_inode_is_sb_rooted(ip))
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
@ -1334,7 +1334,7 @@ xrep_parent_rebuild_pptrs(
|
||||
* so that we can decide if we're moving this file to the orphanage.
|
||||
* For this purpose, root directories are their own parents.
|
||||
*/
|
||||
if (sc->ip == sc->mp->m_rootip) {
|
||||
if (xchk_inode_is_dirtree_root(sc->ip)) {
|
||||
xrep_findparent_scan_found(&rp->pscan, sc->ip->i_ino);
|
||||
} else {
|
||||
error = xrep_parent_lookup_pptrs(sc, &parent_ino);
|
||||
|
Loading…
Reference in New Issue
Block a user