diff options
Diffstat (limited to 'fs/xfs/scrub/parent_repair.c')
-rw-r--r-- | fs/xfs/scrub/parent_repair.c | 44 |
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) |