Esempio n. 1
0
static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex)
{
	for (; bindex >= 0; bindex--)
		if (!au_br_rdonly(au_sbr(sb, bindex)))
			return bindex;
	return -EROFS;
}
Esempio n. 2
0
/* 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;
}
Esempio n. 3
0
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_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;
}
Esempio n. 5
0
/* most free space */
static void au_mfs(struct dentry *dentry)
{
	struct super_block *sb;
	struct au_branch *br;
	struct au_wbr_mfs *mfs;
	aufs_bindex_t bindex, bend;
	int err;
	unsigned long long b, bavail;
	struct path h_path;
	/* reduce the stack usage */
	struct kstatfs *st;

	st = kmalloc(sizeof(*st), GFP_NOFS);
	if (unlikely(!st)) {
		AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM);
		return;
	}

	bavail = 0;
	sb = dentry->d_sb;
	mfs = &au_sbi(sb)->si_wbr_mfs;
	MtxMustLock(&mfs->mfs_lock);
	mfs->mfs_bindex = -EROFS;
	mfs->mfsrr_bytes = 0;
	bend = au_sbend(sb);
	for (bindex = 0; bindex <= bend; bindex++) {
		br = au_sbr(sb, bindex);
		if (au_br_rdonly(br))
			continue;

		/* sb->s_root for NFS is unreliable */
		h_path.mnt = br->br_mnt;
		h_path.dentry = h_path.mnt->mnt_root;
		err = vfs_statfs(&h_path, st);
		if (unlikely(err)) {
			AuWarn1("failed statfs, b%d, %d\n", bindex, err);
			continue;
		}

		/* when the available size is equal, select the lower one */
		BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail)
			     || sizeof(b) < sizeof(st->f_bsize));
		b = st->f_bavail * st->f_bsize;
		br->br_wbr->wbr_bytes = b;
		if (b >= bavail) {
			bavail = b;
			mfs->mfs_bindex = bindex;
			mfs->mfs_jiffy = jiffies;
		}
	}

	mfs->mfsrr_bytes = bavail;
	AuDbg("b%d\n", mfs->mfs_bindex);
	kfree(st);
}
Esempio n. 6
0
/* 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;
}
/* mainly for link(2) and rename(2) */
int au_wbr(struct dentry *dentry, aufs_bindex_t btgt)
{
	aufs_bindex_t bdiropq, bwh;
	struct dentry *parent;
	struct au_branch *br;

	parent = dentry->d_parent;
	IMustLock(parent->d_inode); /* dir is locked */

	bdiropq = au_dbdiropq(parent);
	bwh = au_dbwh(dentry);
	br = au_sbr(dentry->d_sb, btgt);
	if (au_br_rdonly(br)
	    || (0 <= bdiropq && bdiropq < btgt)
	    || (0 <= bwh && bwh < btgt))
		btgt = -1;

	AuDbg("btgt %d\n", btgt);
	return btgt;
}
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;
}
Esempio n. 9
0
static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex,
			struct aufs_stfs *rstfs, int do_lock, int do_notify)
{
	int err;
	struct au_branch *br;
	struct au_br_fhsm *bf;

	br = au_sbr(sb, bindex);
	AuDebugOn(au_br_rdonly(br));
	bf = br->br_fhsm;
	AuDebugOn(!bf);

	if (do_lock)
		mutex_lock(&bf->bf_lock);
	else
		MtxMustLock(&bf->bf_lock);

	/* sb->s_root for NFS is unreliable */
	err = au_br_stfs(br, &bf->bf_stfs);
	if (unlikely(err)) {
		AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err);
		goto out;
	}

	bf->bf_jiffy = jiffies;
	bf->bf_readable = 1;
	if (do_notify)
		au_fhsm_notify(sb, /*val*/1);
	if (rstfs)
		*rstfs = bf->bf_stfs;

out:
	if (do_lock)
		mutex_unlock(&bf->bf_lock);
	au_fhsm_notify(sb, /*val*/1);

	return err;
}
Esempio n. 10
0
int au_test_ro(struct super_block *sb, aufs_bindex_t bindex,
	       struct inode *inode)
{
	int err;

	err = au_br_rdonly(au_sbr(sb, bindex));

	/* pseudo-link after flushed may happen out of bounds */
	if (!err
	    && inode
	    && au_ibstart(inode) <= bindex
	    && bindex <= au_ibend(inode)) {
		/*
		 * permission check is unnecessary since vfsub routine
		 * will be called later
		 */
		struct inode *hi = au_h_iptr(inode, bindex);
		if (hi)
			err = IS_IMMUTABLE(hi) ? -EROFS : 0;
	}

