diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 340f8679b6e7..6a70faeee6fa 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -77,7 +77,6 @@ struct dentry *ovl_lookup_temp(struct ovl_fs *ofs, struct dentry *workdir) return temp; } -/* caller holds i_mutex on workdir */ static struct dentry *ovl_whiteout(struct ovl_fs *ofs) { int err; @@ -85,6 +84,7 @@ static struct dentry *ovl_whiteout(struct ovl_fs *ofs) struct dentry *workdir = ofs->workdir; struct inode *wdir = workdir->d_inode; + inode_lock_nested(wdir, I_MUTEX_PARENT); if (!ofs->whiteout) { whiteout = ovl_lookup_temp(ofs, workdir); if (IS_ERR(whiteout)) @@ -118,14 +118,13 @@ static struct dentry *ovl_whiteout(struct ovl_fs *ofs) whiteout = ofs->whiteout; ofs->whiteout = NULL; out: + inode_unlock(wdir); return whiteout; } -/* Caller must hold i_mutex on both workdir and dir */ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct dentry *dir, struct dentry *dentry) { - struct inode *wdir = ofs->workdir->d_inode; struct dentry *whiteout; int err; int flags = 0; @@ -138,18 +137,22 @@ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct dentry *dir, if (d_is_dir(dentry)) flags = RENAME_EXCHANGE; - err = ovl_do_rename(ofs, ofs->workdir, whiteout, dir, dentry, flags); + err = ovl_lock_rename_workdir(ofs->workdir, whiteout, dir, dentry); + if (!err) { + err = ovl_do_rename(ofs, ofs->workdir, whiteout, dir, dentry, flags); + unlock_rename(ofs->workdir, dir); + } if (err) goto kill_whiteout; if (flags) - ovl_cleanup(ofs, wdir, dentry); + ovl_cleanup_unlocked(ofs, ofs->workdir, dentry); out: dput(whiteout); return err; kill_whiteout: - ovl_cleanup(ofs, wdir, whiteout); + ovl_cleanup_unlocked(ofs, ofs->workdir, whiteout); goto out; } @@ -783,16 +786,11 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, goto out_dput_upper; } - err = ovl_lock_rename_workdir(workdir, NULL, upperdir, upper); - if (err) - goto out_dput_upper; - err = ovl_cleanup_and_whiteout(ofs, upperdir, upper); if (!err) ovl_dir_modified(dentry->d_parent, true); d_drop(dentry); - unlock_rename(workdir, upperdir); out_dput_upper: dput(upper); out_dput: diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index e2d0c314df6c..ecbf39a49d57 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -1230,11 +1230,7 @@ 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_parent_lock(indexdir, index); - if (!err) { - err = ovl_cleanup_and_whiteout(ofs, indexdir, index); - ovl_parent_unlock(indexdir); - } + err = ovl_cleanup_and_whiteout(ofs, indexdir, index); } else { /* Cleanup orphan index entries */ err = ovl_cleanup_unlocked(ofs, indexdir, index); diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 7a1ca9380601..a63fda9ef6fd 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -1119,12 +1119,8 @@ static void ovl_cleanup_index(struct dentry *dentry) index = NULL; } else if (ovl_index_all(dentry->d_sb)) { /* Whiteout orphan index to block future open by handle */ - err = ovl_parent_lock(indexdir, index); - if (!err) { - err = ovl_cleanup_and_whiteout(OVL_FS(dentry->d_sb), - indexdir, index); - ovl_parent_unlock(indexdir); - } + err = ovl_cleanup_and_whiteout(OVL_FS(dentry->d_sb), + indexdir, index); } else { /* Cleanup orphan index entries */ err = ovl_cleanup_unlocked(ofs, indexdir, index); @@ -1232,10 +1228,6 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *work, { struct dentry *trap; - /* Workdir should not be the same as upperdir */ - if (workdir == upperdir) - goto err; - /* Workdir should not be subdir of upperdir and vice versa */ trap = lock_rename(workdir, upperdir); if (IS_ERR(trap))