]> www.infradead.org Git - users/hch/xfs.git/commitdiff
xfs: refactor directory tree root predicates
authorDarrick J. Wong <djwong@kernel.org>
Wed, 7 Aug 2024 22:54:19 +0000 (15:54 -0700)
committerChristoph Hellwig <hch@lst.de>
Sun, 22 Sep 2024 06:07:19 +0000 (08:07 +0200)
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>
13 files changed:
fs/xfs/scrub/common.c
fs/xfs/scrub/common.h
fs/xfs/scrub/dir.c
fs/xfs/scrub/dir_repair.c
fs/xfs/scrub/dirtree.c
fs/xfs/scrub/dirtree.h
fs/xfs/scrub/findparent.c
fs/xfs/scrub/inode_repair.c
fs/xfs/scrub/nlinks.c
fs/xfs/scrub/nlinks_repair.c
fs/xfs/scrub/orphanage.c
fs/xfs/scrub/parent.c
fs/xfs/scrub/parent_repair.c

index 9d74c315418ffbef5d7ef6ac96d20f366be0c50d..a1e67b0f745f358b9a3bf43a9f2b3858c3adc0a8 100644 (file)
@@ -1452,3 +1452,32 @@ out_rcu:
        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_internal_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;
+}
index f3db628b14e1b98ac9cc28c3c040ee31e1b334c6..b419adc6e7cf2abb50c87151351d010b22df9b68 100644 (file)
@@ -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__ */
index bf9199e8df633fa891d5ec160381491eefb31927..6b719c8885ef75f13975432b4b6bfad272c7e21a 100644 (file)
@@ -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);
        }
 
index 64679fe08446505ecd0bb183e52560b0fbe4a95b..0c2cd42b3110f2e9971cbe88750c3dd4889b9d15 100644 (file)
@@ -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);
 
        /*
index bde58fb561ea18dd5fd7483f848cb1ce898c780d..e43840733de9469dfacafc62005a1c54524d5e96 100644 (file)
@@ -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 @@ out:
        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;
+}
index 1e1686365c61c6f61d2645f717b8fb829da22318..9e5d95492717d605f8a875e7b23efec7f70d1c4d 100644 (file)
@@ -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,
index 01766041ba2cd88b8e94a6a67a223f4b19fe3c95..153d185190d8ad08baf5e0aaf65bb4935ff8c421 100644 (file)
@@ -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;
 }
index 1a7d2dfc2f405d19b1f4ac3444fc43e8e80d890d..7700fcd8170448d9533e018131fe4bf71086020e 100644 (file)
@@ -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_metadata_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. */
index 80aee30886c456257f501d478eda84faef82d136..4a47d0aabf73bdf078e3c259139a1b0597d299c6 100644 (file)
@@ -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
index b3e707f47b7b522393678e7ae596db97e4db31f8..4ebdee09542807060b85a80532feeb02541a36c1 100644 (file)
@@ -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;
 }
index 7148d8362db8330306dcbd5c46ffacfae4de1c80..11d7b8a62ebe116b7b1b380ece50d68ce860d038 100644 (file)
@@ -295,7 +295,9 @@ xrep_orphanage_can_adopt(
                return false;
        if (sc->ip == sc->orphanage)
                return false;
-       if (xfs_internal_inum(sc->mp, sc->ip->i_ino))
+       if (xchk_inode_is_sb_rooted(sc->ip))
+               return false;
+       if (xfs_is_metadata_inode(sc->ip))
                return false;
        return true;
 }
index 91e7b51ce0680bc891206255afd4fe20f5f78739..582536076433a44b2212c90381b5ebe5408cbec4 100644 (file)
@@ -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_metadata_inode(ip))
+       if (xchk_inode_is_sb_rooted(ip))
                return false;
 
        /*
index 7b42b7f65a0bd3e61ae5f6dd1b12442e8d79b7bd..f4e4845b7ec09925589c92a4bfee3592361dd622 100644 (file)
@@ -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);