Commit b9343632 authored by Chandan Rajendra's avatar Chandan Rajendra Committed by Miklos Szeredi

ovl: re-structure overlay lower layers in-memory

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: default avatarChandan Rajendra <chandan@linux.vnet.ibm.com>
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent ee023c30
...@@ -285,16 +285,15 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d, ...@@ -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, static int ovl_check_origin(struct dentry *upperdentry,
struct path *lowerstack, unsigned int numlower, struct ovl_path *lower, unsigned int numlower,
struct path **stackp, unsigned int *ctrp) struct ovl_path **stackp, unsigned int *ctrp)
{ {
struct vfsmount *mnt; struct vfsmount *mnt;
struct dentry *origin = NULL; struct dentry *origin = NULL;
int i; int i;
for (i = 0; i < numlower; i++) { for (i = 0; i < numlower; i++) {
mnt = lowerstack[i].mnt; mnt = lower[i].layer->mnt;
origin = ovl_get_origin(upperdentry, mnt); origin = ovl_get_origin(upperdentry, mnt);
if (IS_ERR(origin)) if (IS_ERR(origin))
return PTR_ERR(origin); return PTR_ERR(origin);
...@@ -308,12 +307,12 @@ static int ovl_check_origin(struct dentry *upperdentry, ...@@ -308,12 +307,12 @@ static int ovl_check_origin(struct dentry *upperdentry,
BUG_ON(*ctrp); BUG_ON(*ctrp);
if (!*stackp) if (!*stackp)
*stackp = kmalloc(sizeof(struct path), GFP_KERNEL); *stackp = kmalloc(sizeof(struct ovl_path), GFP_KERNEL);
if (!*stackp) { if (!*stackp) {
dput(origin); dput(origin);
return -ENOMEM; return -ENOMEM;
} }
**stackp = (struct path) { .dentry = origin, .mnt = mnt }; **stackp = (struct ovl_path){.dentry = origin, .layer = lower[i].layer};
*ctrp = 1; *ctrp = 1;
return 0; return 0;
...@@ -383,13 +382,13 @@ int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt, ...@@ -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. * 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. * 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) unsigned int numlower)
{ {
struct ovl_fh *fh = NULL; struct ovl_fh *fh = NULL;
size_t len; size_t len;
struct path origin = { }; struct ovl_path origin = { };
struct path *stack = &origin; struct ovl_path *stack = &origin;
unsigned int ctr = 0; unsigned int ctr = 0;
int err; int err;
...@@ -428,7 +427,7 @@ int ovl_verify_index(struct dentry *index, struct path *lowerstack, ...@@ -428,7 +427,7 @@ int ovl_verify_index(struct dentry *index, struct path *lowerstack,
if (err) if (err)
goto fail; goto fail;
err = ovl_check_origin(index, lowerstack, numlower, &stack, &ctr); err = ovl_check_origin(index, lower, numlower, &stack, &ctr);
if (!err && !ctr) if (!err && !ctr)
err = -ESTALE; err = -ESTALE;
if (err) if (err)
...@@ -567,11 +566,24 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path) ...@@ -567,11 +566,24 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path)
idx++; idx++;
} }
BUG_ON(idx > oe->numlower); 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; 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, struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags) unsigned int flags)
{ {
...@@ -580,7 +592,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -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_fs *ofs = dentry->d_sb->s_fs_info;
struct ovl_entry *poe = dentry->d_parent->d_fsdata; struct ovl_entry *poe = dentry->d_parent->d_fsdata;
struct ovl_entry *roe = dentry->d_sb->s_root->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 *upperdir, *upperdentry = NULL;
struct dentry *index = NULL; struct dentry *index = NULL;
unsigned int ctr = 0; unsigned int ctr = 0;
...@@ -645,17 +657,17 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -645,17 +657,17 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
if (!d.stop && poe->numlower) { if (!d.stop && poe->numlower) {
err = -ENOMEM; err = -ENOMEM;
stack = kcalloc(ofs->numlower, sizeof(struct path), stack = kcalloc(ofs->numlower, sizeof(struct ovl_path),
GFP_KERNEL); GFP_KERNEL);
if (!stack) if (!stack)
goto out_put_upper; goto out_put_upper;
} }
for (i = 0; !d.stop && i < poe->numlower; i++) { 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; d.last = i == poe->numlower - 1;
err = ovl_lookup_layer(lowerpath.dentry, &d, &this); err = ovl_lookup_layer(lower.dentry, &d, &this);
if (err) if (err)
goto out_put; goto out_put;
...@@ -663,7 +675,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -663,7 +675,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
continue; continue;
stack[ctr].dentry = this; stack[ctr].dentry = this;
stack[ctr].mnt = lowerpath.mnt; stack[ctr].layer = lower.layer;
ctr++; ctr++;
if (d.stop) if (d.stop)
...@@ -673,10 +685,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -673,10 +685,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
poe = roe; poe = roe;
/* Find the current layer on the root dentry */ /* Find the current layer on the root dentry */
for (i = 0; i < poe->numlower; i++) i = ovl_find_layer(ofs, &lower);
if (poe->lowerstack[i].mnt == lowerpath.mnt) if (WARN_ON(i == ofs->numlower))
break;
if (WARN_ON(i == poe->numlower))
break; break;
} }
} }
...@@ -699,7 +709,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -699,7 +709,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
goto out_put; goto out_put;
oe->opaque = upperopaque; oe->opaque = upperopaque;
memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr); memcpy(oe->lowerstack, stack, sizeof(struct ovl_path) * ctr);
dentry->d_fsdata = oe; dentry->d_fsdata = oe;
if (upperdentry) if (upperdentry)
......
...@@ -251,7 +251,7 @@ static inline bool ovl_is_impuredir(struct dentry *dentry) ...@@ -251,7 +251,7 @@ static inline bool ovl_is_impuredir(struct dentry *dentry)
/* namei.c */ /* namei.c */
int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt, int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt,
struct dentry *origin, bool is_upper, bool set); 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); unsigned int numlower);
int ovl_get_index_name(struct dentry *origin, struct qstr *name); int ovl_get_index_name(struct dentry *origin, struct qstr *name);
int ovl_path_next(int idx, struct dentry *dentry, struct path *path); int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
...@@ -268,7 +268,7 @@ int ovl_check_d_type_supported(struct path *realpath); ...@@ -268,7 +268,7 @@ int ovl_check_d_type_supported(struct path *realpath);
void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt, void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
struct dentry *dentry, int level); struct dentry *dentry, int level);
int ovl_indexdir_cleanup(struct dentry *dentry, 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);
/* inode.c */ /* inode.c */
int ovl_set_nlink_upper(struct dentry *dentry); int ovl_set_nlink_upper(struct dentry *dentry);
......
...@@ -17,11 +17,20 @@ struct ovl_config { ...@@ -17,11 +17,20 @@ struct ovl_config {
bool index; 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 */ /* private information held for overlayfs's superblock */
struct ovl_fs { struct ovl_fs {
struct vfsmount *upper_mnt; struct vfsmount *upper_mnt;
unsigned numlower; unsigned numlower;
struct vfsmount **lower_mnt; struct ovl_layer *lower_layers;
/* workbasedir is the path at workdir= mount option */ /* workbasedir is the path at workdir= mount option */
struct dentry *workbasedir; struct dentry *workbasedir;
/* workdir is the 'work' directory under workbasedir */ /* workdir is the 'work' directory under workbasedir */
...@@ -52,7 +61,7 @@ struct ovl_entry { ...@@ -52,7 +61,7 @@ struct ovl_entry {
struct rcu_head rcu; struct rcu_head rcu;
}; };
unsigned numlower; unsigned numlower;
struct path lowerstack[]; struct ovl_path lowerstack[];
}; };
struct ovl_entry *ovl_alloc_entry(unsigned int numlower); struct ovl_entry *ovl_alloc_entry(unsigned int numlower);
......
...@@ -1014,7 +1014,7 @@ void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt, ...@@ -1014,7 +1014,7 @@ void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
} }
int ovl_indexdir_cleanup(struct dentry *dentry, 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; int err;
struct dentry *index = NULL; struct dentry *index = NULL;
...@@ -1049,7 +1049,7 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt, ...@@ -1049,7 +1049,7 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
index = NULL; index = NULL;
break; break;
} }
err = ovl_verify_index(index, lowerstack, numlower); err = ovl_verify_index(index, lower, numlower);
/* Cleanup stale and orphan index entries */ /* Cleanup stale and orphan index entries */
if (err && (err == -ESTALE || err == -ENOENT)) if (err && (err == -ESTALE || err == -ENOENT))
err = ovl_cleanup(dir, index); err = ovl_cleanup(dir, index);
......
...@@ -220,8 +220,8 @@ static void ovl_put_super(struct super_block *sb) ...@@ -220,8 +220,8 @@ static void ovl_put_super(struct super_block *sb)
ovl_inuse_unlock(ufs->upper_mnt->mnt_root); ovl_inuse_unlock(ufs->upper_mnt->mnt_root);
mntput(ufs->upper_mnt); mntput(ufs->upper_mnt);
for (i = 0; i < ufs->numlower; i++) for (i = 0; i < ufs->numlower; i++)
mntput(ufs->lower_mnt[i]); mntput(ufs->lower_layers[i].mnt);
kfree(ufs->lower_mnt); kfree(ufs->lower_layers);
kfree(ufs->config.lowerdir); kfree(ufs->config.lowerdir);
kfree(ufs->config.upperdir); kfree(ufs->config.upperdir);
...@@ -1026,24 +1026,26 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1026,24 +1026,26 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
} }
err = -ENOMEM; err = -ENOMEM;
ufs->lower_mnt = kcalloc(numlower, sizeof(struct vfsmount *), GFP_KERNEL); ufs->lower_layers = kcalloc(numlower, sizeof(struct ovl_layer),
if (ufs->lower_mnt == NULL) GFP_KERNEL);
if (ufs->lower_layers == NULL)
goto out_put_workdir; goto out_put_workdir;
for (i = 0; i < numlower; i++) { 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); err = PTR_ERR(mnt);
if (IS_ERR(mnt)) { if (IS_ERR(mnt)) {
pr_err("overlayfs: failed to clone lowerpath\n"); 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. * will fail instead of modifying lower fs.
*/ */
mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME; mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
ufs->lower_mnt[ufs->numlower] = mnt; ufs->lower_layers[ufs->numlower].mnt = mnt;
ufs->numlower++; ufs->numlower++;
/* Check if all lower layers are on same sb */ /* Check if all lower layers are on same sb */
...@@ -1059,13 +1061,25 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -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) else if (ufs->upper_mnt->mnt_sb != ufs->same_sb)
ufs->same_sb = NULL; 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) { if (!(ovl_force_readonly(ufs)) && ufs->config.index) {
/* Verify lower root is upper root origin */ /* Verify lower root is upper root origin */
err = ovl_verify_origin(upperpath.dentry, ufs->lower_mnt[0], err = ovl_verify_origin(upperpath.dentry,
stack[0].dentry, false, true); oe->lowerstack[0].layer->mnt,
oe->lowerstack[0].dentry,
false, true);
if (err) { if (err) {
pr_err("overlayfs: failed to verify upper root origin\n"); 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, ufs->indexdir = ovl_workdir_create(sb, ufs, workpath.dentry,
...@@ -1081,7 +1095,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1081,7 +1095,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
if (!err) if (!err)
err = ovl_indexdir_cleanup(ufs->indexdir, err = ovl_indexdir_cleanup(ufs->indexdir,
ufs->upper_mnt, ufs->upper_mnt,
stack, numlower); oe->lowerstack,
numlower);
} }
if (err || !ufs->indexdir) if (err || !ufs->indexdir)
pr_warn("overlayfs: try deleting index dir or mounting with '-o index=off' to disable inodes index.\n"); pr_warn("overlayfs: try deleting index dir or mounting with '-o index=off' to disable inodes index.\n");
...@@ -1106,11 +1121,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -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 */ /* Never override disk quota limits or use reserved space */
cap_lower(cred->cap_effective, CAP_SYS_RESOURCE); 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_magic = OVERLAYFS_SUPER_MAGIC;
sb->s_op = &ovl_super_operations; sb->s_op = &ovl_super_operations;
sb->s_xattr = ovl_xattr_handlers; sb->s_xattr = ovl_xattr_handlers;
...@@ -1119,11 +1129,12 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -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)); root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, 0));
if (!root_dentry) if (!root_dentry)
goto out_free_oe; goto out_put_cred;
mntput(upperpath.mnt); mntput(upperpath.mnt);
for (i = 0; i < numlower; i++) for (i = 0; i < numlower; i++)
mntput(stack[i].mnt); mntput(stack[i].mnt);
kfree(stack);
mntput(workpath.mnt); mntput(workpath.mnt);
kfree(lowertmp); kfree(lowertmp);
...@@ -1132,11 +1143,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1132,11 +1143,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
if (ovl_is_impuredir(upperpath.dentry)) if (ovl_is_impuredir(upperpath.dentry))
ovl_set_flag(OVL_IMPURE, d_inode(root_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; root_dentry->d_fsdata = oe;
...@@ -1149,16 +1155,16 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1149,16 +1155,16 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
return 0; return 0;
out_free_oe:
kfree(oe);
out_put_cred: out_put_cred:
put_cred(ufs->creator_cred); put_cred(ufs->creator_cred);
out_put_indexdir: out_put_indexdir:
dput(ufs->indexdir); dput(ufs->indexdir);
out_put_lower_mnt: out_free_oe:
kfree(oe);
out_put_lower_layers:
for (i = 0; i < ufs->numlower; i++) for (i = 0; i < ufs->numlower; i++)
mntput(ufs->lower_mnt[i]); mntput(ufs->lower_layers[i].mnt);
kfree(ufs->lower_mnt); kfree(ufs->lower_layers);
out_put_workdir: out_put_workdir:
dput(ufs->workdir); dput(ufs->workdir);
mntput(ufs->upper_mnt); mntput(ufs->upper_mnt);
......
...@@ -124,7 +124,12 @@ void ovl_path_lower(struct dentry *dentry, struct path *path) ...@@ -124,7 +124,12 @@ void ovl_path_lower(struct dentry *dentry, struct path *path)
{ {
struct ovl_entry *oe = dentry->d_fsdata; 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) enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment