summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neil@brown.name>2025-07-16 10:44:24 +1000
committerChristian Brauner <brauner@kernel.org>2025-07-18 11:10:42 +0200
commitd56c6feb69cb8f036855b4d12c84b46b10421278 (patch)
tree4a324b5d41b7865c493d2eeb5f9615dd228f10eb
parent61eb7fec9e79d429939fab16a4558caf7fa83160 (diff)
ovl: narrow locking in ovl_indexdir_cleanup()
Instead of taking the directory lock for the whole cleanup, only take it when needed. Signed-off-by: NeilBrown <neil@brown.name> Link: https://lore.kernel.org/20250716004725.1206467-14-neil@brown.name Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
-rw-r--r--fs/overlayfs/readdir.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 2a222b8185a3..95d5284daf8d 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -1194,7 +1194,6 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
if (err)
goto out;
- inode_lock_nested(dir, I_MUTEX_PARENT);
list_for_each_entry(p, &list, l_node) {
if (p->name[0] == '.') {
if (p->len == 1)
@@ -1202,7 +1201,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
if (p->len == 2 && p->name[1] == '.')
continue;
}
- index = ovl_lookup_upper(ofs, p->name, indexdir, p->len);
+ index = ovl_lookup_upper_unlocked(ofs, p->name, indexdir, p->len);
if (IS_ERR(index)) {
err = PTR_ERR(index);
index = NULL;
@@ -1210,7 +1209,11 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
}
/* Cleanup leftover from index create/cleanup attempt */
if (index->d_name.name[0] == '#') {
- err = ovl_workdir_cleanup(ofs, dir, path.mnt, index, 1);
+ err = ovl_parent_lock(indexdir, index);
+ if (!err) {
+ err = ovl_workdir_cleanup(ofs, dir, path.mnt, index, 1);
+ ovl_parent_unlock(indexdir);
+ }
if (err)
break;
goto next;
@@ -1220,7 +1223,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
goto next;
} else if (err == -ESTALE) {
/* Cleanup stale index entries */
- err = ovl_cleanup(ofs, dir, index);
+ err = ovl_cleanup_unlocked(ofs, indexdir, index);
} else if (err != -ENOENT) {
/*
* Abort mount to avoid corrupting the index if
@@ -1233,10 +1236,14 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
* Whiteout orphan index to block future open by
* handle after overlay nlink dropped to zero.
*/
- err = ovl_cleanup_and_whiteout(ofs, indexdir, index);
+ err = ovl_parent_lock(indexdir, index);
+ if (!err) {
+ err = ovl_cleanup_and_whiteout(ofs, indexdir, index);
+ ovl_parent_unlock(indexdir);
+ }
} else {
/* Cleanup orphan index entries */
- err = ovl_cleanup(ofs, dir, index);
+ err = ovl_cleanup_unlocked(ofs, indexdir, index);
}
if (err)
@@ -1247,7 +1254,6 @@ next:
index = NULL;
}
dput(index);
- inode_unlock(dir);
out:
ovl_cache_free(&list);
if (err)