/* make sure the parent dir is fine */ static int au_mvd_args_parent(const unsigned char dmsg, struct au_mvd_args *a) { int err; aufs_bindex_t bindex; err = 0; if (unlikely(au_alive_dir(a->parent))) { err = -ENOENT; AU_MVD_PR(dmsg, "parent dir is dead\n"); goto out; } a->bopq = au_dbdiropq(a->parent); bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); AuDbg("b%d\n", bindex); if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { err = -EINVAL; a->mvd_errno = EAU_MVDOWN_OPAQUE; AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", a->bopq, a->mvd_bdst); } out: AuTraceErr(err); return err; }
static int au_wbr_create_mfs(struct dentry *dentry, int isdir __maybe_unused) { int err; struct super_block *sb; struct au_wbr_mfs *mfs; err = au_wbr_create_exp(dentry); if (err >= 0) goto out; sb = dentry->d_sb; mfs = &au_sbi(sb)->si_wbr_mfs; mutex_lock(&mfs->mfs_lock); if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) || mfs->mfs_bindex < 0 || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) au_mfs(dentry); mutex_unlock(&mfs->mfs_lock); err = mfs->mfs_bindex; if (err >= 0) err = au_wbr_nonopq(dentry, err); out: AuDbg("b%d\n", err); return err; }
/* an exception for the policy other than tdp */ static int au_wbr_create_exp(struct dentry *dentry) { int err; aufs_bindex_t bwh, bdiropq; struct dentry *parent; err = -1; bwh = au_dbwh(dentry); parent = dget_parent(dentry); bdiropq = au_dbdiropq(parent); if (bwh >= 0) { if (bdiropq >= 0) err = min(bdiropq, bwh); else err = bwh; AuDbg("%d\n", err); } else if (bdiropq >= 0) { err = bdiropq; AuDbg("%d\n", err); } dput(parent); if (err >= 0) err = au_wbr_nonopq(dentry, err); if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) err = -1; AuDbg("%d\n", err); return err; }
static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) { int err; struct dentry *parent; struct super_block *sb; struct au_wbr_mfs *mfs; err = au_wbr_create_exp(dentry); if (err >= 0) goto out; sb = dentry->d_sb; parent = NULL; if (au_ftest_wbr(flags, PARENT)) parent = dget_parent(dentry); mfs = &au_sbi(sb)->si_wbr_mfs; mutex_lock(&mfs->mfs_lock); if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) || mfs->mfs_bindex < 0 || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) au_mfs(dentry, parent); mutex_unlock(&mfs->mfs_lock); err = mfs->mfs_bindex; dput(parent); if (err >= 0) err = au_wbr_nonopq(dentry, err); out: AuDbg("b%d\n", err); return err; }
static int au_wbr_create_rr(struct dentry *dentry, int isdir) { int err, nbr; unsigned int u; aufs_bindex_t bindex, bend; struct super_block *sb; atomic_t *next; err = au_wbr_create_exp(dentry); if (err >= 0) goto out; sb = dentry->d_sb; next = &au_sbi(sb)->si_wbr_rr_next; bend = au_sbend(sb); nbr = bend + 1; for (bindex = 0; bindex <= bend; bindex++) { if (!isdir) { err = atomic_dec_return(next) + 1; /* modulo for 0 is meaningless */ if (unlikely(!err)) err = atomic_dec_return(next) + 1; } else err = atomic_read(next); AuDbg("%d\n", err); u = err; err = u % nbr; AuDbg("%d\n", err); if (!au_br_rdonly(au_sbr(sb, err))) break; err = -EROFS; } if (err >= 0) err = au_wbr_nonopq(dentry, err); out: AuDbg("%d\n", err); return err; }
/* top down parent */ static int au_wbr_create_tdp(struct dentry *dentry, unsigned int flags __maybe_unused) { int err; aufs_bindex_t bstart, bindex; struct super_block *sb; struct dentry *parent, *h_parent; sb = dentry->d_sb; bstart = au_dbstart(dentry); err = bstart; if (!au_br_rdonly(au_sbr(sb, bstart))) goto out; err = -EROFS; parent = dget_parent(dentry); for (bindex = au_dbstart(parent); bindex < bstart; bindex++) { h_parent = au_h_dptr(parent, bindex); if (!h_parent || !h_parent->d_inode) continue; if (!au_br_rdonly(au_sbr(sb, bindex))) { err = bindex; break; } } dput(parent); /* bottom up here */ if (unlikely(err < 0)) { err = au_wbr_bu(sb, bstart - 1); if (err >= 0) err = au_wbr_nonopq(dentry, err); } out: AuDbg("b%d\n", err); return err; }