int au_opts_remount(struct super_block *sb, struct au_opts *opts) { int err, rerr; unsigned char no_dreval; struct inode *dir; struct au_opt_xino *opt_xino; struct au_opt *opt; struct au_sbinfo *sbinfo; SiMustWriteLock(sb); err = 0; dir = d_inode(sb->s_root); sbinfo = au_sbi(sb); 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 */ no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); if (unlikely(rerr && !err)) err = rerr; if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) au_fset_opts(opts->flags, REFRESH_IDOP); 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_ftest_opts(opts->flags, REFRESH_IDOP) )) au_fset_opts(opts->flags, REFRESH); AuDbg("status 0x%x\n", opts->flags); 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: 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_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; }