diff mbox series

[1/5] xfs: parent repair should try the dcache first

Message ID 158812838045.169849.14057774270874259846.stgit@magnolia (mailing list archive)
State New, archived
Headers show
Series xfs: atomic file metadata repairs | expand

Commit Message

Darrick J. Wong April 29, 2020, 2:46 a.m. UTC
From: Darrick J. Wong <darrick.wong@oracle.com>

If we need to find a directory's parent, try the dcache first.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/scrub/dir_repair.c    |    7 +++++-
 fs/xfs/scrub/parent.h        |    1 +
 fs/xfs/scrub/parent_repair.c |   47 ++++++++++++++++++++++++++++++++++++++----
 3 files changed, 49 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c
index 33e98e4172db..b299f8b35ce4 100644
--- a/fs/xfs/scrub/dir_repair.c
+++ b/fs/xfs/scrub/dir_repair.c
@@ -728,11 +728,16 @@  xrep_dir_validate_parent(
 
 	/*
 	 * If the directory salvage scan found no parent or found an obviously
-	 * incorrect parent, jump to the filesystem scan.
+	 * incorrect parent, try asking the dcache for the parent.
+	 *
+	 * If the dcache doesn't know about a parent or the parent seems
+	 * obviously incorrect, jump to the filesystem scan.
 	 *
 	 * Otherwise, if the alleged parent seems plausible, scan the directory
 	 * to make sure it really points to us.
 	 */
+	if (!xrep_parent_acceptable(sc, rd->parent_ino))
+		rd->parent_ino = xrep_parent_check_dcache(sc->ip);
 	if (!xrep_parent_acceptable(sc, rd->parent_ino))
 		goto scan;
 
diff --git a/fs/xfs/scrub/parent.h b/fs/xfs/scrub/parent.h
index 6c79f7f99e9e..62db392b19a5 100644
--- a/fs/xfs/scrub/parent.h
+++ b/fs/xfs/scrub/parent.h
@@ -14,5 +14,6 @@  typedef int (*xrep_parents_iter_fn)(struct xfs_inode *dp, struct xfs_name *name,
 int xrep_scan_for_parents(struct xfs_scrub *sc, xfs_ino_t target_ino,
 		xrep_parents_iter_fn fn, void *data);
 bool xrep_parent_acceptable(struct xfs_scrub *sc, xfs_ino_t ino);
+xfs_ino_t xrep_parent_check_dcache(struct xfs_inode *dp);
 
 #endif /* __XFS_SCRUB_PARENT_H__ */
diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c
index 3d3993ba920d..44cd7da405e5 100644
--- a/fs/xfs/scrub/parent_repair.c
+++ b/fs/xfs/scrub/parent_repair.c
@@ -174,6 +174,37 @@  xrep_parents_scan_inode(
 	return error;
 }
 
+/* Does the dcache have a parent for this directory? */
+xfs_ino_t
+xrep_parent_check_dcache(
+	struct xfs_inode	*dp)
+{
+	struct inode		*pip = NULL;
+	struct dentry		*dentry, *parent;
+	xfs_ino_t		ret = NULLFSINO;
+
+	ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
+
+	dentry = d_find_alias(VFS_I(dp));
+	if (!dentry)
+		goto out;
+
+	parent = dget_parent(dentry);
+	if (!parent)
+		goto out_dput;
+
+	pip = igrab(d_inode(parent));
+	dput(parent);
+
+	ret = pip->i_ino;
+	xfs_irele(XFS_I(pip));
+
+out_dput:
+	dput(dentry);
+out:
+	return ret;
+}
+
 /* Is this an acceptable parent for the inode we're scrubbing? */
 bool
 xrep_parent_acceptable(
@@ -271,11 +302,17 @@  xrep_parent(
 	if (sick & XFS_SICK_INO_DIR)
 		return -EFSCORRUPTED;
 
-	/* Scan the entire directory tree for the directory's parent. */
-	error = xrep_scan_for_parents(sc, sc->ip->i_ino, xrep_parent_absorb,
-			&rp);
-	if (error)
-		return error;
+	/*
+	 * Ask the dcache who it thinks the parent might be.  If that doesn't
+	 * pass muster, scan the entire filesystem for the directory's parent.
+	 */
+	rp.parent_ino = xrep_parent_check_dcache(sc->ip);
+	if (!xrep_parent_acceptable(sc, rp.parent_ino)) {
+		error = xrep_scan_for_parents(sc, sc->ip->i_ino,
+				xrep_parent_absorb, &rp);
+		if (error)
+			return error;
+	}
 
 	/* If we still don't have a parent, bail out. */
 	if (!xrep_parent_acceptable(sc, rp.parent_ino))