From: Darrick J. Wong <djwong@xxxxxxxxxx> Teach online scrub about the metadata directory tree. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- fs/xfs/scrub/dir.c | 9 +++++++++ fs/xfs/scrub/dir_repair.c | 6 ++++++ fs/xfs/scrub/parent.c | 18 ++++++++++++++++++ fs/xfs/scrub/parent_repair.c | 37 +++++++++++++++++++++++++++++++------ 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c index 218cf43cdf93..30636501fb9f 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 7530819e1435..14f34b9d4448 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -204,6 +204,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 92866f1757be..5af765a8182c 100644 --- a/fs/xfs/scrub/parent.c +++ b/fs/xfs/scrub/parent.c @@ -197,6 +197,16 @@ xchk_parent_validate( goto out_rele; } + /* + * 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 @@ -302,5 +312,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 ffef5de0fbe2..bba1cd1c7c8b 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; @@ -227,15 +231,30 @@ xrep_parent_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; } + /* 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; + } + + /* + * Unlinked dirs can point anywhere, so we point them at the root dir + * of whichever tree is appropriate. + */ + 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; + } + /* Reject garbage parent inode numbers and self-referential parents. */ if (*parent_ino == NULLFSINO) return 0; @@ -389,8 +408,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; }