summaryrefslogtreecommitdiff
path: root/fs/aufs/opts.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/aufs/opts.c')
-rw-r--r--fs/aufs/opts.c1835
1 files changed, 0 insertions, 1835 deletions
diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c
deleted file mode 100644
index 4e8e2e1ff..000000000
--- a/fs/aufs/opts.c
+++ /dev/null
@@ -1,1835 +0,0 @@
-/*
- * Copyright (C) 2005-2015 Junjiro R. Okajima
- *
- * This program, aufs is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * 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_del, Opt_mod, Opt_append, Opt_prepend,
- Opt_idel, Opt_imod,
- Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash,
- Opt_rdblk_def, Opt_rdhash_def,
- Opt_xino, Opt_noxino,
- Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino,
- Opt_trunc_xino_path, Opt_itrunc_xino,
- Opt_trunc_xib, Opt_notrunc_xib,
- Opt_shwh, Opt_noshwh,
- Opt_plink, Opt_noplink, Opt_list_plink,
- Opt_udba,
- Opt_dio, Opt_nodio,
- Opt_diropq_a, Opt_diropq_w,
- Opt_warn_perm, Opt_nowarn_perm,
- Opt_wbr_copyup, Opt_wbr_create,
- Opt_fhsm_sec,
- Opt_verbose, Opt_noverbose,
- Opt_sum, Opt_nosum, Opt_wsum,
- Opt_dirperm1, Opt_nodirperm1,
- Opt_acl, Opt_noacl,
- Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err
-};
-
-static match_table_t options = {
- {Opt_br, "br=%s"},
- {Opt_br, "br:%s"},
-
- {Opt_add, "add=%d:%s"},
- {Opt_add, "add:%d:%s"},
- {Opt_add, "ins=%d:%s"},
- {Opt_add, "ins:%d:%s"},
- {Opt_append, "append=%s"},
- {Opt_append, "append:%s"},
- {Opt_prepend, "prepend=%s"},
- {Opt_prepend, "prepend:%s"},
-
- {Opt_del, "del=%s"},
- {Opt_del, "del:%s"},
- /* {Opt_idel, "idel:%d"}, */
- {Opt_mod, "mod=%s"},
- {Opt_mod, "mod:%s"},
- /* {Opt_imod, "imod:%d:%s"}, */
-
- {Opt_dirwh, "dirwh=%d"},
-
- {Opt_xino, "xino=%s"},
- {Opt_noxino, "noxino"},
- {Opt_trunc_xino, "trunc_xino"},
- {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"},
- {Opt_notrunc_xino, "notrunc_xino"},
- {Opt_trunc_xino_path, "trunc_xino=%s"},
- {Opt_itrunc_xino, "itrunc_xino=%d"},
- /* {Opt_zxino, "zxino=%s"}, */
- {Opt_trunc_xib, "trunc_xib"},
- {Opt_notrunc_xib, "notrunc_xib"},
-
-#ifdef CONFIG_PROC_FS
- {Opt_plink, "plink"},
-#else
- {Opt_ignore_silent, "plink"},
-#endif
-
- {Opt_noplink, "noplink"},
-
-#ifdef CONFIG_AUFS_DEBUG
- {Opt_list_plink, "list_plink"},
-#endif
-
- {Opt_udba, "udba=%s"},
-
- {Opt_dio, "dio"},
- {Opt_nodio, "nodio"},
-
-#ifdef CONFIG_AUFS_FHSM
- {Opt_fhsm_sec, "fhsm_sec=%d"},
-#else
- {Opt_ignore_silent, "fhsm_sec=%d"},
-#endif
-
- {Opt_diropq_a, "diropq=always"},
- {Opt_diropq_a, "diropq=a"},
- {Opt_diropq_w, "diropq=whiteouted"},
- {Opt_diropq_w, "diropq=w"},
-
- {Opt_warn_perm, "warn_perm"},
- {Opt_nowarn_perm, "nowarn_perm"},
-
- /* keep them temporary */
- {Opt_ignore_silent, "nodlgt"},
- {Opt_ignore_silent, "clean_plink"},
-
-#ifdef CONFIG_AUFS_SHWH
- {Opt_shwh, "shwh"},
-#endif
- {Opt_noshwh, "noshwh"},
-
- {Opt_dirperm1, "dirperm1"},
- {Opt_nodirperm1, "nodirperm1"},
-
- {Opt_verbose, "verbose"},
- {Opt_verbose, "v"},
- {Opt_noverbose, "noverbose"},
- {Opt_noverbose, "quiet"},
- {Opt_noverbose, "q"},
- {Opt_noverbose, "silent"},
-
- {Opt_sum, "sum"},
- {Opt_nosum, "nosum"},
- {Opt_wsum, "wsum"},
-
- {Opt_rdcache, "rdcache=%d"},
- {Opt_rdblk, "rdblk=%d"},
- {Opt_rdblk_def, "rdblk=def"},
- {Opt_rdhash, "rdhash=%d"},
- {Opt_rdhash_def, "rdhash=def"},
-
- {Opt_wbr_create, "create=%s"},
- {Opt_wbr_create, "create_policy=%s"},
- {Opt_wbr_copyup, "cpup=%s"},
- {Opt_wbr_copyup, "copyup=%s"},
- {Opt_wbr_copyup, "copyup_policy=%s"},
-
- /* generic VFS flag */
-#ifdef CONFIG_FS_POSIX_ACL
- {Opt_acl, "acl"},
- {Opt_noacl, "noacl"},
-#else
- {Opt_ignore_silent, "acl"},
- {Opt_ignore_silent, "noacl"},
-#endif
-
- /* internal use for the scripts */
- {Opt_ignore_silent, "si=%s"},
-
- {Opt_br, "dirs=%s"},
- {Opt_ignore, "debug=%d"},
- {Opt_ignore, "delete=whiteout"},
- {Opt_ignore, "delete=all"},
- {Opt_ignore, "imap=%s"},
-
- /* temporary workaround, due to old mount(8)? */
- {Opt_ignore_silent, "relatime"},
-
- {Opt_err, NULL}
-};
-
-/* ---------------------------------------------------------------------- */
-
-static const char *au_parser_pattern(int val, match_table_t tbl)
-{
- struct match_token *p;
-
- p = tbl;
- while (p->pattern) {
- if (p->token == val)
- return p->pattern;
- p++;
- }
- BUG();
- return "??";
-}
-
-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},
- {AuBrPerm_RR, AUFS_BRPERM_RR},
- {AuBrPerm_RW, AUFS_BRPERM_RW},
- {0, NULL}
-};
-
-static match_table_t brattr = {
- /* general */
- {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG},
- {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL},
- /* 'unpin' attrib is meaningless since linux-3.18-rc1 */
- {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN},
-#ifdef CONFIG_AUFS_FHSM
- {AuBrAttr_FHSM, AUFS_BRATTR_FHSM},
-#endif
-#ifdef CONFIG_AUFS_XATTR
- {AuBrAttr_ICEX, AUFS_BRATTR_ICEX},
- {AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC},
- {AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS},
- {AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR},
- {AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR},
- {AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH},
-#endif
-
- /* ro/rr branch */
- {AuBrRAttr_WH, AUFS_BRRATTR_WH},
-
- /* rw branch */
- {AuBrWAttr_MOO, AUFS_BRWATTR_MOO},
- {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH},
-
- {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) {
- if (v & AuBrAttr_CMOO_Mask)
- attr &= ~AuBrAttr_CMOO_Mask;
- 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, bad, sz;
- char *p;
- substring_t args[MAX_OPT_ARGS];
- au_br_perm_str_t attr;
-
- 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);
-
- bad = 0;
- switch (val & AuBrPerm_Mask) {
- case AuBrPerm_RO:
- case AuBrPerm_RR:
- bad = val & AuBrWAttr_Mask;
- val &= ~AuBrWAttr_Mask;
- break;
- case AuBrPerm_RW:
- bad = val & AuBrRAttr_Mask;
- val &= ~AuBrRAttr_Mask;
- break;
- }
-
- /*
- * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs
- * does not treat it as an error, just warning.
- * this is a tiny guard for the user operation.
- */
- if (val & AuBrAttr_UNPIN) {
- bad |= AuBrAttr_UNPIN;
- val &= ~AuBrAttr_UNPIN;
- }
-
- if (unlikely(bad)) {
- sz = au_do_optstr_br_attr(&attr, bad);
- AuDebugOn(!sz);
- pr_warn("ignored branch attribute %s\n", attr.a);
- }
-
-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 match_table_t udbalevel = {
- {AuOpt_UDBA_REVAL, "reval"},
- {AuOpt_UDBA_NONE, "none"},
-#ifdef CONFIG_AUFS_HNOTIFY
- {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */
-#ifdef CONFIG_AUFS_HFSNOTIFY
- {AuOpt_UDBA_HNOTIFY, "fsnotify"},
-#endif
-#endif
- {-1, NULL}
-};
-
-static int noinline_for_stack udba_val(char *str)
-{
- substring_t args[MAX_OPT_ARGS];
-
- return match_token(str, udbalevel, args);
-}
-
-const char *au_optstr_udba(int udba)
-{
- return au_parser_pattern(udba, udbalevel);
-}
-
-/* ---------------------------------------------------------------------- */
-
-static match_table_t au_wbr_create_policy = {
- {AuWbrCreate_TDP, "tdp"},
- {AuWbrCreate_TDP, "top-down-parent"},
- {AuWbrCreate_RR, "rr"},
- {AuWbrCreate_RR, "round-robin"},
- {AuWbrCreate_MFS, "mfs"},
- {AuWbrCreate_MFS, "most-free-space"},
- {AuWbrCreate_MFSV, "mfs:%d"},
- {AuWbrCreate_MFSV, "most-free-space:%d"},
-
- {AuWbrCreate_MFSRR, "mfsrr:%d"},
- {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"},
- {AuWbrCreate_PMFS, "pmfs"},
- {AuWbrCreate_PMFSV, "pmfs:%d"},
- {AuWbrCreate_PMFSRR, "pmfsrr:%d"},
- {AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"},
-
- {-1, NULL}
-};
-
-/*
- * cf. linux/lib/parser.c and cmdline.c
- * gave up calling memparse() since it uses simple_strtoull() instead of
- * kstrto...().
- */
-static int noinline_for_stack
-au_match_ull(substring_t *s, unsigned long long *result)
-{
- int err;
- unsigned int len;
- char a[32];
-
- err = -ERANGE;
- len = s->to - s->from;
- if (len + 1 <= sizeof(a)) {
- memcpy(a, s->from, len);
- a[len] = '\0';
- err = kstrtoull(a, 0, result);
- }
- return err;
-}
-
-static int au_wbr_mfs_wmark(substring_t *arg, char *str,
- struct au_opt_wbr_create *create)
-{
- int err;
- unsigned long long ull;
-
- err = 0;
- if (!au_match_ull(arg, &ull))
- create->mfsrr_watermark = ull;
- else {
- pr_err("bad integer in %s\n", str);
- err = -EINVAL;
- }
-
- return err;
-}
-
-static int au_wbr_mfs_sec(substring_t *arg, char *str,
- struct au_opt_wbr_create *create)
-{
- int n, err;
-
- err = 0;
- if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC)
- create->mfs_second = n;
- else {
- pr_err("bad integer in %s\n", str);
- err = -EINVAL;
- }
-
- return err;
-}
-
-static int noinline_for_stack
-au_wbr_create_val(char *str, struct au_opt_wbr_create *create)
-{
- int err, e;
- substring_t args[MAX_OPT_ARGS];
-
- err = match_token(str, au_wbr_create_policy, args);
- create->wbr_create = err;
- switch (err) {
- case AuWbrCreate_MFSRRV:
- case AuWbrCreate_PMFSRRV:
- e = au_wbr_mfs_wmark(&args[0], str, create);
- if (!e)
- e = au_wbr_mfs_sec(&args[1], str, create);
- if (unlikely(e))
- err = e;
- break;
- case AuWbrCreate_MFSRR:
- case AuWbrCreate_PMFSRR:
- e = au_wbr_mfs_wmark(&args[0], str, create);
- if (unlikely(e)) {
- err = e;
- break;
- }
- /*FALLTHROUGH*/
- case AuWbrCreate_MFS:
- case AuWbrCreate_PMFS:
- create->mfs_second = AUFS_MFS_DEF_SEC;
- break;
- case AuWbrCreate_MFSV:
- case AuWbrCreate_PMFSV:
- e = au_wbr_mfs_sec(&args[0], str, create);
- if (unlikely(e))
- err = e;
- break;
- }
-
- return err;
-}
-
-const char *au_optstr_wbr_create(int wbr_create)
-{
- return au_parser_pattern(wbr_create, au_wbr_create_policy);
-}
-
-static match_table_t au_wbr_copyup_policy = {
- {AuWbrCopyup_TDP, "tdp"},
- {AuWbrCopyup_TDP, "top-down-parent"},
- {AuWbrCopyup_BUP, "bup"},
- {AuWbrCopyup_BUP, "bottom-up-parent"},
- {AuWbrCopyup_BU, "bu"},
- {AuWbrCopyup_BU, "bottom-up"},
- {-1, NULL}
-};
-
-static int noinline_for_stack au_wbr_copyup_val(char *str)
-{
- substring_t args[MAX_OPT_ARGS];
-
- return match_token(str, au_wbr_copyup_policy, args);
-}
-
-const char *au_optstr_wbr_copyup(int wbr_copyup)
-{
- return au_parser_pattern(wbr_copyup, au_wbr_copyup_policy);
-}
-
-/* ---------------------------------------------------------------------- */
-
-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;
- struct au_opt_del *del;
- struct au_opt_mod *mod;
- struct au_opt_xino *xino;
- struct au_opt_xino_itrunc *xino_itrunc;
- struct au_opt_wbr_create *create;
- } 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;
- case Opt_del:
- case Opt_idel:
- u.del = &opt->del;
- AuDbg("del {%s, %p}\n",
- u.del->pathname, u.del->h_path.dentry);
- break;
- case Opt_mod:
- case Opt_imod:
- u.mod = &opt->mod;
- AuDbg("mod {%s, 0x%x, %p}\n",
- u.mod->path, u.mod->perm, u.mod->h_root);
- break;
- case Opt_append:
- u.add = &opt->add;
- AuDbg("append {b%d, %s, 0x%x, %p}\n",
- u.add->bindex, u.add->pathname, u.add->perm,
- u.add->path.dentry);
- break;
- case Opt_prepend:
- u.add = &opt->add;
- AuDbg("prepend {b%d, %s, 0x%x, %p}\n",
- u.add->bindex, u.add->pathname, u.add->perm,
- u.add->path.dentry);
- break;
- case Opt_dirwh:
- AuDbg("dirwh %d\n", opt->dirwh);
- break;
- case Opt_rdcache:
- AuDbg("rdcache %d\n", opt->rdcache);
- break;
- case Opt_rdblk:
- AuDbg("rdblk %u\n", opt->rdblk);
- break;
- case Opt_rdblk_def:
- AuDbg("rdblk_def\n");
- break;
- case Opt_rdhash:
- AuDbg("rdhash %u\n", opt->rdhash);
- break;
- case Opt_rdhash_def:
- AuDbg("rdhash_def\n");
- break;
- case Opt_xino:
- u.xino = &opt->xino;
- AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file);
- break;
- case Opt_trunc_xino:
- AuLabel(trunc_xino);
- break;
- case Opt_notrunc_xino:
- AuLabel(notrunc_xino);
- break;
- case Opt_trunc_xino_path:
- case Opt_itrunc_xino:
- u.xino_itrunc = &opt->xino_itrunc;
- AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex);
- break;
- case Opt_noxino:
- AuLabel(noxino);
- break;
- case Opt_trunc_xib:
- AuLabel(trunc_xib);
- break;
- case Opt_notrunc_xib:
- AuLabel(notrunc_xib);
- break;
- case Opt_shwh:
- AuLabel(shwh);
- break;
- case Opt_noshwh:
- AuLabel(noshwh);
- break;
- case Opt_dirperm1:
- AuLabel(dirperm1);
- break;
- case Opt_nodirperm1:
- AuLabel(nodirperm1);
- break;
- case Opt_plink:
- AuLabel(plink);
- break;
- case Opt_noplink:
- AuLabel(noplink);
- break;
- case Opt_list_plink:
- AuLabel(list_plink);
- break;
- case Opt_udba:
- AuDbg("udba %d, %s\n",
- opt->udba, au_optstr_udba(opt->udba));
- break;
- case Opt_dio:
- AuLabel(dio);
- break;
- case Opt_nodio:
- AuLabel(nodio);
- break;
- case Opt_diropq_a:
- AuLabel(diropq_a);
- break;
- case Opt_diropq_w:
- AuLabel(diropq_w);
- break;
- case Opt_warn_perm:
- AuLabel(warn_perm);
- break;
- case Opt_nowarn_perm:
- AuLabel(nowarn_perm);
- break;
- case Opt_verbose:
- AuLabel(verbose);
- break;
- case Opt_noverbose:
- AuLabel(noverbose);
- break;
- case Opt_sum:
- AuLabel(sum);
- break;
- case Opt_nosum:
- AuLabel(nosum);
- break;
- case Opt_wsum:
- AuLabel(wsum);
- break;
- case Opt_wbr_create:
- u.create = &opt->wbr_create;
- AuDbg("create %d, %s\n", u.create->wbr_create,
- au_optstr_wbr_create(u.create->wbr_create));
- switch (u.create->wbr_create) {
- case AuWbrCreate_MFSV:
- case AuWbrCreate_PMFSV:
- AuDbg("%d sec\n", u.create->mfs_second);
- break;
- case AuWbrCreate_MFSRR:
- AuDbg("%llu watermark\n",
- u.create->mfsrr_watermark);
- break;
- case AuWbrCreate_MFSRRV:
- case AuWbrCreate_PMFSRRV:
- AuDbg("%llu watermark, %d sec\n",
- u.create->mfsrr_watermark,
- u.create->mfs_second);
- break;
- }
- break;
- case Opt_wbr_copyup:
- AuDbg("copyup %d, %s\n", opt->wbr_copyup,
- au_optstr_wbr_copyup(opt->wbr_copyup));
- break;
- case Opt_fhsm_sec:
- AuDbg("fhsm_sec %u\n", opt->fhsm_second);
- break;
- case Opt_acl:
- AuLabel(acl);
- break;
- case Opt_noacl:
- AuLabel(noacl);
- 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:
- case Opt_append:
- case Opt_prepend:
- path_put(&opt->add.path);
- break;
- case Opt_del:
- case Opt_idel:
- path_put(&opt->del.h_path);
- break;
- case Opt_mod:
- case Opt_imod:
- dput(opt->mod.h_root);
- break;
- case Opt_xino:
- fput(opt->xino.file);
- 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;
- if (au_test_fs_rr(add->path.dentry->d_sb))
- add->perm = AuBrPerm_RR;
- else if (!bindex && !(sb_flags & MS_RDONLY))
- add->perm = AuBrPerm_RW;
- }
- opt->type = Opt_add;
- goto out;
- }
- pr_err("lookup failed %s (%d)\n", add->pathname, err);
- err = -EINVAL;
-
-out:
- return err;
-}
-
-static int au_opts_parse_del(struct au_opt_del *del, substring_t args[])
-{
- int err;
-
- del->pathname = args[0].from;
- AuDbg("del path %s\n", del->pathname);
-
- err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path);
- if (unlikely(err))
- pr_err("lookup failed %s (%d)\n", del->pathname, err);
-
- return err;
-}
-
-#if 0 /* reserved for future use */
-static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex,
- struct au_opt_del *del, substring_t args[])
-{
- int err;
- struct dentry *root;
-
- err = -EINVAL;
- root = sb->s_root;
- aufs_read_lock(root, AuLock_FLUSH);
- if (bindex < 0 || au_sbend(sb) < bindex) {
- pr_err("out of bounds, %d\n", bindex);
- goto out;
- }
-
- err = 0;
- del->h_path.dentry = dget(au_h_dptr(root, bindex));
- del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex));
-
-out:
- aufs_read_unlock(root, !AuLock_IR);
- return err;
-}
-#endif
-
-static int noinline_for_stack
-au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[])
-{
- int err;
- struct path path;
- char *p;
-
- err = -EINVAL;
- mod->path = args[0].from;
- p = strchr(mod->path, '=');
- if (unlikely(!p)) {
- pr_err("no permssion %s\n", args[0].from);
- goto out;
- }
-
- *p++ = 0;
- err = vfsub_kern_path(mod->path, lkup_dirflags, &path);
- if (unlikely(err)) {
- pr_err("lookup failed %s (%d)\n", mod->path, err);
- goto out;
- }
-
- mod->perm = br_perm_val(p);
- AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p);
- mod->h_root = dget(path.dentry);
- path_put(&path);
-
-out:
- return err;
-}
-
-#if 0 /* reserved for future use */
-static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex,
- struct au_opt_mod *mod, substring_t args[])
-{
- int err;
- struct dentry *root;
-
- err = -EINVAL;
- root = sb->s_root;
- aufs_read_lock(root, AuLock_FLUSH);
- if (bindex < 0 || au_sbend(sb) < bindex) {
- pr_err("out of bounds, %d\n", bindex);
- goto out;
- }
-
- err = 0;
- mod->perm = br_perm_val(args[1].from);
- AuDbg("mod path %s, perm 0x%x, %s\n",
- mod->path, mod->perm, args[1].from);
- mod->h_root = dget(au_h_dptr(root, bindex));
-
-out:
- aufs_read_unlock(root, !AuLock_IR);
- return err;
-}
-#endif
-
-static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino,
- substring_t args[])
-{
- int err;
- struct file *file;
-
- file = au_xino_create(sb, args[0].from, /*silent*/0);
- err = PTR_ERR(file);
- if (IS_ERR(file))
- goto out;
-
- err = -EINVAL;
- if (unlikely(file->f_path.dentry->d_sb == sb)) {
- fput(file);
- pr_err("%s must be outside\n", args[0].from);
- goto out;
- }
-
- err = 0;
- xino->file = file;
- xino->path = args[0].from;
-
-out:
- return err;
-}
-
-static int noinline_for_stack
-au_opts_parse_xino_itrunc_path(struct super_block *sb,
- struct au_opt_xino_itrunc *xino_itrunc,
- substring_t args[])
-{
- int err;
- aufs_bindex_t bend, bindex;
- struct path path;
- struct dentry *root;
-
- err = vfsub_kern_path(args[0].from, lkup_dirflags, &path);
- if (unlikely(err)) {
- pr_err("lookup failed %s (%d)\n", args[0].from, err);
- goto out;
- }
-
- xino_itrunc->bindex = -1;
- root = sb->s_root;
- aufs_read_lock(root, AuLock_FLUSH);
- bend = au_sbend(sb);
- for (bindex = 0; bindex <= bend; bindex++) {
- if (au_h_dptr(root, bindex) == path.dentry) {
- xino_itrunc->bindex = bindex;
- break;
- }
- }
- aufs_read_unlock(root, !AuLock_IR);
- path_put(&path);
-
- if (unlikely(xino_itrunc->bindex < 0)) {
- pr_err("no such branch %s\n", args[0].from);
- 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 */
- union {
- struct au_opt_xino_itrunc *xino_itrunc;
- struct au_opt_wbr_create *create;
- } u;
- 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_append:
- err = opt_add(opt, a->args[0].from, opts->sb_flags,
- /*dummy bindex*/1);
- if (!err)
- opt->type = token;
- break;
- case Opt_prepend:
- err = opt_add(opt, a->args[0].from, opts->sb_flags,
- /*bindex*/0);
- if (!err)
- opt->type = token;
- break;
- case Opt_del:
- err = au_opts_parse_del(&opt->del, a->args);
- if (!err)
- opt->type = token;
- break;
-#if 0 /* reserved for future use */
- case Opt_idel:
- del->pathname = "(indexed)";
- if (unlikely(match_int(&args[0], &n))) {
- pr_err("bad integer in %s\n", opt_str);
- break;
- }
- err = au_opts_parse_idel(sb, n, &opt->del, a->args);
- if (!err)
- opt->type = token;
- break;
-#endif
- case Opt_mod:
- err = au_opts_parse_mod(&opt->mod, a->args);
- if (!err)
- opt->type = token;
- break;
-#ifdef IMOD /* reserved for future use */
- case Opt_imod:
- u.mod->path = "(indexed)";
- if (unlikely(match_int(&a->args[0], &n))) {
- pr_err("bad integer in %s\n", opt_str);
- break;
- }
- err = au_opts_parse_imod(sb, n, &opt->mod, a->args);
- if (!err)
- opt->type = token;
- break;
-#endif
- case Opt_xino:
- err = au_opts_parse_xino(sb, &opt->xino, a->args);
- if (!err)
- opt->type = token;
- break;
-
- case Opt_trunc_xino_path:
- err = au_opts_parse_xino_itrunc_path
- (sb, &opt->xino_itrunc, a->args);
- if (!err)
- opt->type = token;
- break;
-
- case Opt_itrunc_xino:
- u.xino_itrunc = &opt->xino_itrunc;
- if (unlikely(match_int(&a->args[0], &n))) {
- pr_err("bad integer in %s\n", opt_str);
- break;
- }
- u.xino_itrunc->bindex = n;
- aufs_read_lock(root, AuLock_FLUSH);
- if (n < 0 || au_sbend(sb) < n) {
- pr_err("out of bounds, %d\n", n);
- aufs_read_unlock(root, !AuLock_IR);
- break;
- }
- aufs_read_unlock(root, !AuLock_IR);
- err = 0;
- opt->type = token;
- break;
-
- case Opt_dirwh:
- if (unlikely(match_int(&a->args[0], &opt->dirwh)))
- break;
- err = 0;
- opt->type = token;
- break;
-
- case Opt_rdcache:
- if (unlikely(match_int(&a->args[0], &n))) {
- pr_err("bad integer in %s\n", opt_str);
- break;
- }
- if (unlikely(n > AUFS_RDCACHE_MAX)) {
- pr_err("rdcache must be smaller than %d\n",
- AUFS_RDCACHE_MAX);
- break;
- }
- opt->rdcache = n;
- err = 0;
- opt->type = token;
- break;
- case Opt_rdblk:
- if (unlikely(match_int(&a->args[0], &n)
- || n < 0
- || n > KMALLOC_MAX_SIZE)) {
- pr_err("bad integer in %s\n", opt_str);
- break;
- }
- if (unlikely(n && n < NAME_MAX)) {
- pr_err("rdblk must be larger than %d\n",
- NAME_MAX);
- break;
- }
- opt->rdblk = n;
- err = 0;
- opt->type = token;
- break;
- case Opt_rdhash:
- if (unlikely(match_int(&a->args[0], &n)
- || n < 0
- || n * sizeof(struct hlist_head)
- > KMALLOC_MAX_SIZE)) {
- pr_err("bad integer in %s\n", opt_str);
- break;
- }
- opt->rdhash = n;
- err = 0;
- opt->type = token;
- break;
-
- case Opt_trunc_xino:
- case Opt_notrunc_xino:
- case Opt_noxino:
- case Opt_trunc_xib:
- case Opt_notrunc_xib:
- case Opt_shwh:
- case Opt_noshwh:
- case Opt_dirperm1:
- case Opt_nodirperm1:
- case Opt_plink:
- case Opt_noplink:
- case Opt_list_plink:
- case Opt_dio:
- case Opt_nodio:
- case Opt_diropq_a:
- case Opt_diropq_w:
- case Opt_warn_perm:
- case Opt_nowarn_perm:
- case Opt_verbose:
- case Opt_noverbose:
- case Opt_sum:
- case Opt_nosum:
- case Opt_wsum:
- case Opt_rdblk_def:
- case Opt_rdhash_def:
- case Opt_acl:
- case Opt_noacl:
- err = 0;
- opt->type = token;
- break;
-
- case Opt_udba:
- opt->udba = udba_val(a->args[0].from);
- if (opt->udba >= 0) {
- err = 0;
- opt->type = token;
- } else
- pr_err("wrong value, %s\n", opt_str);
- break;
-
- case Opt_wbr_create:
- u.create = &opt->wbr_create;
- u.create->wbr_create
- = au_wbr_create_val(a->args[0].from, u.create);
- if (u.create->wbr_create >= 0) {
- err = 0;
- opt->type = token;
- } else
- pr_err("wrong value, %s\n", opt_str);
- break;
- case Opt_wbr_copyup:
- opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from);
- if (opt->wbr_copyup >= 0) {
- err = 0;
- opt->type = token;
- } else
- pr_err("wrong value, %s\n", opt_str);
- break;
-
- case Opt_fhsm_sec:
- if (unlikely(match_int(&a->args[0], &n)
- || n < 0)) {
- pr_err("bad integer in %s\n", opt_str);
- break;
- }
- if (sysaufs_brs) {
- opt->fhsm_second = n;
- opt->type = token;
- } else
- pr_warn("ignored %s\n", opt_str);
- err = 0;
- 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;
- }
- }
-
- kfree(a);
- dump_opts(opts);
- if (unlikely(err))
- au_opts_free(opts);
-
-out:
- return err;
-}
-
-static int au_opt_wbr_create(struct super_block *sb,
- struct au_opt_wbr_create *create)
-{
- int err;
- struct au_sbinfo *sbinfo;
-
- SiMustWriteLock(sb);
-
- err = 1; /* handled */
- sbinfo = au_sbi(sb);
- if (sbinfo->si_wbr_create_ops->fin) {
- err = sbinfo->si_wbr_create_ops->fin(sb);
- if (!err)
- err = 1;
- }
-
- sbinfo->si_wbr_create = create->wbr_create;
- sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create;
- switch (create->wbr_create) {
- case AuWbrCreate_MFSRRV:
- case AuWbrCreate_MFSRR:
- case AuWbrCreate_PMFSRR:
- case AuWbrCreate_PMFSRRV:
- sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark;
- /*FALLTHROUGH*/
- case AuWbrCreate_MFS:
- case AuWbrCreate_MFSV:
- case AuWbrCreate_PMFS:
- case AuWbrCreate_PMFSV:
- sbinfo->si_wbr_mfs.mfs_expire
- = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC);
- break;
- }
-
- if (sbinfo->si_wbr_create_ops->init)
- sbinfo->si_wbr_create_ops->init(sb); /* ignore */
-
- return err;
-}
-
-/*
- * returns,
- * plus: processed without an error
- * zero: unprocessed
- */
-static int au_opt_simple(struct super_block *sb, struct au_opt *opt,
- struct au_opts *opts)
-{
- int err;
- struct au_sbinfo *sbinfo;
-
- SiMustWriteLock(sb);
-
- err = 1; /* handled */
- sbinfo = au_sbi(sb);
- switch (opt->type) {
- case Opt_udba:
- sbinfo->si_mntflags &= ~AuOptMask_UDBA;
- sbinfo->si_mntflags |= opt->udba;
- opts->given_udba |= opt->udba;
- break;
-
- case Opt_plink:
- au_opt_set(sbinfo->si_mntflags, PLINK);
- break;
- case Opt_noplink:
- if (au_opt_test(sbinfo->si_mntflags, PLINK))
- au_plink_put(sb, /*verbose*/1);
- au_opt_clr(sbinfo->si_mntflags, PLINK);
- break;
- case Opt_list_plink:
- if (au_opt_test(sbinfo->si_mntflags, PLINK))
- au_plink_list(sb);
- break;
-
- case Opt_dio:
- au_opt_set(sbinfo->si_mntflags, DIO);
- au_fset_opts(opts->flags, REFRESH_DYAOP);
- break;
- case Opt_nodio:
- au_opt_clr(sbinfo->si_mntflags, DIO);
- au_fset_opts(opts->flags, REFRESH_DYAOP);
- break;
-
- case Opt_fhsm_sec:
- au_fhsm_set(sbinfo, opt->fhsm_second);
- break;
-
- case Opt_diropq_a:
- au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ);
- break;
- case Opt_diropq_w:
- au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ);
- break;
-
- case Opt_warn_perm:
- au_opt_set(sbinfo->si_mntflags, WARN_PERM);
- break;
- case Opt_nowarn_perm:
- au_opt_clr(sbinfo->si_mntflags, WARN_PERM);
- break;
-
- case Opt_verbose:
- au_opt_set(sbinfo->si_mntflags, VERBOSE);
- break;
- case Opt_noverbose:
- au_opt_clr(sbinfo->si_mntflags, VERBOSE);
- break;
-
- case Opt_sum:
- au_opt_set(sbinfo->si_mntflags, SUM);
- break;
- case Opt_wsum:
- au_opt_clr(sbinfo->si_mntflags, SUM);
- au_opt_set(sbinfo->si_mntflags, SUM_W);
- case Opt_nosum:
- au_opt_clr(sbinfo->si_mntflags, SUM);
- au_opt_clr(sbinfo->si_mntflags, SUM_W);
- break;
-
- case Opt_wbr_create:
- err = au_opt_wbr_create(sb, &opt->wbr_create);
- break;
- case Opt_wbr_copyup:
- sbinfo->si_wbr_copyup = opt->wbr_copyup;
- sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup;
- break;
-
- case Opt_dirwh:
- sbinfo->si_dirwh = opt->dirwh;
- break;
-
- case Opt_rdcache:
- sbinfo->si_rdcache
- = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC);
- break;
- case Opt_rdblk:
- sbinfo->si_rdblk = opt->rdblk;
- break;
- case Opt_rdblk_def:
- sbinfo->si_rdblk = AUFS_RDBLK_DEF;
- break;
- case Opt_rdhash:
- sbinfo->si_rdhash = opt->rdhash;
- break;
- case Opt_rdhash_def:
- sbinfo->si_rdhash = AUFS_RDHASH_DEF;
- break;
-
- case Opt_shwh:
- au_opt_set(sbinfo->si_mntflags, SHWH);
- break;
- case Opt_noshwh:
- au_opt_clr(sbinfo->si_mntflags, SHWH);
- break;
-
- case Opt_dirperm1:
- au_opt_set(sbinfo->si_mntflags, DIRPERM1);
- break;
- case Opt_nodirperm1:
- au_opt_clr(sbinfo->si_mntflags, DIRPERM1);
- break;
-
- case Opt_trunc_xino:
- au_opt_set(sbinfo->si_mntflags, TRUNC_XINO);
- break;
- case Opt_notrunc_xino:
- au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO);
- break;
-
- case Opt_trunc_xino_path:
- case Opt_itrunc_xino:
- err = au_xino_trunc(sb, opt->xino_itrunc.bindex);
- if (!err)
- err = 1;
- break;
-
- case Opt_trunc_xib:
- au_fset_opts(opts->flags, TRUNC_XIB);
- break;
- case Opt_notrunc_xib:
- au_fclr_opts(opts->flags, TRUNC_XIB);
- break;
-
- case Opt_acl:
- sb->s_flags |= MS_POSIXACL;
- break;
- case Opt_noacl:
- sb->s_flags &= ~MS_POSIXACL;
- break;
-
- default:
- err = 0;
- break;
- }
-
- 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, do_refresh;
-
- err = 0;
- switch (opt->type) {
- case Opt_append:
- opt->add.bindex = au_sbend(sb) + 1;
- if (opt->add.bindex < 0)
- opt->add.bindex = 0;
- goto add;
- case Opt_prepend:
- opt->add.bindex = 0;
- add: /* indented label */
- case Opt_add:
- err = au_br_add(sb, &opt->add,
- au_ftest_opts(opts->flags, REMOUNT));
- if (!err) {
- err = 1;
- au_fset_opts(opts->flags, REFRESH);
- }
- break;
-
- case Opt_del:
- case Opt_idel:
- err = au_br_del(sb, &opt->del,
- au_ftest_opts(opts->flags, REMOUNT));
- if (!err) {
- err = 1;
- au_fset_opts(opts->flags, TRUNC_XIB);
- au_fset_opts(opts->flags, REFRESH);
- }
- break;
-
- case Opt_mod:
- case Opt_imod:
- err = au_br_mod(sb, &opt->mod,
- au_ftest_opts(opts->flags, REMOUNT),
- &do_refresh);
- if (!err) {
- err = 1;
- if (do_refresh)
- au_fset_opts(opts->flags, REFRESH);
- }
- break;
- }
-
- return err;
-}
-
-static int au_opt_xino(struct super_block *sb, struct au_opt *opt,
- struct au_opt_xino **opt_xino,
- struct au_opts *opts)
-{
- int err;
- aufs_bindex_t bend, bindex;
- struct dentry *root, *parent, *h_root;
-
- err = 0;
- switch (opt->type) {
- case Opt_xino:
- err = au_xino_set(sb, &opt->xino,
- !!au_ftest_opts(opts->flags, REMOUNT));
- if (unlikely(err))
- break;
-
- *opt_xino = &opt->xino;
- au_xino_brid_set(sb, -1);
-
- /* safe d_parent access */
- parent = opt->xino.file->f_path.dentry->d_parent;
- root = sb->s_root;
- bend = au_sbend(sb);
- for (bindex = 0; bindex <= bend; bindex++) {
- h_root = au_h_dptr(root, bindex);
- if (h_root == parent) {
- au_xino_brid_set(sb, au_sbr_id(sb, bindex));
- break;
- }
- }
- break;
-
- case Opt_noxino:
- au_xino_clr(sb);
- au_xino_brid_set(sb, -1);
- *opt_xino = (void *)-1;
- break;
- }
-
- return err;
-}
-
-int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
- unsigned int pending)
-{
- int err, fhsm;
- aufs_bindex_t bindex, bend;
- unsigned char do_plink, skip, do_free;
- struct au_branch *br;
- struct au_wbr *wbr;
- struct dentry *root;
- struct inode *dir, *h_dir;
- struct au_sbinfo *sbinfo;
- struct au_hinode *hdir;
-
- SiMustAnyLock(sb);
-
- sbinfo = au_sbi(sb);
- AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA));
-
- if (!(sb_flags & MS_RDONLY)) {
- if (unlikely(!au_br_writable(au_sbr_perm(sb, 0))))
- pr_warn("first branch should be rw\n");
- if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH)))
- pr_warn("shwh should be used with ro\n");
- }
-
- if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY)
- && !au_opt_test(sbinfo->si_mntflags, XINO))
- pr_warn("udba=*notify requires xino\n");
-
- if (au_opt_test(sbinfo->si_mntflags, DIRPERM1))
- pr_warn("dirperm1 breaks the protection"
- " by the permission bits on the lower branch\n");
-
- err = 0;
- fhsm = 0;
- root = sb->s_root;
- dir = d_inode(root);
- do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK);
- bend = au_sbend(sb);
- for (bindex = 0; !err && bindex <= bend; bindex++) {
- skip = 0;
- h_dir = au_h_iptr(dir, bindex);
- br = au_sbr(sb, bindex);
-
- if ((br->br_perm & AuBrAttr_ICEX)
- && !h_dir->i_op->listxattr)
- br->br_perm &= ~AuBrAttr_ICEX;
-#if 0
- if ((br->br_perm & AuBrAttr_ICEX_SEC)
- && (au_br_sb(br)->s_flags & MS_NOSEC))
- br->br_perm &= ~AuBrAttr_ICEX_SEC;
-#endif
-
- do_free = 0;
- wbr = br->br_wbr;
- if (wbr)
- wbr_wh_read_lock(wbr);
-
- if (!au_br_writable(br->br_perm)) {
- do_free = !!wbr;
- skip = (!wbr
- || (!wbr->wbr_whbase
- && !wbr->wbr_plink
- && !wbr->wbr_orph));
- } else if (!au_br_wh_linkable(br->br_perm)) {
- /* skip = (!br->br_whbase && !br->br_orph); */
- skip = (!wbr || !wbr->wbr_whbase);
- if (skip && wbr) {
- if (do_plink)
- skip = !!wbr->wbr_plink;
- else
- skip = !wbr->wbr_plink;
- }
- } else {
- /* skip = (br->br_whbase && br->br_ohph); */
- skip = (wbr && wbr->wbr_whbase);
- if (skip) {
- if (do_plink)
- skip = !!wbr->wbr_plink;
- else
- skip = !wbr->wbr_plink;
- }
- }
- if (wbr)
- wbr_wh_read_unlock(wbr);
-
- if (au_br_fhsm(br->br_perm)) {
- fhsm++;
- AuDebugOn(!br->br_fhsm);
- }
-
- if (skip)
- continue;
-
- hdir = au_hi(dir, bindex);
- au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
- if (wbr)
- wbr_wh_write_lock(wbr);
- err = au_wh_init(br, sb);
- if (wbr)
- wbr_wh_write_unlock(wbr);
- au_hn_imtx_unlock(hdir);
-
- if (!err && do_free) {
- kfree(wbr);
- br->br_wbr = NULL;
- }
- }
-
- if (fhsm >= 2) {
- au_fset_si(sbinfo, FHSM);
- for (bindex = bend; bindex >= 0; bindex--) {
- br = au_sbr(sb, bindex);
- if (au_br_fhsm(br->br_perm)) {
- au_fhsm_set_bottom(sb, bindex);
- break;
- }
- }
- } else {
- au_fclr_si(sbinfo, FHSM);
- au_fhsm_set_bottom(sb, -1);
- }
-
- return err;
-}
-
-int au_opts_mount(struct super_block *sb, struct au_opts *opts)
-{
- int err;
- unsigned int tmp;
- aufs_bindex_t bindex, bend;
- struct au_opt *opt;
- struct au_opt_xino *opt_xino, xino;
- struct au_sbinfo *sbinfo;
- struct au_branch *br;
- struct inode *dir;
-
- SiMustWriteLock(sb);
-
- err = 0;
- opt_xino = NULL;
- opt = opts->opt;
- while (err >= 0 && opt->type != Opt_tail)
- err = au_opt_simple(sb, opt++, opts);
- if (err > 0)
- err = 0;
- else if (unlikely(err < 0))
- goto out;
-
- /* disable xino and udba temporary */
- sbinfo = au_sbi(sb);
- tmp = sbinfo->si_mntflags;
- au_opt_clr(sbinfo->si_mntflags, XINO);
- au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL);
-
- 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;
-
- bend = au_sbend(sb);
- if (unlikely(bend < 0)) {
- err = -EINVAL;
- pr_err("no branches\n");
- goto out;
- }
-
- if (au_opt_test(tmp, XINO))
- au_opt_set(sbinfo->si_mntflags, XINO);
- opt = opts->opt;
- while (!err && opt->type != Opt_tail)
- err = au_opt_xino(sb, opt++, &opt_xino, opts);
- if (unlikely(err))
- goto out;
-
- err = au_opts_verify(sb, sb->s_flags, tmp);
- if (unlikely(err))
- goto out;
-
- /* restore xino */
- if (au_opt_test(tmp, XINO) && !opt_xino) {
- xino.file = au_xino_def(sb);
- err = PTR_ERR(xino.file);
- if (IS_ERR(xino.file))
- goto out;
-
- err = au_xino_set(sb, &xino, /*remount*/0);
- fput(xino.file);
- if (unlikely(err))
- goto out;
- }
-
- /* restore udba */
- tmp &= AuOptMask_UDBA;
- sbinfo->si_mntflags &= ~AuOptMask_UDBA;
- sbinfo->si_mntflags |= tmp;
- bend = au_sbend(sb);
- for (bindex = 0; bindex <= bend; bindex++) {
- br = au_sbr(sb, bindex);
- err = au_hnotify_reset_br(tmp, br, br->br_perm);
- if (unlikely(err))
- AuIOErr("hnotify failed on br %d, %d, ignored\n",
- bindex, err);
- /* go on even if err */
- }
- if (au_opt_test(tmp, UDBA_HNOTIFY)) {
- dir = d_inode(sb->s_root);
- au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO);
- }
-
-out:
- return err;
-}
-
-int au_opts_remount(struct super_block *sb, struct au_opts *opts)
-{
- int err, rerr;
- struct inode *dir;
- struct au_opt_xino *opt_xino;
- struct au_opt *opt;
- struct au_sbinfo *sbinfo;
-
- SiMustWriteLock(sb);
-
- dir = d_inode(sb->s_root);
- sbinfo = au_sbi(sb);
- err = 0;
- opt_xino = NULL;
- opt = opts->opt;
- while (err >= 0 && opt->type != Opt_tail) {
- err = au_opt_simple(sb, opt, opts);
- if (!err)
- err = au_opt_br(sb, opt, opts);
- if (!err)
- err = au_opt_xino(sb, opt, &opt_xino, opts);
- opt++;
- }
- if (err > 0)
- err = 0;
- AuTraceErr(err);
- /* go on even err */
-
- rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0);
- if (unlikely(rerr && !err))
- err = rerr;
-
- if (au_ftest_opts(opts->flags, TRUNC_XIB)) {
- rerr = au_xib_trunc(sb);
- if (unlikely(rerr && !err))
- err = rerr;
- }
-
- /* will be handled by the caller */
- if (!au_ftest_opts(opts->flags, REFRESH)
- && (opts->given_udba || au_opt_test(sbinfo->si_mntflags, XINO)))
- au_fset_opts(opts->flags, REFRESH);
-
- AuDbg("status 0x%x\n", opts->flags);
- return err;
-}
-
-/* ---------------------------------------------------------------------- */
-
-unsigned int au_opt_udba(struct super_block *sb)
-{
- return au_mntflags(sb) & AuOptMask_UDBA;
-}