summaryrefslogtreecommitdiff
path: root/fs/xfs/scrub/parent_repair.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/scrub/parent_repair.c')
-rw-r--r--fs/xfs/scrub/parent_repair.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c
index 1d01d00a1501..99fd0363da43 100644
--- a/fs/xfs/scrub/parent_repair.c
+++ b/fs/xfs/scrub/parent_repair.c
@@ -255,6 +255,44 @@ out_rele:
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.
@@ -384,6 +422,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)