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 <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
Amir Goldstein 2020-02-20 09:00:19 +02:00 committed by Miklos Szeredi
parent bccece1ead
commit cad218ab33
3 changed files with 71 additions and 1 deletions

View file

@ -42,7 +42,7 @@ int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
return err;
}
static struct dentry *ovl_lookup_temp(struct dentry *workdir)
struct dentry *ovl_lookup_temp(struct dentry *workdir)
{
struct dentry *temp;
char name[20];

View file

@ -453,6 +453,7 @@ struct ovl_cattr {
struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
struct ovl_cattr *attr);
int ovl_cleanup(struct inode *dir, struct dentry *dentry);
struct dentry *ovl_lookup_temp(struct dentry *workdir);
struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr);
/* file.c */

View file

@ -1071,6 +1071,66 @@ static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs,
return err;
}
/*
* Returns 1 if RENAME_WHITEOUT is supported, 0 if not supported and
* negative values if error is encountered.
*/
static int ovl_check_rename_whiteout(struct dentry *workdir)
{
struct inode *dir = d_inode(workdir);
struct dentry *temp;
struct dentry *dest;
struct dentry *whiteout;
struct name_snapshot name;
int err;
inode_lock_nested(dir, I_MUTEX_PARENT);
temp = ovl_create_temp(workdir, OVL_CATTR(S_IFREG | 0));
err = PTR_ERR(temp);
if (IS_ERR(temp))
goto out_unlock;
dest = ovl_lookup_temp(workdir);
err = PTR_ERR(dest);
if (IS_ERR(dest)) {
dput(temp);
goto out_unlock;
}
/* Name is inline and stable - using snapshot as a copy helper */
take_dentry_name_snapshot(&name, temp);
err = ovl_do_rename(dir, temp, dir, dest, RENAME_WHITEOUT);
if (err) {
if (err == -EINVAL)
err = 0;
goto cleanup_temp;
}
whiteout = lookup_one_len(name.name.name, workdir, name.name.len);
err = PTR_ERR(whiteout);
if (IS_ERR(whiteout))
goto cleanup_temp;
err = ovl_is_whiteout(whiteout);
/* Best effort cleanup of whiteout and temp file */
if (err)
ovl_cleanup(dir, whiteout);
dput(whiteout);
cleanup_temp:
ovl_cleanup(dir, temp);
release_dentry_name_snapshot(&name);
dput(temp);
dput(dest);
out_unlock:
inode_unlock(dir);
return err;
}
static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
struct path *workpath)
{
@ -1116,6 +1176,15 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
else
pr_warn("upper fs does not support tmpfile.\n");
/* Check if upper/work fs supports RENAME_WHITEOUT */
err = ovl_check_rename_whiteout(ofs->workdir);
if (err < 0)
goto out;
if (!err)
pr_warn("upper fs does not support RENAME_WHITEOUT.\n");
/*
* Check if upper/work fs supports trusted.overlay.* xattr
*/