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; }
void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force) { int err; struct au_sbinfo *sbinfo; struct au_fhsm *fhsm; struct au_branch *br; struct au_br_fhsm *bf; AuDbg("b%d, force %d\n", bindex, force); SiMustAnyLock(sb); sbinfo = au_sbi(sb); fhsm = &sbinfo->si_fhsm; if (!au_ftest_si(sbinfo, FHSM) || fhsm->fhsm_bottom == bindex) return; br = au_sbr(sb, bindex); bf = br->br_fhsm; AuDebugOn(!bf); mutex_lock(&bf->bf_lock); if (force || au_fhsm_pid(fhsm) || au_fhsm_test_jiffy(sbinfo, br)) err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0, /*do_notify*/1); mutex_unlock(&bf->bf_lock); }
/* * during a user process maintains the pseudo-links, * prohibit adding a new plink and branch manipulation. */ void au_plink_block_maintain(struct super_block *sb) { struct au_sbinfo *sbi = au_sbi(sb); SiMustAnyLock(sb); /* gave up wake_up_bit() */ wait_event(sbi->si_plink_wq, !au_ftest_si(sbi, MAINTAIN_PLINK)); }
void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo) { unsigned int u; if (!au_ftest_si(sbinfo, FHSM)) return; u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC; if (u != AUFS_FHSM_CACHE_DEF_SEC) seq_printf(seq, ",fhsm_sec=%u", u); }
int au_fhsm_fd(struct super_block *sb, int oflags) { int err, fd; struct au_sbinfo *sbinfo; struct au_fhsm *fhsm; err = -EPERM; if (unlikely(!capable(CAP_SYS_ADMIN))) goto out; err = -EINVAL; if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK))) goto out; err = 0; sbinfo = au_sbi(sb); fhsm = &sbinfo->si_fhsm; spin_lock(&fhsm->fhsm_spin); if (!fhsm->fhsm_pid) fhsm->fhsm_pid = current->pid; else err = -EBUSY; spin_unlock(&fhsm->fhsm_spin); if (unlikely(err)) goto out; oflags |= O_RDONLY; /* oflags |= FMODE_NONOTIFY; */ fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags); err = fd; if (unlikely(fd < 0)) goto out_pid; /* succeed reglardless 'fhsm' status */ kobject_get(&sbinfo->si_kobj); si_noflush_read_lock(sb); if (au_ftest_si(sbinfo, FHSM)) au_fhsm_wrote_all(sb, /*force*/0); si_read_unlock(sb); goto out; /* success */ out_pid: spin_lock(&fhsm->fhsm_spin); fhsm->fhsm_pid = 0; spin_unlock(&fhsm->fhsm_spin); out: AuTraceErr(err); return err; }
int au_reval_dpath(struct dentry *dentry, unsigned int sigen) { int err; struct dentry *d, *parent; struct inode *inode; if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS)) return simple_reval_dpath(dentry, sigen); /* slow loop, keep it simple and stupid */ /* cf: au_cpup_dirs() */ err = 0; parent = NULL; while (au_digen(dentry) != sigen || au_iigen(dentry->d_inode) != sigen) { d = dentry; while (1) { dput(parent); parent = dget_parent(d); if (au_digen(parent) == sigen && au_iigen(parent->d_inode) == sigen) break; d = parent; } inode = d->d_inode; if (d != dentry) di_write_lock_child(d); /* someone might update our dentry while we were sleeping */ if (au_digen(d) != sigen || au_iigen(d->d_inode) != sigen) { di_read_lock_parent(parent, AuLock_IR); /* returns a number of positive dentries */ err = au_refresh_hdentry(d, inode->i_mode & S_IFMT); if (err >= 0) err = au_refresh_hinode(inode, d); di_read_unlock(parent, AuLock_IR); } if (d != dentry) di_write_unlock(d); dput(parent); if (unlikely(err)) break; } return err; }
int au_reval_dpath(struct dentry *dentry, unsigned int sigen) { int err; struct dentry *d, *parent; struct inode *inode; if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) return simple_reval_dpath(dentry, sigen); /* slow loop, keep it simple and stupid */ /* cf: au_cpup_dirs() */ err = 0; parent = NULL; while (au_digen_test(dentry, sigen)) { d = dentry; while (1) { dput(parent); parent = dget_parent(d); if (!au_digen_test(parent, sigen)) break; d = parent; } inode = d->d_inode; if (d != dentry) di_write_lock_child2(d); /* someone might update our dentry while we were sleeping */ if (au_digen_test(d, sigen)) { /* * todo: consolidate with simple_reval_dpath(), * do_refresh() and au_reval_for_attr(). */ di_read_lock_parent(parent, AuLock_IR); err = au_refresh_dentry(d, parent); di_read_unlock(parent, AuLock_IR); } if (d != dentry) di_write_unlock(d); dput(parent); if (unlikely(err)) break; } return err; }