diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-02-17 20:11:46 -0800 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-03-25 17:08:37 -0700 |
commit | ba4e7884e52e1f90e3adab43514a2af0c825c88a (patch) | |
tree | 857f1d74071a11fd54d6ddca65798c79c7e4aff5 | |
parent | 20e9d03d164e2961fdb77243182211632d7afdbd (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 | 17 |
4 files changed, 50 insertions, 0 deletions
diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c index 26035e86cfc5..7881ff4754f4 100644 --- a/fs/xfs/scrub/dir.c +++ b/fs/xfs/scrub/dir.c @@ -133,6 +133,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 942ae7e15165..2d91194c83e2 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -171,6 +171,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)) { + xfs_irele(ip); + return 0; + } + key.ftype = xfs_mode_to_ftype(VFS_I(ip)->i_mode); xfs_irele(ip); diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c index be3f3834eb9e..06ce60b73a9d 100644 --- a/fs/xfs/scrub/parent.c +++ b/fs/xfs/scrub/parent.c @@ -221,6 +221,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, validate the pointers and we're done. We must @@ -348,6 +358,14 @@ xchk_parent( goto out; } + /* 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 != dnum) + xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); + goto out; + } + do { error = xchk_parent_validate(sc, dnum, &try_again); if (error) diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c index b215c70bee32..579754a51a88 100644 --- a/fs/xfs/scrub/parent_repair.c +++ b/fs/xfs/scrub/parent_repair.c @@ -49,6 +49,8 @@ struct xrep_parents_scan { void *data; xrep_parents_walk_fn fn; + struct xfs_scrub *sc; + /* Potential parent of the directory we're scanning. */ // xfs_ino_t *parent_ino; @@ -129,6 +131,10 @@ xrep_parents_iwalk( if (!S_ISDIR(VFS_I(dp)->i_mode)) goto out_rele; + /* Don't mix metadata and regular directory trees. */ + if (xfs_is_metadata_inode(dp) ^ xfs_is_metadata_inode(rps->sc->ip)) + goto out_rele; + /* * Try to get the parent directory's IOLOCK. We still hold the child's * IOLOCK in exclusive mode, so we must avoid an ABBA deadlock. @@ -189,6 +195,7 @@ xrep_parents_walk( void *data) { struct xrep_parents_scan rps = { + .sc = sc, .dc.actor = xrep_parents_iwalk_dirents, .data = data, .fn = fn, @@ -295,6 +302,7 @@ xrep_dir_parent_check( .found_parent = NULLFSINO, }; struct xrep_parents_scan rps = { + .sc = sc, .dc.actor = xrep_parents_iwalk_dirents, .data = &dpi, .fn = xrep_dir_parent_pick, @@ -338,6 +346,15 @@ xrep_dir_parent_find( } /* + * If we are the metadata root directory, then we are our own parent. + * Return the root directory. + */ + if (sc->ip == sc->mp->m_metadirip) { + *parent_ino = sc->mp->m_sb.sb_metadirino; + return 0; + } + + /* * If we are an unlinked directory, the parent won't have a link to us. * We might as well return the suggestion, or the root directory if the * suggestion is NULLFSINO or garbage. There's no point in scanning |