diff options
author | Darrick J. Wong <djwong@kernel.org> | 2022-07-14 11:15:14 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2022-11-09 19:07:50 -0800 |
commit | 5fb05a1a2df73b606bbddbee413b33cfc7d1afc6 (patch) | |
tree | c5e4db42e113651f785818b88b412b5b85f46b3d | |
parent | f0cafa7c23214850d08e07043649786dcf2a8487 (diff) |
xfs: scrub metadata directories
Teach online scrub about the metadata directory tree.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r-- | fs/xfs/scrub/dir.c | 9 | ||||
-rw-r--r-- | fs/xfs/scrub/dir_repair.c | 6 | ||||
-rw-r--r-- | fs/xfs/scrub/parent.c | 18 | ||||
-rw-r--r-- | fs/xfs/scrub/parent_repair.c | 35 |
4 files changed, 63 insertions, 5 deletions
diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c index b2c5e5b37618..cf862b59e012 100644 --- a/fs/xfs/scrub/dir.c +++ b/fs/xfs/scrub/dir.c @@ -59,6 +59,15 @@ xchk_dir_check_ftype( if (xfs_mode_to_ftype(VFS_I(ip)->i_mode) != ftype) xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset); + + /* + * Metadata and regular inodes cannot cross trees. This property + * cannot change without a full inode free and realloc cycle, so it's + * safe to check this without holding locks. + */ + if (xfs_is_metadata_inode(ip) ^ xfs_is_metadata_inode(sc->ip)) + xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset); + } /* diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c index 3277f04a0292..d6add6ff179d 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -203,6 +203,12 @@ xrep_dir_salvage_entry( if (error) return 0; + /* Don't mix metadata and regular directory trees. */ + if (xfs_is_metadata_inode(ip) ^ xfs_is_metadata_inode(rd->sc->ip)) { + xchk_irele(sc, ip); + return 0; + } + entry.ftype = xfs_mode_to_ftype(VFS_I(ip)->i_mode); xchk_irele(sc, ip); diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c index 8874b0344cd3..b7d733c9a251 100644 --- a/fs/xfs/scrub/parent.c +++ b/fs/xfs/scrub/parent.c @@ -172,6 +172,16 @@ xchk_parent_validate( } /* + * Metadata and regular inodes cannot cross trees. This property + * cannot change without a full inode free and realloc cycle, so it's + * safe to check this without holding locks. + */ + if (xfs_is_metadata_inode(dp) ^ xfs_is_metadata_inode(sc->ip)) { + xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); + goto out_rele; + } + + /* * We prefer to keep the inode locked while we lock and search its * alleged parent for a forward reference. If we can grab the iolock * of the alleged parent, then we can move ahead to counting dirents @@ -278,5 +288,13 @@ xchk_parent( return 0; } + /* Is this the metadata root dir? Then '..' must point to itself. */ + if (sc->ip == mp->m_metadirip) { + if (sc->ip->i_ino != mp->m_sb.sb_metadirino || + sc->ip->i_ino != parent_ino) + xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); + return 0; + } + return xchk_parent_validate(sc, parent_ino); } diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c index a3508d3fcc0e..45342783746d 100644 --- a/fs/xfs/scrub/parent_repair.c +++ b/fs/xfs/scrub/parent_repair.c @@ -135,6 +135,10 @@ xrep_findparent_walk_directory( if (xrep_is_tempfile(dp)) return 0; + /* Don't mix metadata and regular directory trees. */ + if (xfs_is_metadata_inode(dp) ^ xfs_is_metadata_inode(sc->ip)) + return 0; + /* Try to lock dp; if we can, we're ready to scan! */ if (!xfs_ilock_nowait(dp, XFS_IOLOCK_SHARED)) { xfs_ino_t orig_parent, new_parent; @@ -219,12 +223,27 @@ xrep_parent_confirm( }; int error; + /* The root directory always points to itself. */ + if (sc->ip == sc->mp->m_rootip) { + *parent_ino = sc->mp->m_sb.sb_rootino; + return 0; + } + + /* The metadata root directory always points to itself. */ + if (sc->ip == sc->mp->m_metadirip) { + *parent_ino = sc->mp->m_sb.sb_metadirino; + return 0; + } + /* - * The root directory always points to itself. Unlinked dirs can point - * anywhere, so we point them at the root dir too. + * Unlinked dirs can point anywhere, so we point them at the root dir + * of whichever tree is appropriate. */ - if (sc->ip == sc->mp->m_rootip || VFS_I(sc->ip)->i_nlink == 0) { - *parent_ino = sc->mp->m_sb.sb_rootino; + if (VFS_I(sc->ip)->i_nlink == 0) { + if (xfs_is_metadata_inode(sc->ip)) + *parent_ino = sc->mp->m_sb.sb_metadirino; + else + *parent_ino = sc->mp->m_sb.sb_rootino; return 0; } @@ -381,8 +400,14 @@ xrep_parent_self_reference( if (sc->ip->i_ino == sc->mp->m_sb.sb_rootino) return sc->mp->m_sb.sb_rootino; - if (VFS_I(sc->ip)->i_nlink == 0) + if (sc->ip->i_ino == sc->mp->m_sb.sb_metadirino) + return sc->mp->m_sb.sb_metadirino; + + if (VFS_I(sc->ip)->i_nlink == 0) { + if (xfs_is_metadata_inode(sc->ip)) + return sc->mp->m_sb.sb_metadirino; return sc->mp->m_sb.sb_rootino; + } return NULLFSINO; } |