Skip to content

Commit

Permalink
ovl: re-structure overlay lower layers in-memory
Browse files Browse the repository at this point in the history
Define new structures to represent overlay instance lower layers and
overlay merge dir lower layers to make room for storing more per layer
information in-memory.

Instead of keeping the fs instance lower layers in an array of struct
vfsmount, keep them in an array of new struct ovl_layer, that has a
pointer to struct vfsmount.

Instead of keeping the dentry lower layers in an array of struct path,
keep them in an array of new struct ovl_path, that has a pointer to
struct dentry and to struct ovl_layer.

Add a small helper to find the fs layer id that correspopnds to a lower
struct ovl_path and use it in ovl_lookup().

[amir: split re-structure from anonymous bdev patch]

Signed-off-by: Chandan Rajendra <chandan@linux.vnet.ibm.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
  • Loading branch information
Chandan Rajendra authored and Miklos Szeredi committed Nov 9, 2017
1 parent ee023c3 commit b934363
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 56 deletions.
52 changes: 31 additions & 21 deletions fs/overlayfs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,16 +285,15 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,


static int ovl_check_origin(struct dentry *upperdentry,
struct path *lowerstack, unsigned int numlower,
struct path **stackp, unsigned int *ctrp)
struct ovl_path *lower, unsigned int numlower,
struct ovl_path **stackp, unsigned int *ctrp)
{
struct vfsmount *mnt;
struct dentry *origin = NULL;
int i;


for (i = 0; i < numlower; i++) {
mnt = lowerstack[i].mnt;
mnt = lower[i].layer->mnt;
origin = ovl_get_origin(upperdentry, mnt);
if (IS_ERR(origin))
return PTR_ERR(origin);
Expand All @@ -308,12 +307,12 @@ static int ovl_check_origin(struct dentry *upperdentry,

BUG_ON(*ctrp);
if (!*stackp)
*stackp = kmalloc(sizeof(struct path), GFP_KERNEL);
*stackp = kmalloc(sizeof(struct ovl_path), GFP_KERNEL);
if (!*stackp) {
dput(origin);
return -ENOMEM;
}
**stackp = (struct path) { .dentry = origin, .mnt = mnt };
**stackp = (struct ovl_path){.dentry = origin, .layer = lower[i].layer};
*ctrp = 1;

return 0;
Expand Down Expand Up @@ -383,13 +382,13 @@ int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt,
* OVL_XATTR_ORIGIN and that origin file handle can be decoded to lower path.
* Return 0 on match, -ESTALE on mismatch or stale origin, < 0 on error.
*/
int ovl_verify_index(struct dentry *index, struct path *lowerstack,
int ovl_verify_index(struct dentry *index, struct ovl_path *lower,
unsigned int numlower)
{
struct ovl_fh *fh = NULL;
size_t len;
struct path origin = { };
struct path *stack = &origin;
struct ovl_path origin = { };
struct ovl_path *stack = &origin;
unsigned int ctr = 0;
int err;

Expand Down Expand Up @@ -428,7 +427,7 @@ int ovl_verify_index(struct dentry *index, struct path *lowerstack,
if (err)
goto fail;

err = ovl_check_origin(index, lowerstack, numlower, &stack, &ctr);
err = ovl_check_origin(index, lower, numlower, &stack, &ctr);
if (!err && !ctr)
err = -ESTALE;
if (err)
Expand Down Expand Up @@ -567,11 +566,24 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path)
idx++;
}
BUG_ON(idx > oe->numlower);
*path = oe->lowerstack[idx - 1];
path->dentry = oe->lowerstack[idx - 1].dentry;
path->mnt = oe->lowerstack[idx - 1].layer->mnt;

return (idx < oe->numlower) ? idx + 1 : -1;
}

static int ovl_find_layer(struct ovl_fs *ofs, struct ovl_path *path)
{
int i;

for (i = 0; i < ofs->numlower; i++) {
if (ofs->lower_layers[i].mnt == path->layer->mnt)
break;
}

return i;
}

struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags)
{
Expand All @@ -580,7 +592,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
struct ovl_entry *poe = dentry->d_parent->d_fsdata;
struct ovl_entry *roe = dentry->d_sb->s_root->d_fsdata;
struct path *stack = NULL;
struct ovl_path *stack = NULL;
struct dentry *upperdir, *upperdentry = NULL;
struct dentry *index = NULL;
unsigned int ctr = 0;
Expand Down Expand Up @@ -645,25 +657,25 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,

if (!d.stop && poe->numlower) {
err = -ENOMEM;
stack = kcalloc(ofs->numlower, sizeof(struct path),
stack = kcalloc(ofs->numlower, sizeof(struct ovl_path),
GFP_KERNEL);
if (!stack)
goto out_put_upper;
}

for (i = 0; !d.stop && i < poe->numlower; i++) {
struct path lowerpath = poe->lowerstack[i];
struct ovl_path lower = poe->lowerstack[i];

d.last = i == poe->numlower - 1;
err = ovl_lookup_layer(lowerpath.dentry, &d, &this);
err = ovl_lookup_layer(lower.dentry, &d, &this);
if (err)
goto out_put;

if (!this)
continue;

stack[ctr].dentry = this;
stack[ctr].mnt = lowerpath.mnt;
stack[ctr].layer = lower.layer;
ctr++;

if (d.stop)
Expand All @@ -673,10 +685,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
poe = roe;

/* Find the current layer on the root dentry */
for (i = 0; i < poe->numlower; i++)
if (poe->lowerstack[i].mnt == lowerpath.mnt)
break;
if (WARN_ON(i == poe->numlower))
i = ovl_find_layer(ofs, &lower);
if (WARN_ON(i == ofs->numlower))
break;
}
}
Expand All @@ -699,7 +709,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
goto out_put;

oe->opaque = upperopaque;
memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
memcpy(oe->lowerstack, stack, sizeof(struct ovl_path) * ctr);
dentry->d_fsdata = oe;

if (upperdentry)
Expand Down
4 changes: 2 additions & 2 deletions fs/overlayfs/overlayfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ static inline bool ovl_is_impuredir(struct dentry *dentry)
/* namei.c */
int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt,
struct dentry *origin, bool is_upper, bool set);
int ovl_verify_index(struct dentry *index, struct path *lowerstack,
int ovl_verify_index(struct dentry *index, struct ovl_path *lower,
unsigned int numlower);
int ovl_get_index_name(struct dentry *origin, struct qstr *name);
int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
Expand All @@ -268,7 +268,7 @@ int ovl_check_d_type_supported(struct path *realpath);
void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
struct dentry *dentry, int level);
int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
struct path *lowerstack, unsigned int numlower);
struct ovl_path *lower, unsigned int numlower);

