return temp;
}
-/* caller holds i_mutex on workdir */
static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
{
int err;
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))
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;
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;
}
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:
* 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);
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);
{
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))