diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-09-01 11:15:39 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-09-17 18:55:07 -0700 |
commit | ef45eb63b2906de79321672ac456a3ad883d5bfb (patch) | |
tree | e7a44d60ca13ff5fc270ee5483816173d8e718e2 | |
parent | 2778bc0ecc1cfce0f54b83d38e87f33bcc0942ee (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 | 21 |
4 files changed, 52 insertions, 2 deletions
diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c index 3811f21b7697..acca10a72fc1 100644 --- a/fs/xfs/scrub/dir.c +++ b/fs/xfs/scrub/dir.c @@ -134,6 +134,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 8f069636ae1a..91d812dbdb1d 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -180,6 +180,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 02c682be29de..519acb248d97 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 75e0db34b3b3..4570e7c94c32 100644 --- a/fs/xfs/scrub/parent_repair.c +++ b/fs/xfs/scrub/parent_repair.c @@ -129,6 +129,10 @@ findparent_walk_directory( 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(fpi->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. @@ -304,14 +308,27 @@ xrep_findparent( } /* + * 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 * the filesystem. */ if (VFS_I(sc->ip)->i_nlink == 0) { - if (!xfs_verify_dir_ino(sc->mp, *parent_ino)) - *parent_ino = sc->mp->m_sb.sb_rootino; + if (!xfs_verify_dir_ino(sc->mp, *parent_ino)) { + 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; } |