summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2022-07-14 11:15:14 -0700
committerDarrick J. Wong <djwong@kernel.org>2022-10-14 14:17:02 -0700
commit982026b2f6fe7b1a2cd7c5c5e9680894b8557347 (patch)
tree3dc9722ce5fce2de0e7f4f94637a323e67c64865 /fs
parent4c10b40c8fd5f5e5285f769dbd3897a192fb0b7e (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.c9
-rw-r--r--fs/xfs/scrub/dir_repair.c6
-rw-r--r--fs/xfs/scrub/parent.c18
-rw-r--r--fs/xfs/scrub/parent_repair.c35
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;
}