[PATCH 7/7] xfs: compare generated and existing dirents

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Darrick J. Wong <djwong@xxxxxxxxxx>

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

Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx>
---
 fs/xfs/scrub/dir_repair.c |  101 ++++++++++++++++++++++++++++++++++++++++++++-
 fs/xfs/scrub/trace.h      |    2 +
 2 files changed, 100 insertions(+), 3 deletions(-)


diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c
index 25af002df1da..ec48b3268809 100644
--- a/fs/xfs/scrub/dir_repair.c
+++ b/fs/xfs/scrub/dir_repair.c
@@ -757,7 +757,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,
@@ -768,7 +771,9 @@ xrep_dir_dump_tempdir(
 	void			*priv)
 {
 	struct xrep_dir		*rd = priv;
+	xfs_ino_t		child_ino;
 	bool			child = true;
+	xfs_dir2_dataptr_t	child_diroffset = XFS_DIR2_NULL_DATAPTR;
 	int			error;
 
 	/*
@@ -809,7 +814,88 @@ xrep_dir_dump_tempdir(
 	mutex_lock(&rd->lock);
 	error = xrep_dir_remove_dirent(rd, name, ino, dapos);
 	mutex_unlock(&rd->lock);
-	return error;
+	if (error)
+		return error;
+
+	/* Check that the dir being repaired has the same entry. */
+	error = xchk_dir_lookup(sc, sc->ip, name, &child_ino,
+			&child_diroffset);
+	if (error == -ENOENT) {
+		trace_xrep_dir_checkname(sc->ip, name, NULLFSINO,
+				XFS_DIR2_NULL_DATAPTR);
+		ASSERT(error != -ENOENT);
+		return -EFSCORRUPTED;
+	}
+	if (error)
+		return error;
+
+	if (ino != child_ino) {
+		trace_xrep_dir_checkname(sc->ip, name, child_ino,
+				child_diroffset);
+		ASSERT(ino == child_ino);
+		return -EFSCORRUPTED;
+	}
+
+	if (dapos != child_diroffset) {
+		trace_xrep_dir_badposname(sc->ip, name, child_ino,
+				child_diroffset);
+		/* We have no way to update this, so we just leave it. */
+	}
+
+	return 0;
+}
+
+/*
+ * 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;
+	xfs_dir2_dataptr_t	child_diroffset = XFS_DIR2_NULL_DATAPTR;
+	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, dapos);
+
+	/* Check that the tempdir has the same entry. */
+	error = xchk_dir_lookup(sc, sc->tempip, name, &child_ino,
+			&child_diroffset);
+	if (error == -ENOENT) {
+		trace_xrep_dir_checkname(sc->tempip, name, NULLFSINO,
+				XFS_DIR2_NULL_DATAPTR);
+		ASSERT(error != -ENOENT);
+		return -EFSCORRUPTED;
+	}
+	if (error)
+		return error;
+
+	if (ino != child_ino) {
+		trace_xrep_dir_checkname(sc->tempip, name, child_ino,
+				child_diroffset);
+		ASSERT(ino == child_ino);
+		return -EFSCORRUPTED;
+	}
+
+	if (dapos != child_diroffset) {
+		trace_xrep_dir_badposname(sc->ip, name, child_ino,
+				child_diroffset);
+		/* We have no way to update this, so we just leave it. */
+	}
+
+	return 0;
 }
 
 /*
@@ -876,12 +962,21 @@ xrep_dir_rebuild_tree(
 
 	trace_xrep_dir_rebuild_tree(sc->ip, rd->parent_ino);
 
-	xrep_tempfile_ilock(sc);
+	xchk_ilock(sc, XFS_ILOCK_EXCL);
+	error = xrep_tempfile_ilock_polled(sc);
+	if (error)
+		return error;
+
 	error = xchk_dir_walk(sc, sc->tempip, xrep_dir_dump_tempdir, rd);
 	if (error)
 		return error;
 
+	error = xchk_dir_walk(sc, sc->ip, xrep_dir_dump_baddir, rd);
+	if (error)
+		return error;
+
 	xrep_tempfile_iunlock(sc);
+	xchk_iunlock(sc, XFS_ILOCK_EXCL);
 	xchk_trans_cancel(sc);
 
 	return xrep_dir_replay_updates(rd);
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index cbf914bce6db..81d26be0ef3b 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -1224,6 +1224,8 @@ 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);
+DEFINE_XREP_DIRENT_CLASS(xrep_dir_badposname);
 
 DECLARE_EVENT_CLASS(xrep_dir_class,
 	TP_PROTO(struct xfs_inode *dp, xfs_ino_t parent_ino),




[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux