summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neil@brown.name>2025-07-16 10:44:23 +1000
committerChristian Brauner <brauner@kernel.org>2025-07-18 11:10:42 +0200
commit61eb7fec9e79d429939fab16a4558caf7fa83160 (patch)
treed349deb3aad30e7eec033d8c284a53e81ae4c188
parent8290fb412d2f3dced1b744330d22f2d639ccdf36 (diff)
downloadlinux-61eb7fec9e79d429939fab16a4558caf7fa83160.tar.gz
linux-61eb7fec9e79d429939fab16a4558caf7fa83160.zip
ovl: narrow locking in ovl_workdir_create()
In ovl_workdir_create() don't hold the dir lock for the whole time, but only take it when needed. It now gets taken separately for ovl_workdir_cleanup(). A subsequent patch will move the locking into that function. Signed-off-by: NeilBrown <neil@brown.name> Link: https://lore.kernel.org/20250716004725.1206467-13-neil@brown.name Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
-rw-r--r--fs/overlayfs/super.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 2e6b25bde83f..cb2551a155d8 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -299,8 +299,8 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs,
int err;
bool retried = false;
- inode_lock_nested(dir, I_MUTEX_PARENT);
retry:
+ inode_lock_nested(dir, I_MUTEX_PARENT);
work = ovl_lookup_upper(ofs, name, ofs->workbasedir, strlen(name));
if (!IS_ERR(work)) {
@@ -311,23 +311,28 @@ retry:
if (work->d_inode) {
err = -EEXIST;
+ inode_unlock(dir);
if (retried)
goto out_dput;
if (persist)
- goto out_unlock;
+ return work;
retried = true;
- err = ovl_workdir_cleanup(ofs, dir, mnt, work, 0);
- dput(work);
- if (err == -EINVAL) {
- work = ERR_PTR(err);
- goto out_unlock;
+ err = ovl_parent_lock(ofs->workbasedir, work);
+ if (!err) {
+ err = ovl_workdir_cleanup(ofs, dir, mnt, work, 0);
+ ovl_parent_unlock(ofs->workbasedir);
}
+ dput(work);
+ if (err == -EINVAL)
+ return ERR_PTR(err);
+
goto retry;
}
work = ovl_do_mkdir(ofs, dir, work, attr.ia_mode);
+ inode_unlock(dir);
err = PTR_ERR(work);
if (IS_ERR(work))
goto out_err;
@@ -365,11 +370,10 @@ retry:
if (err)
goto out_dput;
} else {
+ inode_unlock(dir);
err = PTR_ERR(work);
goto out_err;
}
-out_unlock:
- inode_unlock(dir);
return work;
out_dput:
@@ -377,8 +381,7 @@ out_dput:
out_err:
pr_warn("failed to create directory %s/%s (errno: %i); mounting read-only\n",
ofs->config.workdir, name, -err);
- work = NULL;
- goto out_unlock;
+ return NULL;
}
static int ovl_check_namelen(const struct path *path, struct ovl_fs *ofs,