diff options
Diffstat (limited to 'fs/aufs/opts.c')
-rw-r--r-- | fs/aufs/opts.c | 1835 |
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; -} |