/* inode.c */
int ovl_set_nlink_upper(struct dentry *dentry);
Expand Down
13 changes: 11 additions & 2 deletions fs/overlayfs/ovl_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,20 @@ struct ovl_config {
bool index;
};

struct ovl_layer {
struct vfsmount *mnt;
};

struct ovl_path {
struct ovl_layer *layer;
struct dentry *dentry;
};

/* private information held for overlayfs's superblock */
struct ovl_fs {
struct vfsmount *upper_mnt;
unsigned numlower;
struct vfsmount **lower_mnt;
struct ovl_layer *lower_layers;
/* workbasedir is the path at workdir= mount option */
struct dentry *workbasedir;
/* workdir is the 'work' directory under workbasedir */
Expand Down Expand Up @@ -52,7 +61,7 @@ struct ovl_entry {
struct rcu_head rcu;
};
unsigned numlower;
struct path lowerstack[];
struct ovl_path lowerstack[];
};

struct ovl_entry *ovl_alloc_entry(unsigned int numlower);
Expand Down
4 changes: 2 additions & 2 deletions fs/overlayfs/readdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,7 @@ void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
}

int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
struct path *lowerstack, unsigned int numlower)
struct ovl_path *lower, unsigned int numlower)
{
int err;
struct dentry *index = NULL;
Expand Down Expand Up @@ -1049,7 +1049,7 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
index = NULL;
break;
}
err = ovl_verify_index(index, lowerstack, numlower);
err = ovl_verify_index(index, lower, numlower);
/* Cleanup stale and orphan index entries */
if (err && (err == -ESTALE || err == -ENOENT))
err = ovl_cleanup(dir, index);
Expand Down
62 changes: 34 additions & 28 deletions fs/overlayfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,8 @@ static void ovl_put_super(struct super_block *sb)
ovl_inuse_unlock(ufs->upper_mnt->mnt_root);
mntput(ufs->upper_mnt);
for (i = 0; i < ufs->numlower; i++)
mntput(ufs->lower_mnt[i]);
kfree(ufs->lower_mnt);
mntput(ufs->lower_layers[i].mnt);
kfree(ufs->lower_layers);

kfree(ufs->config.lowerdir);
kfree(ufs->config.upperdir);
Expand Down Expand Up @@ -1026,24 +1026,26 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
}

