diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-09-01 11:15:39 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-12-15 17:29:08 -0800 |
commit | 52ef80084aa116f623bd79a5bd99e2ecbd1697e0 (patch) | |
tree | 36d3af95b2fafd109120df1e5c840122cb6fb54e | |
parent | c30358814d4e757e02cd713f367801076cd9077c (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 | 14 | ||||
-rw-r--r-- | fs/xfs/scrub/parent.c | 18 | ||||
-rw-r--r-- | fs/xfs/scrub/parent_repair.c | 27 |
4 files changed, 63 insertions, 5 deletions
diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c index 48b6960db5ed..0f94f94d3918 100644 --- a/fs/xfs/scrub/dir.c +++ b/fs/xfs/scrub/dir.c @@ -95,6 +95,15 @@ xchk_dir_check_ftype( xfs_mode_to_ftype(VFS_I(ip)->i_mode)); if (ino_dtype != dtype) xchk_fblock_set_corrupt(sdc->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(sdc->sc->ip)) + xchk_fblock_set_corrupt(sdc->sc, XFS_DATA_FORK, 0); + xfs_irele(ip); out: return error; diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c index 071126d3fe12..791ec9b5d991 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -213,6 +213,12 @@ xrep_directory_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)) { + xfs_irele(ip); + return 0; + } + entry.ftype = xfs_mode_to_ftype(VFS_I(ip)->i_mode); xfs_irele(ip); @@ -1080,8 +1086,14 @@ xrep_directory_self_parent( 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; } diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c index ea169669e8c3..e4de4cb6ea19 100644 --- a/fs/xfs/scrub/parent.c +++ b/fs/xfs/scrub/parent.c @@ -215,6 +215,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 @@ -313,5 +323,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 134726bb20bf..743476192cf8 100644 --- a/fs/xfs/scrub/parent_repair.c +++ b/fs/xfs/scrub/parent_repair.c @@ -137,6 +137,10 @@ xrep_findparent_walk_directory( if (dp == sc->ip) 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; @@ -245,12 +249,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; } |