diff mbox series

[3/3] xfs: compare generated and existing dirents

Message ID 168080825323.615785.1816381633759007236.stgit@frogsfrogsfrogs (mailing list archive)
State Deferred, archived
Headers show
Series xfs: online repair of directories | expand

Commit Message

Darrick J. Wong April 6, 2023, 7:27 p.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

Check our work to make sure we found all the dirents that the original
directory had.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/scrub/dir_repair.c |   75 ++++++++++++++++++++++++++++++++++++++++++++-
 fs/xfs/scrub/trace.h      |    1 +
 2 files changed, 74 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c
index c484e6f36ca0..1e253feaa15d 100644
--- a/fs/xfs/scrub/dir_repair.c
+++ b/fs/xfs/scrub/dir_repair.c
@@ -746,7 +746,10 @@  xrep_dir_scan_dirtree(
 	return 0;
 }
 
-/* Dump a dirent from the temporary dir. */
+/*
+ * Dump a dirent from the temporary dir and check it against the dir we're
+ * rebuilding.  We are not committing any of this.
+ */
 STATIC int
 xrep_dir_dump_tempdir(
 	struct xfs_scrub	*sc,
@@ -757,8 +760,10 @@  xrep_dir_dump_tempdir(
 	void			*priv)
 {
 	struct xrep_dir		*rd = priv;
+	xfs_ino_t		child_ino;
 	bool			child_dirent = true;
-	int			error = 0;
+	bool			compare_dirent = true;
+	int			error;
 
 	/*
 	 * The tempdir was created with a dotdot entry pointing to the root
@@ -781,11 +786,30 @@  xrep_dir_dump_tempdir(
 	}
 	if (xrep_dir_samename(name, &xfs_name_dot)) {
 		child_dirent = false;
+		compare_dirent = false;
 		ino = sc->ip->i_ino;
 	}
 
 	trace_xrep_dir_dumpname(sc->tempip, name, ino);
 
+	/* Check that the dir being repaired has the same entry. */
+	if (compare_dirent) {
+		error = xchk_dir_lookup(sc, sc->ip, name, &child_ino);
+		if (error == -ENOENT) {
+			trace_xrep_dir_checkname(sc->ip, name, NULLFSINO);
+			ASSERT(error != -ENOENT);
+			return -EFSCORRUPTED;
+		}
+		if (error)
+			return error;
+
+		if (ino != child_ino) {
+			trace_xrep_dir_checkname(sc->ip, name, child_ino);
+			ASSERT(ino == child_ino);
+			return -EFSCORRUPTED;
+		}
+	}
+
 	/*
 	 * Set ourselves up to free every dirent in the tempdir because
 	 * directory inactivation won't do it for us.  The rest of the online
@@ -801,6 +825,49 @@  xrep_dir_dump_tempdir(
 	return error;
 }
 
+/*
+ * Dump a dirent from the dir we're rebuilding and check it against the
+ * temporary dir.  This assumes that the directory wasn't really corrupt to
+ * begin with.
+ */
+STATIC int
+xrep_dir_dump_baddir(
+	struct xfs_scrub	*sc,
+	struct xfs_inode	*dp,
+	xfs_dir2_dataptr_t	dapos,
+	const struct xfs_name	*name,
+	xfs_ino_t		ino,
+	void			*priv)
+{
+	xfs_ino_t		child_ino;
+	int			error;
+
+	/* Ignore the directory's dot and dotdot entries. */
+	if (xrep_dir_samename(name, &xfs_name_dotdot) ||
+	    xrep_dir_samename(name, &xfs_name_dot))
+		return 0;
+
+	trace_xrep_dir_dumpname(sc->ip, name, ino);
+
+	/* Check that the tempdir has the same entry. */
+	error = xchk_dir_lookup(sc, sc->tempip, name, &child_ino);
+	if (error == -ENOENT) {
+		trace_xrep_dir_checkname(sc->tempip, name, NULLFSINO);
+		ASSERT(error != -ENOENT);
+		return -EFSCORRUPTED;
+	}
+	if (error)
+		return error;
+
+	if (ino != child_ino) {
+		trace_xrep_dir_checkname(sc->tempip, name, child_ino);
+		ASSERT(ino == child_ino);
+		return -EFSCORRUPTED;
+	}
+
+	return 0;
+}
+
 /*
  * "Commit" the new directory structure to the file that we're repairing.
  *
@@ -886,6 +953,10 @@  xrep_dir_rebuild_tree(
 	if (error)
 		return error;
 
+	error = xchk_dir_walk(sc, sc->ip, xrep_dir_dump_baddir, rd);
+	if (error)
+		return error;
+
 	error = xchk_dir_walk(sc, sc->tempip, xrep_dir_dump_tempdir, rd);
 	if (error)
 		return error;
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index af5b5cd6d55b..d97a6bab9a4a 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -1279,6 +1279,7 @@  DEFINE_XREP_DIRENT_CLASS(xrep_dir_createname);
 DEFINE_XREP_DIRENT_CLASS(xrep_dir_removename);
 DEFINE_XREP_DIRENT_CLASS(xrep_dir_replacename);
 DEFINE_XREP_DIRENT_CLASS(xrep_dir_dumpname);
+DEFINE_XREP_DIRENT_CLASS(xrep_dir_checkname);
 
 DECLARE_EVENT_CLASS(xrep_dir_class,
 	TP_PROTO(struct xfs_inode *dp, xfs_ino_t parent_ino),