summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-02-17 20:11:46 -0800
committerDarrick J. Wong <djwong@kernel.org>2021-03-25 17:08:37 -0700
commitba4e7884e52e1f90e3adab43514a2af0c825c88a (patch)
tree857f1d74071a11fd54d6ddca65798c79c7e4aff5
parent20e9d03d164e2961fdb77243182211632d7afdbd (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.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.c17
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