summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/scrub/parent_repair.c47
-rw-r--r--fs/xfs/scrub/trace.h1
2 files changed, 48 insertions, 0 deletions
diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c
index dbbf9ca11c38..511fd77d9b86 100644
--- a/fs/xfs/scrub/parent_repair.c
+++ b/fs/xfs/scrub/parent_repair.c
@@ -237,6 +237,44 @@ findparent_check_dir(
return fpi.found_parent == parent_ino;
}
+/* Check the dentry cache to see if knows of a parent for the scrub target. */
+STATIC xfs_ino_t
+findparent_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_dcache(sc->ip, XFS_I(pip)->i_ino);
+ ret = XFS_I(pip)->i_ino;
+ }
+
+ xfs_irele(XFS_I(pip));
+
+out_dput:
+ dput(dentry);
+out:
+ return ret;
+}
+
/*
* Find the parent of the scrub target directory. Callers can pass in a
* suggested parent as the initial value of @parent_ino, or NULLFSINO if they
@@ -248,6 +286,8 @@ xrep_findparent(
struct xfs_scrub *sc,
xfs_ino_t *parent_ino)
{
+ xfs_ino_t ino;
+
ASSERT(S_ISDIR(VFS_I(sc->ip)->i_mode));
/*
@@ -278,6 +318,13 @@ xrep_findparent(
if (findparent_check_dir(sc, *parent_ino))
return 0;
+ /* Maybe the vfs dentry cache will supply us with a parent? */
+ ino = findparent_from_dcache(sc);
+ if (findparent_check_dir(sc, ino)) {
+ *parent_ino = ino;
+ return 0;
+ }
+
/* Otherwise, scan the entire filesystem to find a parent. */
return findparent_walk_inodes(sc, parent_ino);
}
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index 950b1d0d32a6..0b2c9bf57408 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -1663,6 +1663,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_dcache);
#endif /* IS_ENABLED(CONFIG_XFS_ONLINE_REPAIR) */