diff options
author | Darrick J. Wong <djwong@kernel.org> | 2021-09-01 10:59:07 -0700 |
---|---|---|
committer | Darrick J. Wong <djwong@kernel.org> | 2021-10-22 16:40:46 -0700 |
commit | 6780caa2619855a1afc3751453a6ea1d9424c67e (patch) | |
tree | df77104f67ea62b41161f2049936254896725792 /fs | |
parent | 6773c22cee21e0a56a6d2e2d0c305999191e019f (diff) |
xfs: ask the dentry cache if it knows the parent of a directory
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@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/scrub/dir_repair.c | 6 | ||||
-rw-r--r-- | fs/xfs/scrub/parent.h | 1 | ||||
-rw-r--r-- | fs/xfs/scrub/parent_repair.c | 45 | ||||
-rw-r--r-- | fs/xfs/scrub/trace.h | 1 |
4 files changed, 53 insertions, 0 deletions
diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c index c7e3968abd9d..635b30fdd7b9 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -1115,6 +1115,12 @@ xrep_directory_find_parent( return 0; } + /* 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 foundit; + /* * Try to look up '..'; if it seems plausible, go with it. Check that * the parent directory actually points to this directory. If so, we diff --git a/fs/xfs/scrub/parent.h b/fs/xfs/scrub/parent.h index 10612f204d41..03681ab24596 100644 --- a/fs/xfs/scrub/parent.h +++ b/fs/xfs/scrub/parent.h @@ -10,5 +10,6 @@ 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); #endif /* __XFS_SCRUB_PARENT_H__ */ diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c index 3eb2fcb6ee40..b3fbb0ed5ac7 100644 --- a/fs/xfs/scrub/parent_repair.c +++ b/fs/xfs/scrub/parent_repair.c @@ -269,6 +269,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; + } + + xfs_irele(XFS_I(pip)); + +out_dput: + dput(dentry); +out: + return ret; +} + /* * Scan the entire filesystem looking for a parent inode. * @@ -374,6 +412,12 @@ xrep_parent( if (sick & XFS_SICK_INO_DIR) return -EFSCORRUPTED; + /* 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) @@ -381,6 +425,7 @@ xrep_parent( if (parent_ino == NULLFSINO) return -EFSCORRUPTED; +reset_parent: /* If the '..' entry is already set to the parent inode, we're done. */ curr_parent = xrep_dotdot_lookup(sc); if (curr_parent != NULLFSINO && curr_parent == parent_ino) diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h index 4e293a8c7724..afbcd9bf7001 100644 --- a/fs/xfs/scrub/trace.h +++ b/fs/xfs/scrub/trace.h @@ -1743,6 +1743,7 @@ DEFINE_EVENT(xrep_parent_salvage_class, name, \ DEFINE_XREP_PARENT_SALVAGE_CLASS(xrep_directory_salvaged_parent); 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) */ |