Skip to content

Commit 2fa14cf

Browse files
neilbrownbrauner
authored andcommitted
ovl: change ovl_cleanup_and_whiteout() to take rename lock as needed
Rather than locking the directory(s) before calling ovl_cleanup_and_whiteout(), change it (and ovl_whiteout()) to do the locking, so the locking can be fine grained as will be needed for proposed locking changes. Sometimes this is called to whiteout something in the index dir, in which case only that dir must be locked. In one case it is called on something in an upperdir, so two directories must be locked. We use ovl_lock_rename_workdir() for this and remove the restriction that upperdir cannot be indexdir - because now sometimes it is. Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: NeilBrown <neil@brown.name> Link: https://lore.kernel.org/20250716004725.1206467-18-neil@brown.name Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent c69566b commit 2fa14cf

3 files changed

Lines changed: 12 additions & 26 deletions

File tree

fs/overlayfs/dir.c

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@ struct dentry *ovl_lookup_temp(struct ovl_fs *ofs, struct dentry *workdir)
7777
return temp;
7878
}
7979

80-
/* caller holds i_mutex on workdir */
8180
static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
8281
{
8382
int err;
8483
struct dentry *whiteout;
8584
struct dentry *workdir = ofs->workdir;
8685
struct inode *wdir = workdir->d_inode;
8786

87+
inode_lock_nested(wdir, I_MUTEX_PARENT);
8888
if (!ofs->whiteout) {
8989
whiteout = ovl_lookup_temp(ofs, workdir);
9090
if (IS_ERR(whiteout))
@@ -118,14 +118,13 @@ static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
118118
whiteout = ofs->whiteout;
119119
ofs->whiteout = NULL;
120120
out:
121+
inode_unlock(wdir);
121122
return whiteout;
122123
}
123124

124-
/* Caller must hold i_mutex on both workdir and dir */
125125
int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct dentry *dir,
126126
struct dentry *dentry)
127127
{
128-
struct inode *wdir = ofs->workdir->d_inode;
129128
struct dentry *whiteout;
130129
int err;
131130
int flags = 0;
@@ -138,18 +137,22 @@ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct dentry *dir,
138137
if (d_is_dir(dentry))
139138
flags = RENAME_EXCHANGE;
140139

141-
err = ovl_do_rename(ofs, ofs->workdir, whiteout, dir, dentry, flags);
140+
err = ovl_lock_rename_workdir(ofs->workdir, whiteout, dir, dentry);
141+
if (!err) {
142+
err = ovl_do_rename(ofs, ofs->workdir, whiteout, dir, dentry, flags);
143+
unlock_rename(ofs->workdir, dir);
144+
}
142145
if (err)
143146
goto kill_whiteout;
144147
if (flags)
145-
ovl_cleanup(ofs, wdir, dentry);
148+
ovl_cleanup_unlocked(ofs, ofs->workdir, dentry);
146149

147150
out:
148151
dput(whiteout);
149152
return err;
150153

151154
kill_whiteout:
152-
ovl_cleanup(ofs, wdir, whiteout);
155+
ovl_cleanup_unlocked(ofs, ofs->workdir, whiteout);
153156
goto out;
154157
}
155158

@@ -783,16 +786,11 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
783786
goto out_dput_upper;
784787
}
785788

786-
err = ovl_lock_rename_workdir(workdir, NULL, upperdir, upper);
787-
if (err)
788-
goto out_dput_upper;
789-
790789
err = ovl_cleanup_and_whiteout(ofs, upperdir, upper);
791790
if (!err)
792791
ovl_dir_modified(dentry->d_parent, true);
793792

794793
d_drop(dentry);
795-
unlock_rename(workdir, upperdir);
796794
out_dput_upper:
797795
dput(upper);
798796
out_dput:

fs/overlayfs/readdir.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,11 +1230,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
12301230
* Whiteout orphan index to block future open by
12311231
* handle after overlay nlink dropped to zero.
12321232
*/
1233-
err = ovl_parent_lock(indexdir, index);
1234-
if (!err) {
1235-
err = ovl_cleanup_and_whiteout(ofs, indexdir, index);
1236-
ovl_parent_unlock(indexdir);
1237-
}
1233+
err = ovl_cleanup_and_whiteout(ofs, indexdir, index);
12381234
} else {
12391235
/* Cleanup orphan index entries */
12401236
err = ovl_cleanup_unlocked(ofs, indexdir, index);

fs/overlayfs/util.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,12 +1119,8 @@ static void ovl_cleanup_index(struct dentry *dentry)
11191119
index = NULL;
11201120
} else if (ovl_index_all(dentry->d_sb)) {
11211121
/* Whiteout orphan index to block future open by handle */
1122-
err = ovl_parent_lock(indexdir, index);
1123-
if (!err) {
1124-
err = ovl_cleanup_and_whiteout(OVL_FS(dentry->d_sb),
1125-
indexdir, index);
1126-
ovl_parent_unlock(indexdir);
1127-
}
1122+
err = ovl_cleanup_and_whiteout(OVL_FS(dentry->d_sb),
1123+
indexdir, index);
11281124
} else {
11291125
/* Cleanup orphan index entries */
11301126
err = ovl_cleanup_unlocked(ofs, indexdir, index);
@@ -1232,10 +1228,6 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *work,
12321228
{
12331229
struct dentry *trap;
12341230

1235-
/* Workdir should not be the same as upperdir */
1236-
if (workdir == upperdir)
1237-
goto err;
1238-
12391231
/* Workdir should not be subdir of upperdir and vice versa */
12401232
trap = lock_rename(workdir, upperdir);
12411233
if (IS_ERR(trap))

0 commit comments

Comments
 (0)