	return err;
}
Esempio n. 11
0
static int aufs_permission(struct inode *inode, int mask)
{
	int err;
	aufs_bindex_t bindex, bend;
	const unsigned char isdir = !!S_ISDIR(inode->i_mode),
		write_mask = !!(mask & (MAY_WRITE | MAY_APPEND));
	struct inode *h_inode;
	struct super_block *sb;
	struct au_branch *br;

	/* todo: support rcu-walk? */
	if (mask & MAY_NOT_BLOCK)
		return -ECHILD;

	sb = inode->i_sb;
	si_read_lock(sb, AuLock_FLUSH);
	ii_read_lock_child(inode);
#if 0
	err = au_iigen_test(inode, au_sigen(sb));
	if (unlikely(err))
		goto out;
#endif

	if (!isdir || write_mask) {
		err = au_busy_or_stale();
		h_inode = au_h_iptr(inode, au_ibstart(inode));
		if (unlikely(!h_inode
			     || (h_inode->i_mode & S_IFMT)
			     != (inode->i_mode & S_IFMT)))
			goto out;

		err = 0;
		bindex = au_ibstart(inode);
		br = au_sbr(sb, bindex);
		err = h_permission(h_inode, mask, br->br_mnt, br->br_perm);
		if (write_mask
		    && !err
		    && !special_file(h_inode->i_mode)) {
			/* test whether the upper writable branch exists */
			err = -EROFS;
			for (; bindex >= 0; bindex--)
				if (!au_br_rdonly(au_sbr(sb, bindex))) {
					err = 0;
					break;
				}
		}
		goto out;
	}

	/* non-write to dir */
	err = 0;
	bend = au_ibend(inode);
	for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) {
		h_inode = au_h_iptr(inode, bindex);
		if (h_inode) {
			err = au_busy_or_stale();
			if (unlikely(!S_ISDIR(h_inode->i_mode)))
				break;

			br = au_sbr(sb, bindex);
			err = h_permission(h_inode, mask, br->br_mnt,
					   br->br_perm);
		}
	}

out:
	ii_read_unlock(inode);
	si_read_unlock(sb);
	return err;
}
Esempio n. 12
0
static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a)
{
    int err;
    struct au_branch *br;

    err = -EISDIR;
    if (unlikely(S_ISDIR(a->inode->i_mode)))
        goto out;

    err = -EINVAL;
    if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER))
        a->mvd_bsrc = au_ibstart(a->inode);
    else {
        a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid);
        if (unlikely(a->mvd_bsrc < 0
                     || (a->mvd_bsrc < au_dbstart(a->dentry)
                         || au_dbend(a->dentry) < a->mvd_bsrc
                         || !au_h_dptr(a->dentry, a->mvd_bsrc))
                     || (a->mvd_bsrc < au_ibstart(a->inode)
                         || au_ibend(a->inode) < a->mvd_bsrc
                         || !au_h_iptr(a->inode, a->mvd_bsrc)))) {
            a->mvd_errno = EAU_MVDOWN_NOUPPER;
            AU_MVD_PR(dmsg, "no upper\n");
            goto out;
        }
    }
    if (unlikely(a->mvd_bsrc == au_sbend(a->sb))) {
        a->mvd_errno = EAU_MVDOWN_BOTTOM;
        AU_MVD_PR(dmsg, "on the bottom\n");
        goto out;
    }
    a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc);
    br = au_sbr(a->sb, a->mvd_bsrc);
    err = au_br_rdonly(br);
    if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) {
        if (unlikely(err))
            goto out;
    } else if (!(vfsub_native_ro(a->mvd_h_src_inode)
                 || IS_APPEND(a->mvd_h_src_inode))) {
        if (err)
            a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R;
        /* go on */
    } else
        goto out;

    err = -EINVAL;
    if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) {
        a->mvd_bdst = find_lower_writable(a);
        if (unlikely(a->mvd_bdst < 0)) {
            a->mvd_errno = EAU_MVDOWN_BOTTOM;
            AU_MVD_PR(dmsg, "no writable lower branch\n");
            goto out;
        }
    } else {
        a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid);
        if (unlikely(a->mvd_bdst < 0
                     || au_sbend(a->sb) < a->mvd_bdst)) {
            a->mvd_errno = EAU_MVDOWN_NOLOWERBR;
            AU_MVD_PR(dmsg, "no lower brid\n");
            goto out;
        }
    }

    err = au_mvd_args_busy(dmsg, a);
    if (!err)
        err = au_mvd_args_parent(dmsg, a);
    if (!err)
        err = au_mvd_args_intermediate(dmsg, a);
    if (!err)
        err = au_mvd_args_exist(dmsg, a);
    if (!err)
        AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst);

out:
    AuTraceErr(err);
    return err;
}