diff options
| author | NeilBrown <neil@brown.name> | 2025-07-16 10:44:23 +1000 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2025-07-18 11:10:42 +0200 |
| commit | 61eb7fec9e79d429939fab16a4558caf7fa83160 (patch) | |
| tree | d349deb3aad30e7eec033d8c284a53e81ae4c188 | |
| parent | 8290fb412d2f3dced1b744330d22f2d639ccdf36 (diff) | |
| download | linux-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.c | 25 |
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, |