err = -ENOMEM;
ufs->lower_mnt = kcalloc(numlower, sizeof(struct vfsmount *), GFP_KERNEL);
if (ufs->lower_mnt == NULL)
ufs->lower_layers = kcalloc(numlower, sizeof(struct ovl_layer),
GFP_KERNEL);
if (ufs->lower_layers == NULL)
goto out_put_workdir;
for (i = 0; i < numlower; i++) {
struct vfsmount *mnt = clone_private_mount(&stack[i]);
struct vfsmount *mnt;

mnt = clone_private_mount(&stack[i]);
err = PTR_ERR(mnt);
if (IS_ERR(mnt)) {
pr_err("overlayfs: failed to clone lowerpath\n");
goto out_put_lower_mnt;
goto out_put_lower_layers;
}
/*
* Make lower_mnt R/O. That way fchmod/fchown on lower file
* Make lower layers R/O. That way fchmod/fchown on lower file
* will fail instead of modifying lower fs.
*/
mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;

ufs->lower_mnt[ufs->numlower] = mnt;
ufs->lower_layers[ufs->numlower].mnt = mnt;
ufs->numlower++;

/* Check if all lower layers are on same sb */
Expand All @@ -1059,13 +1061,25 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
else if (ufs->upper_mnt->mnt_sb != ufs->same_sb)
ufs->same_sb = NULL;

err = -ENOMEM;
oe = ovl_alloc_entry(numlower);
if (!oe)
goto out_put_lower_layers;

for (i = 0; i < numlower; i++) {
oe->lowerstack[i].dentry = stack[i].dentry;
oe->lowerstack[i].layer = &(ufs->lower_layers[i]);
}

if (!(ovl_force_readonly(ufs)) && ufs->config.index) {
/* Verify lower root is upper root origin */
err = ovl_verify_origin(upperpath.dentry, ufs->lower_mnt[0],
stack[0].dentry, false, true);
err = ovl_verify_origin(upperpath.dentry,
oe->lowerstack[0].layer->mnt,
oe->lowerstack[0].dentry,
false, true);
if (err) {
pr_err("overlayfs: failed to verify upper root origin\n");
goto out_put_lower_mnt;
goto out_free_oe;
}

ufs->indexdir = ovl_workdir_create(sb, ufs, workpath.dentry,
Expand All @@ -1081,7 +1095,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
if (!err)
err = ovl_indexdir_cleanup(ufs->indexdir,
ufs->upper_mnt,
stack, numlower);
oe->lowerstack,
numlower);
}
if (err || !ufs->indexdir)
pr_warn("overlayfs: try deleting index dir or mounting with '-o index=off' to disable inodes index.\n");
Expand All @@ -1106,11 +1121,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
/* Never override disk quota limits or use reserved space */
cap_lower(cred->cap_effective, CAP_SYS_RESOURCE);

err = -ENOMEM;
oe = ovl_alloc_entry(numlower);
if (!oe)
goto out_put_cred;

sb->s_magic = OVERLAYFS_SUPER_MAGIC;
sb->s_op = &ovl_super_operations;
sb->s_xattr = ovl_xattr_handlers;
Expand All @@ -1119,11 +1129,12 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)

root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, 0));
if (!root_dentry)
goto out_free_oe;
goto out_put_cred;

mntput(upperpath.mnt);
for (i = 0; i < numlower; i++)
mntput(stack[i].mnt);
kfree(stack);
mntput(workpath.mnt);
kfree(lowertmp);

Expand All @@ -1132,11 +1143,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
if (ovl_is_impuredir(upperpath.dentry))
ovl_set_flag(OVL_IMPURE, d_inode(root_dentry));
}
for (i = 0; i < numlower; i++) {
oe->lowerstack[i].dentry = stack[i].dentry;
oe->lowerstack[i].mnt = ufs->lower_mnt[i];
}
kfree(stack);

root_dentry->d_fsdata = oe;

Expand All @@ -1149,16 +1155,16 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)

return 0;

out_free_oe:
kfree(oe);
out_put_cred:
put_cred(ufs->creator_cred);
out_put_indexdir:
dput(ufs->indexdir);
out_put_lower_mnt:
out_free_oe:
kfree(oe);
out_put_lower_layers:
for (i = 0; i < ufs->numlower; i++)
mntput(ufs->lower_mnt[i]);
kfree(ufs->lower_mnt);
mntput(ufs->lower_layers[i].mnt);
kfree(ufs->lower_layers);
out_put_workdir:
dput(ufs->workdir);
mntput(ufs->upper_mnt);
Expand Down
7 changes: 6 additions & 1 deletion fs/overlayfs/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,12 @@ void ovl_path_lower(struct dentry *dentry, struct path *path)
{
struct ovl_entry *oe = dentry->d_fsdata;

*path = oe->numlower ? oe->lowerstack[0] : (struct path) { };
if (oe->numlower) {
path->mnt = oe->lowerstack[0].layer->mnt;
path->dentry = oe->lowerstack[0].dentry;
} else {
*path = (struct path) { };
}
}

enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path)
Expand Down

0 comments on commit b934363

Please sign in to comment.