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@xxxxxxxxxx> --- fs/overlayfs/super.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 9cce3251dd83..239ae1946edf 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,27 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, if (work->d_inode) { err = -EEXIST; + inode_unlock(dir); if (retried) goto out_dput; if (persist) - goto out_unlock; + goto out; retried = true; + inode_lock_nested(dir, I_MUTEX_PARENT); err = ovl_workdir_cleanup(ofs, dir, mnt, work, 0); + inode_unlock(dir); dput(work); if (err == -EINVAL) { work = ERR_PTR(err); - goto out_unlock; + goto out; } 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 +369,11 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, if (err) goto out_dput; } else { + inode_unlock(dir); err = PTR_ERR(work); goto out_err; } -out_unlock: - inode_unlock(dir); +out: return work; out_dput: @@ -378,7 +382,7 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, pr_warn("failed to create directory %s/%s (errno: %i); mounting read-only\n", ofs->config.workdir, name, -err); work = NULL; - goto out_unlock; + goto out; } static int ovl_check_namelen(const struct path *path, struct ovl_fs *ofs, -- 2.49.0