Skip to content

Commit cad218a

Browse files
amir73ilMiklos Szeredi
authored andcommitted
ovl: check if upper fs supports RENAME_WHITEOUT
As with other required upper fs features, we only warn if support is missing to avoid breaking existing sub-optimal setups. Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent bccece1 commit cad218a

File tree

3 files changed

+71
-1
lines changed

3 files changed

+71
-1
lines changed

fs/overlayfs/dir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
4242
return err;
4343
}
4444

45-
static struct dentry *ovl_lookup_temp(struct dentry *workdir)
45+
struct dentry *ovl_lookup_temp(struct dentry *workdir)
4646
{
4747
struct dentry *temp;
4848
char name[20];

fs/overlayfs/overlayfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ struct ovl_cattr {
453453
struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
454454
struct ovl_cattr *attr);
455455
int ovl_cleanup(struct inode *dir, struct dentry *dentry);
456+
struct dentry *ovl_lookup_temp(struct dentry *workdir);
456457
struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr);
457458

458459
/* file.c */

fs/overlayfs/super.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,66 @@ static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs,
10711071
return err;
10721072
}
10731073

1074+
/*
1075+
* Returns 1 if RENAME_WHITEOUT is supported, 0 if not supported and
1076+
* negative values if error is encountered.
1077+
*/
1078+
static int ovl_check_rename_whiteout(struct dentry *workdir)
1079+
{
1080+
struct inode *dir = d_inode(workdir);
1081+
struct dentry *temp;
1082+
struct dentry *dest;
1083+
struct dentry *whiteout;
1084+
struct name_snapshot name;
1085+
int err;
1086+
1087+
inode_lock_nested(dir, I_MUTEX_PARENT);
1088+
1089+
temp = ovl_create_temp(workdir, OVL_CATTR(S_IFREG | 0));
1090+
err = PTR_ERR(temp);
1091+
if (IS_ERR(temp))
1092+
goto out_unlock;
1093+
1094+
dest = ovl_lookup_temp(workdir);
1095+
err = PTR_ERR(dest);
1096+
if (IS_ERR(dest)) {
1097+
dput(temp);
1098+
goto out_unlock;
1099+
}
1100+
1101+
/* Name is inline and stable - using snapshot as a copy helper */
1102+
take_dentry_name_snapshot(&name, temp);
1103+
err = ovl_do_rename(dir, temp, dir, dest, RENAME_WHITEOUT);
1104+
if (err) {
1105+
if (err == -EINVAL)
1106+
err = 0;
1107+
goto cleanup_temp;
1108+
}
1109+
1110+
whiteout = lookup_one_len(name.name.name, workdir, name.name.len);
1111+
err = PTR_ERR(whiteout);
1112+
if (IS_ERR(whiteout))
1113+
goto cleanup_temp;
1114+
1115+
err = ovl_is_whiteout(whiteout);
1116+
1117+
/* Best effort cleanup of whiteout and temp file */
1118+
if (err)
1119+
ovl_cleanup(dir, whiteout);
1120+
dput(whiteout);
1121+
1122+
cleanup_temp:
1123+
ovl_cleanup(dir, temp);
1124+
release_dentry_name_snapshot(&name);
1125+
dput(temp);
1126+
dput(dest);
1127+
1128+
out_unlock:
1129+
inode_unlock(dir);
1130+
1131+
return err;
1132+
}
1133+
10741134
static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
10751135
struct path *workpath)
10761136
{
@@ -1116,6 +1176,15 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
11161176
else
11171177
pr_warn("upper fs does not support tmpfile.\n");
11181178

1179+
1180+
/* Check if upper/work fs supports RENAME_WHITEOUT */
1181+
err = ovl_check_rename_whiteout(ofs->workdir);
1182+
if (err < 0)
1183+
goto out;
1184+
1185+
if (!err)
1186+
pr_warn("upper fs does not support RENAME_WHITEOUT.\n");
1187+
11191188
/*
11201189
* Check if upper/work fs supports trusted.overlay.* xattr
11211190
*/

0 commit comments

Comments
 (0)