static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, struct au_branch *br) { aufs_bindex_t bend; struct au_sbinfo *sbinfo; struct dentry *root, *h_root; struct inode *inode, *h_inode; struct au_hinode *hinode; SiMustWriteLock(sb); root = sb->s_root; inode = root->d_inode; sbinfo = au_sbi(sb); bend = sbinfo->si_bend; h_root = au_h_dptr(root, bindex); hinode = au_hi(inode, bindex); h_inode = au_igrab(hinode->hi_inode); au_hiput(hinode); au_sbilist_lock(); au_br_do_del_brp(sbinfo, bindex, bend); au_br_do_del_hdp(au_di(root), bindex, bend); au_br_do_del_hip(au_ii(inode), bindex, bend); au_sbilist_unlock(); dput(h_root); iput(h_inode); au_br_do_free(br); }
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; }
int au_sigen_inc(struct super_block *sb) { int gen; SiMustWriteLock(sb); gen = ++stosi(sb)->si_generation; au_update_digen(sb->s_root); au_update_iigen(sb->s_root->d_inode); sb->s_root->d_inode->i_version++; return gen; }
unsigned int au_sigen_inc(struct super_block *sb) { unsigned int gen; SiMustWriteLock(sb); gen = ++au_sbi(sb)->si_generation; au_update_digen(sb->s_root); au_update_iigen(sb->s_root->d_inode, /*half*/0); sb->s_root->d_inode->i_version++; return gen; }
void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex) { struct au_sbinfo *sbinfo; struct au_fhsm *fhsm; SiMustWriteLock(sb); sbinfo = au_sbi(sb); fhsm = &sbinfo->si_fhsm; AuDebugOn(!fhsm); fhsm->fhsm_bottom = bindex; }
void au_xigen_clr(struct super_block *sb) { struct au_sbinfo *sbinfo; SiMustWriteLock(sb); sbinfo = au_sbi(sb); if (sbinfo->si_xigen) { fput(sbinfo->si_xigen); sbinfo->si_xigen = NULL; } }
aufs_bindex_t new_br_id(struct super_block *sb) { aufs_bindex_t br_id; TraceEnter(); SiMustWriteLock(sb); while (1) { br_id = ++stosi(sb)->si_last_br_id; if (br_id && find_brindex(sb, br_id) < 0) return br_id; } }
void au_export_init(struct super_block *sb) { struct au_sbinfo *sbinfo; __u32 u; AuTraceEnter(); SiMustWriteLock(sb); sb->s_export_op = &aufs_export_op; sbinfo = au_sbi(sb); sbinfo->si_xigen = NULL; get_random_bytes(&u, sizeof(u)); BUILD_BUG_ON(sizeof(u) != sizeof(int)); atomic_set(&sbinfo->si_xigen_next, u); //memset(&sbinfo->si_xinodir, 0, sizeof(struct path)); }
aufs_bindex_t au_new_br_id(struct super_block *sb) { aufs_bindex_t br_id; int i; struct au_sbinfo *sbinfo; SiMustWriteLock(sb); sbinfo = au_sbi(sb); for (i = 0; i <= AUFS_BRANCH_MAX; i++) { br_id = ++sbinfo->si_last_br_id; if (br_id && au_br_index(sb, br_id) < 0) return br_id; } return -1; }
int au_xigen_set(struct super_block *sb, struct file *base) { int err; struct au_sbinfo *sbinfo; struct file *file; SiMustWriteLock(sb); sbinfo = au_sbi(sb); file = au_xino_create2(base, sbinfo->si_xigen); err = PTR_ERR(file); if (IS_ERR(file)) goto out; err = 0; if (sbinfo->si_xigen) fput(sbinfo->si_xigen); sbinfo->si_xigen = file; 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; }
int au_xigen_set(struct super_block *sb, struct file *base) { int err; struct au_sbinfo *sbinfo; struct file *file; LKTRTrace("%.*s\n", AuDLNPair(base->f_dentry)); SiMustWriteLock(sb); sbinfo = au_sbi(sb); file = au_xino_create2(sb, base, sbinfo->si_xigen); err = PTR_ERR(file); if (IS_ERR(file)) goto out; err = 0; if (sbinfo->si_xigen) fput(sbinfo->si_xigen); sbinfo->si_xigen = file; out: AuTraceErr(err); 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; 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)) { struct inode *dir = sb->s_root->d_inode; au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); } out: 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_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_refrof: au_opt_set(sbinfo->si_mntflags, REFROF); break; case Opt_norefrof: au_opt_clr(sbinfo->si_mntflags, REFROF); 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_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; default: err = 0; break; } return err; }
int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) { int err, rerr, i; unsigned int mnt_flags; aufs_bindex_t bindex, bend, br_id; unsigned char do_wh, verbose; struct au_branch *br; struct au_wbr *wbr; err = 0; bindex = au_find_dbindex(sb->s_root, del->h_path.dentry); if (bindex < 0) { if (remount) goto out; /* success */ err = -ENOENT; pr_err("%s no such branch\n", del->pathname); goto out; } AuDbg("bindex b%d\n", bindex); err = -EBUSY; mnt_flags = au_mntflags(sb); verbose = !!au_opt_test(mnt_flags, VERBOSE); bend = au_sbend(sb); if (unlikely(!bend)) { AuVerbose(verbose, "no more branches left\n"); goto out; } br = au_sbr(sb, bindex); i = atomic_read(&br->br_count); if (unlikely(i)) { AuVerbose(verbose, "%d file(s) opened\n", i); goto out; } wbr = br->br_wbr; do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); if (do_wh) { /* instead of WbrWhMustWriteLock(wbr) */ SiMustWriteLock(sb); for (i = 0; i < AuBrWh_Last; i++) { dput(wbr->wbr_wh[i]); wbr->wbr_wh[i] = NULL; } } err = test_children_busy(sb->s_root, bindex, verbose); if (unlikely(err)) { if (do_wh) goto out_wh; goto out; } err = 0; br_id = br->br_id; if (!remount) au_br_do_del(sb, bindex, br); else { sysaufs_brs_del(sb, bindex); au_br_do_del(sb, bindex, br); sysaufs_brs_add(sb, bindex); } if (!bindex) { au_cpup_attr_all(sb->s_root->d_inode, /*force*/1); sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; } else au_sub_nlink(sb->s_root->d_inode, del->h_path.dentry->d_inode); if (au_opt_test(mnt_flags, PLINK)) au_plink_half_refresh(sb, br_id); if (au_xino_brid(sb) == br_id) au_xino_brid_set(sb, -1); goto out; /* success */ out_wh: /* revert */ rerr = au_br_init_wh(sb, br, br->br_perm, del->h_path.dentry); if (rerr) pr_warning("failed re-creating base whiteout, %s. (%d)\n", del->pathname, rerr); out: return err; }