Skip to content

Commit

Permalink
ovl: pass ofs to creation operations
Browse files Browse the repository at this point in the history
Pass down struct ovl_fs to all creation helpers so we can ultimately
retrieve the relevant upper mount and take the mount's idmapping into
account when creating new filesystem objects. This is needed to support
idmapped base layers with overlay.

Cc: <linux-unionfs@vger.kernel.org>
Tested-by: Giuseppe Scrivano <gscrivan@redhat.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Christian Brauner (Microsoft) <brauner@kernel.org>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
  • Loading branch information
Christian Brauner authored and Miklos Szeredi committed Apr 28, 2022
1 parent c914c0e commit 576bb26
Showing 6 changed files with 121 additions and 97 deletions.
21 changes: 12 additions & 9 deletions fs/overlayfs/copy_up.c
Original file line number Diff line number Diff line change
@@ -474,7 +474,7 @@ static int ovl_create_index(struct dentry *dentry, struct dentry *origin,
if (err)
return err;

temp = ovl_create_temp(indexdir, OVL_CATTR(S_IFDIR | 0));
temp = ovl_create_temp(ofs, indexdir, OVL_CATTR(S_IFDIR | 0));
err = PTR_ERR(temp);
if (IS_ERR(temp))
goto free_name;
@@ -487,12 +487,12 @@ static int ovl_create_index(struct dentry *dentry, struct dentry *origin,
if (IS_ERR(index)) {
err = PTR_ERR(index);
} else {
err = ovl_do_rename(dir, temp, dir, index, 0);
err = ovl_do_rename(ofs, dir, temp, dir, index, 0);
dput(index);
}
out:
if (err)
ovl_cleanup(dir, temp);
ovl_cleanup(ofs, dir, temp);
dput(temp);
free_name:
kfree(name.name);
@@ -519,6 +519,7 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
int err;
struct dentry *upper;
struct dentry *upperdir = ovl_dentry_upper(c->parent);
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
struct inode *udir = d_inode(upperdir);

/* Mark parent "impure" because it may now contain non-pure upper */
@@ -535,7 +536,7 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
c->dentry->d_name.len);
err = PTR_ERR(upper);
if (!IS_ERR(upper)) {
err = ovl_do_link(ovl_dentry_upper(c->dentry), udir, upper);
err = ovl_do_link(ofs, ovl_dentry_upper(c->dentry), udir, upper);
dput(upper);

if (!err) {
@@ -656,6 +657,7 @@ static void ovl_revert_cu_creds(struct ovl_cu_creds *cc)
*/
static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
{
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
struct inode *inode;
struct inode *udir = d_inode(c->destdir), *wdir = d_inode(c->workdir);
struct dentry *temp, *upper;
@@ -677,7 +679,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
if (err)
goto unlock;

temp = ovl_create_temp(c->workdir, &cattr);
temp = ovl_create_temp(ofs, c->workdir, &cattr);
ovl_revert_cu_creds(&cc);

err = PTR_ERR(temp);
@@ -699,7 +701,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
if (IS_ERR(upper))
goto cleanup;

err = ovl_do_rename(wdir, temp, udir, upper, 0);
err = ovl_do_rename(ofs, wdir, temp, udir, upper, 0);
dput(upper);
if (err)
goto cleanup;
@@ -716,14 +718,15 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
return err;

cleanup:
ovl_cleanup(wdir, temp);
ovl_cleanup(ofs, wdir, temp);
dput(temp);
goto unlock;
}

/* Copyup using O_TMPFILE which does not require cross dir locking */
static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
{
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
struct inode *udir = d_inode(c->destdir);
struct dentry *temp, *upper;
struct ovl_cu_creds cc;
@@ -733,7 +736,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
if (err)
return err;

temp = ovl_do_tmpfile(c->workdir, c->stat.mode);
temp = ovl_do_tmpfile(ofs, c->workdir, c->stat.mode);
ovl_revert_cu_creds(&cc);

if (IS_ERR(temp))
@@ -748,7 +751,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
upper = lookup_one_len(c->destname.name, c->destdir, c->destname.len);
err = PTR_ERR(upper);
if (!IS_ERR(upper)) {
err = ovl_do_link(temp, udir, upper);
err = ovl_do_link(ofs, temp, udir, upper);
dput(upper);
}
inode_unlock(udir);
85 changes: 45 additions & 40 deletions fs/overlayfs/dir.c
Original file line number Diff line number Diff line change
@@ -23,15 +23,15 @@ MODULE_PARM_DESC(redirect_max,

static int ovl_set_redirect(struct dentry *dentry, bool samedir);

int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
int ovl_cleanup(struct ovl_fs *ofs, struct inode *wdir, struct dentry *wdentry)
{
int err;

dget(wdentry);
if (d_is_dir(wdentry))
err = ovl_do_rmdir(wdir, wdentry);
err = ovl_do_rmdir(ofs, wdir, wdentry);
else
err = ovl_do_unlink(wdir, wdentry);
err = ovl_do_unlink(ofs, wdir, wdentry);
dput(wdentry);

if (err) {
@@ -42,7 +42,7 @@ int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
return err;
}

struct dentry *ovl_lookup_temp(struct dentry *workdir)
struct dentry *ovl_lookup_temp(struct ovl_fs *ofs, struct dentry *workdir)
{
struct dentry *temp;
char name[20];
@@ -70,11 +70,11 @@ static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
struct inode *wdir = workdir->d_inode;

if (!ofs->whiteout) {
whiteout = ovl_lookup_temp(workdir);
whiteout = ovl_lookup_temp(ofs, workdir);
if (IS_ERR(whiteout))
goto out;

err = ovl_do_whiteout(wdir, whiteout);
err = ovl_do_whiteout(ofs, wdir, whiteout);
if (err) {
dput(whiteout);
whiteout = ERR_PTR(err);
@@ -84,11 +84,11 @@ static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
}

if (ofs->share_whiteout) {
whiteout = ovl_lookup_temp(workdir);
whiteout = ovl_lookup_temp(ofs, workdir);
if (IS_ERR(whiteout))
goto out;

err = ovl_do_link(ofs->whiteout, wdir, whiteout);
err = ovl_do_link(ofs, ofs->whiteout, wdir, whiteout);
if (!err)
goto out;

@@ -122,27 +122,28 @@ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct inode *dir,
if (d_is_dir(dentry))
flags = RENAME_EXCHANGE;

err = ovl_do_rename(wdir, whiteout, dir, dentry, flags);
err = ovl_do_rename(ofs, wdir, whiteout, dir, dentry, flags);
if (err)
goto kill_whiteout;
if (flags)
ovl_cleanup(wdir, dentry);
ovl_cleanup(ofs, wdir, dentry);

out:
dput(whiteout);
return err;

kill_whiteout:
ovl_cleanup(wdir, whiteout);
ovl_cleanup(ofs, wdir, whiteout);
goto out;
}

int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry, umode_t mode)
int ovl_mkdir_real(struct ovl_fs *ofs, struct inode *dir,
struct dentry **newdentry, umode_t mode)
{
int err;
struct dentry *d, *dentry = *newdentry;

err = ovl_do_mkdir(dir, dentry, mode);
err = ovl_do_mkdir(ofs, dir, dentry, mode);
if (err)
return err;

@@ -167,8 +168,8 @@ int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry, umode_t mode)
return 0;
}

struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
struct ovl_cattr *attr)
struct dentry *ovl_create_real(struct ovl_fs *ofs, struct inode *dir,
struct dentry *newdentry, struct ovl_cattr *attr)
{
int err;

@@ -180,28 +181,28 @@ struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
goto out;

if (attr->hardlink) {
err = ovl_do_link(attr->hardlink, dir, newdentry);
err = ovl_do_link(ofs, attr->hardlink, dir, newdentry);
} else {
switch (attr->mode & S_IFMT) {
case S_IFREG:
err = ovl_do_create(dir, newdentry, attr->mode);
err = ovl_do_create(ofs, dir, newdentry, attr->mode);
break;

case S_IFDIR:
/* mkdir is special... */
err = ovl_mkdir_real(dir, &newdentry, attr->mode);
err = ovl_mkdir_real(ofs, dir, &newdentry, attr->mode);
break;

case S_IFCHR:
case S_IFBLK:
case S_IFIFO:
case S_IFSOCK:
err = ovl_do_mknod(dir, newdentry, attr->mode,
err = ovl_do_mknod(ofs, dir, newdentry, attr->mode,
attr->rdev);
break;

case S_IFLNK:
err = ovl_do_symlink(dir, newdentry, attr->link);
err = ovl_do_symlink(ofs, dir, newdentry, attr->link);
break;

default:
@@ -223,10 +224,11 @@ struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
return newdentry;
}

struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr)
struct dentry *ovl_create_temp(struct ovl_fs *ofs, struct dentry *workdir,
struct ovl_cattr *attr)
{
return ovl_create_real(d_inode(workdir), ovl_lookup_temp(workdir),
attr);
return ovl_create_real(ofs, d_inode(workdir),
ovl_lookup_temp(ofs, workdir), attr);
}

static int ovl_set_opaque_xerr(struct dentry *dentry, struct dentry *upper,
@@ -330,7 +332,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
attr->mode &= ~current_umask();

inode_lock_nested(udir, I_MUTEX_PARENT);
newdentry = ovl_create_real(udir,
newdentry = ovl_create_real(ofs, udir,
lookup_one_len(dentry->d_name.name,
upperdir,
dentry->d_name.len),
@@ -353,14 +355,15 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
return err;

out_cleanup:
ovl_cleanup(udir, newdentry);
ovl_cleanup(ofs, udir, newdentry);
dput(newdentry);
goto out_unlock;
}

static struct dentry *ovl_clear_empty(struct dentry *dentry,
struct list_head *list)
{
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
struct dentry *workdir = ovl_workdir(dentry);
struct inode *wdir = workdir->d_inode;
struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
@@ -391,7 +394,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
if (upper->d_parent->d_inode != udir)
goto out_unlock;

opaquedir = ovl_create_temp(workdir, OVL_CATTR(stat.mode));
opaquedir = ovl_create_temp(ofs, workdir, OVL_CATTR(stat.mode));
err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir))
goto out_unlock;
@@ -410,12 +413,12 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
if (err)
goto out_cleanup;

err = ovl_do_rename(wdir, opaquedir, udir, upper, RENAME_EXCHANGE);
err = ovl_do_rename(ofs, wdir, opaquedir, udir, upper, RENAME_EXCHANGE);
if (err)
goto out_cleanup;

ovl_cleanup_whiteouts(upper, list);
ovl_cleanup(wdir, upper);
ovl_cleanup_whiteouts(ofs, upper, list);
ovl_cleanup(ofs, wdir, upper);
unlock_rename(workdir, upperdir);

/* dentry's upper doesn't match now, get rid of it */
@@ -424,7 +427,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
return opaquedir;

out_cleanup:
ovl_cleanup(wdir, opaquedir);
ovl_cleanup(ofs, wdir, opaquedir);
dput(opaquedir);
out_unlock:
unlock_rename(workdir, upperdir);
@@ -495,7 +498,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
if (d_is_negative(upper) || !IS_WHITEOUT(d_inode(upper)))
goto out_dput;

newdentry = ovl_create_temp(workdir, cattr);
newdentry = ovl_create_temp(ofs, workdir, cattr);
err = PTR_ERR(newdentry);
if (IS_ERR(newdentry))
goto out_dput;
@@ -533,20 +536,20 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
if (err)
goto out_cleanup;

err = ovl_do_rename(wdir, newdentry, udir, upper,
err = ovl_do_rename(ofs, wdir, newdentry, udir, upper,
RENAME_EXCHANGE);
if (err)
goto out_cleanup;

ovl_cleanup(wdir, upper);
ovl_cleanup(ofs, wdir, upper);
} else {
err = ovl_do_rename(wdir, newdentry, udir, upper, 0);
err = ovl_do_rename(ofs, wdir, newdentry, udir, upper, 0);
if (err)
goto out_cleanup;
}
err = ovl_instantiate(dentry, inode, newdentry, hardlink);
if (err) {
ovl_cleanup(udir, newdentry);
ovl_cleanup(ofs, udir, newdentry);
dput(newdentry);
}
out_dput:
@@ -561,7 +564,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
return err;

out_cleanup:
ovl_cleanup(wdir, newdentry);
ovl_cleanup(ofs, wdir, newdentry);
dput(newdentry);
goto out_dput;
}
@@ -801,6 +804,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
static int ovl_remove_upper(struct dentry *dentry, bool is_dir,
struct list_head *list)
{
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
struct inode *dir = upperdir->d_inode;
struct dentry *upper;
@@ -827,9 +831,9 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir,
goto out_dput_upper;

if (is_dir)
err = vfs_rmdir(&init_user_ns, dir, upper);
err = ovl_do_rmdir(ofs, dir, upper);
else
err = vfs_unlink(&init_user_ns, dir, upper, NULL);
err = ovl_do_unlink(ofs, dir, upper);
ovl_dir_modified(dentry->d_parent, ovl_type_origin(dentry));

/*
@@ -1096,6 +1100,7 @@ static int ovl_rename(struct user_namespace *mnt_userns, struct inode *olddir,
bool samedir = olddir == newdir;
struct dentry *opaquedir = NULL;
const struct cred *old_cred = NULL;
struct ovl_fs *ofs = OVL_FS(old->d_sb);
LIST_HEAD(list);

err = -EINVAL;
@@ -1252,13 +1257,13 @@ static int ovl_rename(struct user_namespace *mnt_userns, struct inode *olddir,
if (err)
goto out_dput;

err = ovl_do_rename(old_upperdir->d_inode, olddentry,
err = ovl_do_rename(ofs, old_upperdir->d_inode, olddentry,
new_upperdir->d_inode, newdentry, flags);
if (err)
goto out_dput;

if (cleanup_whiteout)
ovl_cleanup(old_upperdir->d_inode, newdentry);
ovl_cleanup(ofs, old_upperdir->d_inode, newdentry);

if (overwrite && d_inode(new)) {
if (new_is_dir)
Loading

0 comments on commit 576bb26

Please sign in to comment.