summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-01-05 17:45:19 -0800
committerDarrick J. Wong <djwong@kernel.org>2021-03-25 17:08:30 -0700
commit72c0b9dbb97568b0c49d2bbf85fa6eadf74f63be (patch)
treea6255d8a499e49df7c93fbd0b2b0d3d318fc3e0b
parent6fe04e9be9541e905a6dfd553a91bda4d7885d8f (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>
-rw-r--r--fs/xfs/scrub/parent_repair.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/fs/xfs/scrub/parent_repair.c b/fs/xfs/scrub/parent_repair.c
index 308a6cad9227..1e4b454b66b9 100644
--- a/fs/xfs/scrub/parent_repair.c
+++ b/fs/xfs/scrub/parent_repair.c
@@ -211,6 +211,44 @@ xrep_parents_walk(
* capable of rebuilding a directory with the proper parent inode.
*/
+/* Check the dentry cache to see if it thinks it knows of a parent. */
+STATIC xfs_ino_t
+xrep_parent_check_dcache(
+ struct xfs_inode *dp)
+{
+ struct inode *pip = NULL;
+ struct dentry *dentry, *parent;
+ xfs_ino_t ret = NULLFSINO;
+
+ ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
+
+ dentry = d_find_alias(VFS_I(dp));
+ if (!dentry)
+ goto out;
+
+ parent = dget_parent(dentry);
+ if (!parent)
+ goto out_dput;
+
+ if (parent->d_sb != dp->i_mount->m_super) {
+ dput(parent);
+ goto out_dput;
+ }
+
+ pip = igrab(d_inode(parent));
+ dput(parent);
+
+ if (S_ISDIR(pip->i_mode))
+ ret = XFS_I(pip)->i_ino;
+
+ xfs_irele(XFS_I(pip));
+
+out_dput:
+ dput(dentry);
+out:
+ return ret;
+}
+
struct xrep_dir_parent_pick_info {
struct xfs_scrub *sc;
xfs_ino_t found_parent;
@@ -286,6 +324,7 @@ xrep_dir_parent_find(
.sc = sc,
.found_parent = NULLFSINO,
};
+ xfs_ino_t suggestion;
bool is_parent = false;
int error;
@@ -320,6 +359,18 @@ xrep_dir_parent_find(
return error;
}
+ /* Maybe the dcache will supply us with a parent? */
+ suggestion = xrep_parent_check_dcache(sc->ip);
+ if (!xfs_verify_dir_ino(sc->mp, suggestion)) {
+ error = xrep_dir_parent_check(sc, suggestion, &is_parent);
+ if (error)
+ return error;
+ if (is_parent) {
+ *parent_ino = suggestion;
+ return 0;
+ }
+ }
+
/* Otherwise, scan the entire filesystem to find a parent. */
error = xrep_parents_walk(sc, sc->ip->i_ino, xrep_dir_parent_pick,
&dpi);