diff options
author | Darrick J. Wong <djwong@kernel.org> | 2022-07-14 11:15:14 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2022-10-14 14:17:02 -0700 |
commit | 982026b2f6fe7b1a2cd7c5c5e9680894b8557347 (patch) | |
tree | 3dc9722ce5fce2de0e7f4f94637a323e67c64865 /fs | |
parent | 4c10b40c8fd5f5e5285f769dbd3897a192fb0b7e (diff) |
xfs: scrub metadata directories
Teach online scrub about the metadata directory tree.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs')
-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 416682027c48..7bad5e1d3200 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 349ab1014c15..83e97aef882c 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; } |