Commit 66bc346d authored by J. R. Okajima's avatar J. R. Okajima
Browse files

aufs: readonly branch 2/2, callers



For details, see previous commit.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent b7051459
......@@ -10,11 +10,11 @@ ccflags-y += -DDEBUG
ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h
obj-$(CONFIG_AUFS_FS) += aufs.o
aufs-y := module.o sbinfo.o super.o branch.o \
dcsub.o \
aufs-y := module.o sbinfo.o super.o branch.o opts.o \
vfsub.o dcsub.o \
cpup.o \
dinfo.o \
iinfo.o
iinfo.o inode.o
# all are boolean
aufs-$(CONFIG_AUFS_DEBUG) += debug.o
......@@ -83,6 +83,8 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
int perm)
{
struct au_branch *add_branch;
struct dentry *root;
struct inode *inode;
int err;
err = -ENOMEM;
......@@ -90,9 +92,6 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
if (unlikely(!add_branch))
goto out;
#if 0 /* re-commit later */
struct dentry *root;
struct inode *inode;
root = sb->s_root;
err = au_sbr_realloc(au_sbi(sb), new_nbranch, /*may_shrink*/0);
if (!err)
......@@ -102,7 +101,6 @@ static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
err = au_hinode_realloc(au_ii(inode), new_nbranch,
/*may_shrink*/0);
}
#endif
if (!err)
return add_branch; /* success */
......@@ -127,8 +125,7 @@ static int test_add(struct super_block *sb, struct au_opt_add *add)
root = sb->s_root;
bbot = au_sbbot(sb);
if (unlikely(bbot >= 0
/* re-commit later */
/* && au_find_dbindex(root, add->path.dentry) >= 0 */)) {
&& au_find_dbindex(root, add->path.dentry) >= 0)) {
err = -EINVAL;
pr_err("%s duplicated\n", add->pathname);
goto out;
......@@ -273,8 +270,7 @@ static void au_br_do_add(struct super_block *sb, struct au_branch *br,
au_br_do_add_hip(au_ii(root_inode), bindex, bbot, amount);
au_set_h_dptr(root, bindex, dget(h_dentry));
h_inode = d_inode(h_dentry);
/* re-commit later */
/* au_set_h_iptr(root_inode, bindex, au_igrab(h_inode), /\*flags*\/0); */
au_set_h_iptr(root_inode, bindex, au_igrab(h_inode), /*flags*/0);
}
int au_br_add(struct super_block *sb, struct au_opt_add *add)
......
......@@ -17,6 +17,7 @@
struct au_hdentry {
struct dentry *hd_dentry;
aufs_bindex_t hd_id;
};
struct au_dinfo {
......@@ -36,6 +37,7 @@ struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc);
void au_di_free(struct au_dinfo *dinfo);
int au_di_init(struct dentry *dentry);
void au_di_fin(struct dentry *dentry);
int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink);
void di_read_lock(struct dentry *d, int flags, unsigned int lsc);
void di_read_unlock(struct dentry *d, int flags);
......@@ -51,6 +53,7 @@ int au_digen_test(struct dentry *dentry, unsigned int sigen);
void au_update_digen(struct dentry *dentry);
void au_update_dbtop(struct dentry *dentry);
void au_update_dbbot(struct dentry *dentry);
int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry);
/* ---------------------------------------------------------------------- */
......
......@@ -19,18 +19,22 @@ void au_di_init_once(void *_dinfo)
struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc)
{
struct au_dinfo *dinfo;
int nbr;
int nbr, i;
dinfo = au_cache_alloc_dinfo();
if (unlikely(!dinfo))
goto out;
nbr = 1; /* re-commit later */
nbr = au_sbbot(sb) + 1;
if (nbr <= 0)
nbr = 1;
dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS);
if (dinfo->di_hdentry) {
au_rw_write_lock_nested(&dinfo->di_rwsem, lsc);
dinfo->di_btop = -1;
dinfo->di_bbot = -1;
for (i = 0; i < nbr; i++)
dinfo->di_hdentry[i].hd_id = -1;
goto out;
}
......@@ -86,6 +90,27 @@ void au_di_fin(struct dentry *dentry)
au_di_free(dinfo);
}
int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink)
{
int err, sz;
struct au_hdentry *hdp;
AuRwMustWriteLock(&dinfo->di_rwsem);
err = -ENOMEM;
sz = sizeof(*hdp) * (dinfo->di_bbot + 1);
if (!sz)
sz = sizeof(*hdp);
hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS,
may_shrink);
if (hdp) {
dinfo->di_hdentry = hdp;
err = 0;
}
return err;
}
/* ---------------------------------------------------------------------- */
static void do_ii_write_lock(struct inode *inode, unsigned int lsc)
......@@ -216,6 +241,7 @@ void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
{
struct au_dinfo *dinfo;
struct au_hdentry *hd;
struct au_branch *br;
DiMustWriteLock(dentry);
......@@ -223,6 +249,10 @@ void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
hd = au_hdentry(dinfo, bindex);
au_hdput(hd);
hd->hd_dentry = h_dentry;
if (h_dentry) {
br = au_sbr(dentry->d_sb, bindex);
hd->hd_id = br->br_id;
}
}
int au_digen_test(struct dentry *dentry, unsigned int sigen)
......@@ -278,3 +308,14 @@ void au_update_dbbot(struct dentry *dentry)
au_set_h_dptr(dentry, bindex, NULL);
}
}
int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry)
{
aufs_bindex_t bindex, bbot;
bbot = au_dbbot(dentry);
for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++)
if (au_h_dptr(dentry, bindex) == h_dentry)
return bindex;
return -1;
}
......@@ -45,11 +45,16 @@ void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex,
au_hiput(hinode);
hinode->hi_inode = h_inode;
if (h_inode) {
struct super_block *sb = inode->i_sb;
struct au_branch *br;
AuDebugOn(inode->i_mode
&& (h_inode->i_mode & S_IFMT)
!= (inode->i_mode & S_IFMT));
if (bindex == iinfo->ii_btop)
au_cpup_igen(inode, h_inode);
br = au_sbr(sb, bindex);
hinode->hi_id = br->br_id;
}
}
......@@ -82,6 +87,7 @@ void au_icntnr_init_once(void *_c)
void au_hinode_init(struct au_hinode *hinode)
{
hinode->hi_inode = NULL;
hinode->hi_id = -1;
}
int au_iinfo_init(struct inode *inode)
......@@ -93,7 +99,9 @@ int au_iinfo_init(struct inode *inode)
sb = inode->i_sb;
iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo);
nbr = 1; /* re-commit later */
nbr = au_sbbot(sb) + 1;
if (unlikely(nbr <= 0))
nbr = 1;
hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS);
if (hi) {
iinfo->ii_hinode = hi;
......@@ -108,6 +116,28 @@ int au_iinfo_init(struct inode *inode)
return -ENOMEM;
}
int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink)
{
int err, i;
struct au_hinode *hip;
AuRwMustWriteLock(&iinfo->ii_rwsem);
err = -ENOMEM;
hip = au_krealloc(iinfo->ii_hinode, sizeof(*hip) * nbr, GFP_NOFS,
may_shrink);
if (hip) {
iinfo->ii_hinode = hip;
i = iinfo->ii_bbot + 1;
hip += i;
for (; i < nbr; i++, hip++)
au_hinode_init(hip);
err = 0;
}
return err;
}
void au_iinfo_fin(struct inode *inode)
{
struct au_iinfo *iinfo;
......@@ -127,6 +157,6 @@ void au_iinfo_fin(struct inode *inode)
hi++;
}
}
au_kfree_small(iinfo->ii_hinode);
au_kfree_rcu(iinfo->ii_hinode);
AuRwDestroy(&iinfo->ii_rwsem);
}
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2005-2019 Junjiro R. Okajima
*/
/*
* inode functions
*/
#include "aufs.h"
struct inode *au_igrab(struct inode *inode)
{
if (inode) {
AuDebugOn(!atomic_read(&inode->i_count));
ihold(inode);
}
return inode;
}
......@@ -17,6 +17,7 @@
struct au_hinode {
struct inode *hi_inode;
aufs_bindex_t hi_id;
};
struct au_iigen {
......@@ -50,6 +51,9 @@ static inline struct au_iinfo *au_ii(struct inode *inode)
/* ---------------------------------------------------------------------- */
/* inode.c */
struct inode *au_igrab(struct inode *inode);
/* iinfo.c */
struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex);
void au_hiput(struct au_hinode *hinode);
......@@ -63,6 +67,7 @@ void au_icntnr_init_once(void *_c);
void au_hinode_init(struct au_hinode *hinode);
int au_iinfo_init(struct inode *inode);
void au_iinfo_fin(struct inode *inode);
int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink);
/* ---------------------------------------------------------------------- */
......@@ -194,6 +199,13 @@ static inline int au_is_bad_inode(struct inode *inode)
return !!(is_bad_inode(inode) || !au_hinode(au_ii(inode), 0));
}
static inline aufs_bindex_t au_ii_br_id(struct inode *inode,
aufs_bindex_t bindex)
{
IiMustAnyLock(inode);
return au_hinode(au_ii(inode), bindex)->hi_id;
}
static inline aufs_bindex_t au_ibtop(struct inode *inode)
{
IiMustAnyLock(inode);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2005-2019 Junjiro R. Okajima
*/
/*
* mount options/flags
*/
#include <linux/namei.h>
#include <linux/types.h> /* a distribution requires */
#include <linux/parser.h>
#include "aufs.h"
/* ---------------------------------------------------------------------- */
enum {
Opt_br,
Opt_add,
Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err
};
static match_table_t options = {
{Opt_br, "br=%s"},
{Opt_br, "br:%s"},
/* internal use for the scripts */
{Opt_ignore_silent, "si=%s"},
/* temporary workaround, due to old mount(8)? */
{Opt_ignore_silent, "relatime"},
{Opt_err, NULL}
};
/* ---------------------------------------------------------------------- */
static const char *au_optstr(int *val, match_table_t tbl)
{
struct match_token *p;
int v;
v = *val;
if (!v)
goto out;
p = tbl;
while (p->pattern) {
if (p->token
&& (v & p->token) == p->token) {
*val &= ~p->token;
return p->pattern;
}
p++;
}
out:
return NULL;
}
/* ---------------------------------------------------------------------- */
static match_table_t brperm = {
{AuBrPerm_RO, AUFS_BRPERM_RO},
/* add more later */
{0, NULL}
};
static match_table_t brattr = {
/* add more later */
{0, NULL}
};
static int br_attr_val(char *str, match_table_t table, substring_t args[])
{
int attr, v;
char *p;
attr = 0;
do {
p = strchr(str, '+');
if (p)
*p = 0;
v = match_token(str, table, args);
if (v)
attr |= v;
else {
if (p)
*p = '+';
pr_warn("ignored branch attribute %s\n", str);
break;
}
if (p)
str = p + 1;
} while (p);
return attr;
}
static int au_do_optstr_br_attr(au_br_perm_str_t *str, int perm)
{
int sz;
const char *p;
char *q;
q = str->a;
*q = 0;
p = au_optstr(&perm, brattr);
if (p) {
sz = strlen(p);
memcpy(q, p, sz + 1);
q += sz;
} else
goto out;
do {
p = au_optstr(&perm, brattr);
if (p) {
*q++ = '+';
sz = strlen(p);
memcpy(q, p, sz + 1);
q += sz;
}
} while (p);
out:
return q - str->a;
}
static int noinline_for_stack br_perm_val(char *perm)
{
int val;
char *p;
substring_t args[MAX_OPT_ARGS];
p = strchr(perm, '+');
if (p)
*p = 0;
val = match_token(perm, brperm, args);
if (!val) {
if (p)
*p = '+';
pr_warn("ignored branch permission %s\n", perm);
val = AuBrPerm_RO;
goto out;
}
if (!p)
goto out;
val |= br_attr_val(p + 1, brattr, args);
out:
return val;
}
void au_optstr_br_perm(au_br_perm_str_t *str, int perm)
{
au_br_perm_str_t attr;
const char *p;
char *q;
int sz;
q = str->a;
p = au_optstr(&perm, brperm);
AuDebugOn(!p || !*p);
sz = strlen(p);
memcpy(q, p, sz + 1);
q += sz;
sz = au_do_optstr_br_attr(&attr, perm);
if (sz) {
*q++ = '+';
memcpy(q, attr.a, sz + 1);
}
AuDebugOn(strlen(str->a) >= sizeof(str->a));
}
/* ---------------------------------------------------------------------- */
static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
static void dump_opts(struct au_opts *opts)
{
#ifdef CONFIG_AUFS_DEBUG
/* reduce stack space */
union {
struct au_opt_add *add;
} u;
struct au_opt *opt;
opt = opts->opt;
while (opt->type != Opt_tail) {
switch (opt->type) {
case Opt_add:
u.add = &opt->add;
AuDbg("add {b%d, %s, 0x%x, %p}\n",
u.add->bindex, u.add->pathname, u.add->perm,
u.add->path.dentry);
break;
default:
BUG();
}
opt++;
}
#endif
}
void au_opts_free(struct au_opts *opts)
{
struct au_opt *opt;
opt = opts->opt;
while (opt->type != Opt_tail) {
switch (opt->type) {
case Opt_add:
path_put(&opt->add.path);
break;
}
opt++;
}
}
static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags,
aufs_bindex_t bindex)
{
int err;
struct au_opt_add *add = &opt->add;
char *p;
add->bindex = bindex;
add->perm = AuBrPerm_RO;
add->pathname = opt_str;
p = strchr(opt_str, '=');
if (p) {
*p++ = 0;
if (*p)
add->perm = br_perm_val(p);
}
err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path);
if (!err) {
if (!p)
add->perm = AuBrPerm_RO;
/* re-commit later */
opt->type = Opt_add;
goto out;
}
pr_err("lookup failed %s (%d)\n", add->pathname, err);
err = -EINVAL;
out:
return err;
}
/* called without aufs lock */
int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
{
int err, n, token;
aufs_bindex_t bindex;
unsigned char skipped;
struct dentry *root;
struct au_opt *opt, *opt_tail;
char *opt_str;
/* reduce the stack space */
struct {
substring_t args[MAX_OPT_ARGS];
} *a;
err = -ENOMEM;
a = kmalloc(sizeof(*a), GFP_NOFS);
if (unlikely(!a))
goto out;
root = sb->s_root;
err = 0;
bindex = 0;
opt = opts->opt;
opt_tail = opt + opts->max_opt - 1;
opt->type = Opt_tail;
while (!err && (opt_str = strsep(&str, ",")) && *opt_str) {
err = -EINVAL;
skipped = 0;
token = match_token(opt_str, options, a->args);
switch (token) {
case Opt_br:
err = 0;
while (!err && (opt_str = strsep(&a->args[0].from, ":"))
&& *opt_str) {
err = opt_add(opt, opt_str, opts->sb_flags,
bindex++);
if (unlikely(!err && ++opt > opt_tail)) {
err = -E2BIG;
break;
}
opt->type = Opt_tail;
skipped = 1;
}
break;
case Opt_add:
if (unlikely(match_int(&a->args[0], &n))) {
pr_err("bad integer in %s\n", opt_str);
break;
}
bindex = n;
err = opt_add(opt, a->args[1].from, opts->sb_flags,
bindex);
if (!err)
opt->type = token;
break;
case Opt_ignore:
pr_warn("ignored %s\n", opt_str);
/*FALLTHROUGH*/
case Opt_ignore_silent:
skipped = 1;
err = 0;
break;
case Opt_err:
pr_err("unknown option %s\n", opt_str);
break;
}
if (!err && !skipped) {
if (unlikely(++opt > opt_tail)) {
err = -E2BIG;
opt--;
opt->type = Opt_tail;
break;
}
opt->type = Opt_tail;
}
}
au_kfree_rcu(a);
dump_opts(opts);
if (unlikely(err))
au_opts_free(opts);
out:
return err;
}
/*
* returns tri-state.
* plus: processed without an error
* zero: unprocessed
* minus: error
*/
static int au_opt_br(struct super_block *sb, struct au_opt *opt,
struct au_opts *opts)
{
int err;
err = 0;
switch (opt->type) {
case Opt_add:
err = au_br_add(sb, &opt->add);
if (!err) {
err = 1;
/* au_fset_opts(opts->flags, REFRESH); re-commit later */
}
break;
}
return err;
}
int au_opts_mount(struct super_block *sb, struct au_opts *opts)
{
int err;
unsigned int tmp;
aufs_bindex_t bbot;
struct au_opt *opt;
struct au_sbinfo *sbinfo;
SiMustWriteLock(sb);
err = 0;
opt = opts->opt;
while (err >= 0 && opt->type != Opt_tail)
/* re-commit later */
/* err = au_opt_simple(sb, opt++, opts); */
err = 0;
if (err > 0)
err = 0;
else if (unlikely(err < 0))
goto out;
sbinfo = au_sbi(sb);
tmp = sbinfo->si_mntflags;
opt = opts->opt;
while (err >= 0 && opt->type != Opt_tail)
err = au_opt_br(sb, opt++, opts);
if (err > 0)
err = 0;
else if (unlikely(err < 0))
goto out;
bbot = au_sbbot(sb);
if (unlikely(bbot < 0)) {
err = -EINVAL;
pr_err("no branches\n");
goto out;
}
out:
return err;
}
......@@ -32,7 +32,19 @@ struct au_opt {
struct au_opts {
struct au_opt *opt;
int max_opt;
unsigned long sb_flags;
};
/* ---------------------------------------------------------------------- */
/* opts.c */
void au_optstr_br_perm(au_br_perm_str_t *str, int perm);
void au_opts_free(struct au_opts *opts);
struct super_block;
int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts);
int au_opts_mount(struct super_block *sb, struct au_opts *opts);
#endif /* __KERNEL__ */
#endif /* __AUFS_OPTS_H__ */
......@@ -18,6 +18,11 @@ void au_si_free(struct kobject *kobj)
struct au_sbinfo *sbinfo;
sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
au_rw_write_lock(&sbinfo->si_rwsem);
au_br_free(sbinfo);
au_rw_write_unlock(&sbinfo->si_rwsem);
au_kfree_try_rcu(sbinfo->si_branch);
AuRwDestroy(&sbinfo->si_rwsem);
......@@ -55,6 +60,27 @@ out:
return err;
}
int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink)
{
int err, sz;
struct au_branch **brp;
AuRwMustWriteLock(&sbinfo->si_rwsem);
err = -ENOMEM;
sz = sizeof(*brp) * (sbinfo->si_bbot + 1);
if (unlikely(!sz))
sz = sizeof(*brp);
brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS,
may_shrink);
if (brp) {
sbinfo->si_branch = brp;
err = 0;
}
return err;
}
/* ---------------------------------------------------------------------- */
unsigned int au_sigen_inc(struct super_block *sb)
......
......@@ -34,6 +34,10 @@ struct au_sbinfo {
sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1;
struct au_branch **si_branch;
/* mount flags */
/* include/asm-ia64/siginfo.h defines a macro named si_flags */
unsigned int si_mntflags;
/*
* sysfs and lifetime management.
* this is not a small structure and it may be a waste of memory in case
......@@ -63,6 +67,7 @@ struct inode *au_iget_locked(struct super_block *sb, ino_t ino);
/* sbinfo.c */
void au_si_free(struct kobject *kobj);
int au_si_alloc(struct super_block *sb);
int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink);
unsigned int au_sigen_inc(struct super_block *sb);
aufs_bindex_t au_new_br_id(struct super_block *sb);
......@@ -104,6 +109,12 @@ static inline aufs_bindex_t au_sbbot(struct super_block *sb)
return au_sbi(sb)->si_bbot;
}
static inline unsigned int au_mntflags(struct super_block *sb)
{
SiMustAnyLock(sb);
return au_sbi(sb)->si_mntflags;
}
static inline unsigned int au_sigen(struct super_block *sb)
{
SiMustAnyLock(sb);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2005-2019 Junjiro R. Okajima
*/
/*
* sub-routines for VFS
*/
#include <linux/namei.h>
#include "aufs.h"
int vfsub_kern_path(const char *name, unsigned int flags, struct path *path)
{
int err;
err = kern_path(name, flags, path);
/* add more later */
return err;
}
......@@ -19,5 +19,7 @@
#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx))
#define IMustLock(i) AuDebugOn(!inode_is_locked(i))
int vfsub_kern_path(const char *name, unsigned int flags, struct path *path);
#endif /* __KERNEL__ */
#endif /* __AUFS_VFSUB_H__ */
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