[PATCH 3/3] xfs: ask the dentry cache if it knows the parent of a directory

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

 



From: Darrick J. Wong <djwong@xxxxxxxxxx>

It's possible that the dentry cache can tell us the parent of a
directory.  Therefore, when repairing directory dot dot entries, query
the dcache as a last resort before scanning the entire filesystem.

Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx>
---
 fs/xfs/scrub/dir_repair.c    |   27 ++++++++++++++++++++++++++
 fs/xfs/scrub/parent.h        |    1 +
 fs/xfs/scrub/parent_repair.c |   44 ++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/scrub/trace.h         |    1 +
 4 files changed, 73 insertions(+)


diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c
index e2de2fc24ba0..871b14c09e86 100644
--- a/fs/xfs/scrub/dir_repair.c
+++ b/fs/xfs/scrub/dir_repair.c
@@ -1033,6 +1033,29 @@ xrep_dir_lookup_parent(
 	return parent_ino;
 }
 
+/*
+ * Look up '..' in the dentry cache and confirm that it's really the parent.
+ * Returns NULLFSINO if the dcache misses or if the hit is implausible.
+ */
+static inline xfs_ino_t
+xrep_dir_dcache_parent(
+	struct xrep_dir		*rd)
+{
+	struct xfs_scrub	*sc = rd->sc;
+	xfs_ino_t		parent_ino;
+	int			error;
+
+	parent_ino = xrep_parent_from_dcache(sc);
+	if (parent_ino == NULLFSINO)
+		return parent_ino;
+
+	error = xrep_parent_confirm(sc, &parent_ino);
+	if (error)
+		return NULLFSINO;
+
+	return parent_ino;
+}
+
 /* Try to find the parent of the directory being repaired. */
 STATIC int
 xrep_dir_find_parent(
@@ -1044,6 +1067,10 @@ xrep_dir_find_parent(
 	if (rd->parent_ino != NULLFSINO)
 		return 0;
 
+	rd->parent_ino = xrep_dir_dcache_parent(rd);
+	if (rd->parent_ino != NULLFSINO)
+		return 0;
+
 	rd->parent_ino = xrep_dir_lookup_parent(rd);
 	if (rd->parent_ino != NULLFSINO)
 		return 0;
diff --git a/fs/xfs/scrub/parent.h b/fs/xfs/scrub/parent.h
index e1979f5bb001..c20673d8f093 100644
--- a/fs/xfs/scrub/parent.h
+++ b/fs/xfs/scrub/parent.h
@@ -10,6 +10,7 @@ int xchk_parent_lock_two_dirs(struct xfs_scrub *sc, struct xfs_inode *dp);
 
 int xrep_parent_confirm(struct xfs_scrub *sc, xfs_ino_t *parent_ino);
 int xrep_parent_scan(struct xfs_scrub *sc, xfs_ino_t *parent_ino);
+xfs_ino_t xrep_parent_from_dcache(struct xfs_scrub *sc);
 
 xfs_ino_t xrep_parent_self_reference(struct xfs_scrub *sc);
 
diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c
index d275c2129176..d83948d1fd05 100644
--- a/fs/xfs/scrub/parent_repair.c
+++ b/fs/xfs/scrub/parent_repair.c
@@ -263,6 +263,44 @@ xrep_parent_confirm(
 	return error;
 }
 
+/* Check the dentry cache to see if knows of a parent for the scrub target. */
+xfs_ino_t
+xrep_parent_from_dcache(
+	struct xfs_scrub	*sc)
+{
+	struct inode		*pip = NULL;
+	struct dentry		*dentry, *parent;
+	xfs_ino_t		ret = NULLFSINO;
+
+	dentry = d_find_alias(VFS_I(sc->ip));
+	if (!dentry)
+		goto out;
+
+	parent = dget_parent(dentry);
+	if (!parent)
+		goto out_dput;
+
+	if (parent->d_sb != sc->ip->i_mount->m_super) {
+		dput(parent);
+		goto out_dput;
+	}
+
+	pip = igrab(d_inode(parent));
+	dput(parent);
+
+	if (S_ISDIR(pip->i_mode)) {
+		trace_xrep_findparent_from_dcache(sc->ip, XFS_I(pip)->i_ino);
+		ret = XFS_I(pip)->i_ino;
+	}
+
+	xchk_irele(sc, XFS_I(pip));
+
+out_dput:
+	dput(dentry);
+out:
+	return ret;
+}
+
 /*
  * Scan the entire filesystem looking for a parent inode for the inode being
  * scrubbed.  @sc->ip must not be the root of a directory tree.
@@ -392,6 +430,12 @@ xrep_parent(
 	if (parent_ino != NULLFSINO)
 		goto reset_parent;
 
+	/* Does the VFS dcache have an answer for us? */
+	parent_ino = xrep_parent_from_dcache(sc);
+	error = xrep_parent_confirm(sc, &parent_ino);
+	if (!error && parent_ino != NULLFSINO)
+		goto reset_parent;
+
 	/* Scan the entire filesystem for a parent. */
 	error = xrep_parent_scan(sc, &parent_ino);
 	if (error)
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index b27abaa84d11..d8223ec24369 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -2535,6 +2535,7 @@ DEFINE_EVENT(xrep_parent_salvage_class, name, \
 	TP_ARGS(dp, ino))
 DEFINE_XREP_PARENT_SALVAGE_CLASS(xrep_dir_salvaged_parent);
 DEFINE_XREP_PARENT_SALVAGE_CLASS(xrep_findparent_dirent);
+DEFINE_XREP_PARENT_SALVAGE_CLASS(xrep_findparent_from_dcache);
 
 #endif /* IS_ENABLED(CONFIG_XFS_ONLINE_REPAIR) */
 




[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