Ejemplo n.º 1
0
static int find_lower_writable(struct au_mvd_args *a)
{
    struct super_block *sb;
    aufs_bindex_t bindex, bend;
    struct au_branch *br;

    sb = a->sb;
    bindex = a->mvd_bsrc;
    bend = au_sbend(sb);
    if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER)
        for (bindex++; bindex <= bend; bindex++) {
            br = au_sbr(sb, bindex);
            if (au_br_fhsm(br->br_perm)
                    && (!(au_br_sb(br)->s_flags & MS_RDONLY)))
                return bindex;
        }
    else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER))
        for (bindex++; bindex <= bend; bindex++) {
            br = au_sbr(sb, bindex);
            if (!au_br_rdonly(br))
                return bindex;
        }
    else
        for (bindex++; bindex <= bend; bindex++) {
            br = au_sbr(sb, bindex);
            if (!(au_br_sb(br)->s_flags & MS_RDONLY)) {
                if (au_br_rdonly(br))
                    a->mvdown.flags
                    |= AUFS_MVDOWN_ROLOWER_R;
                return bindex;
            }
        }

    return -1;
}
Ejemplo n.º 2
0
static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count,
			   loff_t *pos)
{
	ssize_t err;
	int readable;
	aufs_bindex_t nfhsm, bindex, bend;
	struct au_sbinfo *sbinfo;
	struct au_fhsm *fhsm;
	struct au_branch *br;
	struct super_block *sb;

	err = 0;
	sbinfo = file->private_data;
	fhsm = &sbinfo->si_fhsm;
need_data:
	spin_lock_irq(&fhsm->fhsm_wqh.lock);
	if (!atomic_read(&fhsm->fhsm_readable)) {
		if (vfsub_file_flags(file) & O_NONBLOCK)
			err = -EAGAIN;
		else
			err = wait_event_interruptible_locked_irq
				(fhsm->fhsm_wqh,
				 atomic_read(&fhsm->fhsm_readable));
	}
	spin_unlock_irq(&fhsm->fhsm_wqh.lock);
	if (unlikely(err))
		goto out;

	/* sb may already be dead */
	au_rw_read_lock(&sbinfo->si_rwsem);
	readable = atomic_read(&fhsm->fhsm_readable);
	if (readable > 0) {
		sb = sbinfo->si_sb;
		AuDebugOn(!sb);
		/* exclude the bottom branch */
		nfhsm = 0;
		bend = au_fhsm_bottom(sb);
		for (bindex = 0; bindex < bend; bindex++) {
			br = au_sbr(sb, bindex);
			if (au_br_fhsm(br->br_perm))
				nfhsm++;
		}
		err = -EMSGSIZE;
		if (nfhsm * sizeof(struct aufs_stbr) <= count) {
			atomic_set(&fhsm->fhsm_readable, 0);
			err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf,
					     count);
		}
	}
	au_rw_read_unlock(&sbinfo->si_rwsem);
	if (!readable)
		goto need_data;

out:
	return err;
}
Ejemplo n.º 3
0
void au_fhsm_wrote_all(struct super_block *sb, int force)
{
	aufs_bindex_t bindex, bend;
	struct au_branch *br;

	/* exclude the bottom */
	bend = au_fhsm_bottom(sb);
	for (bindex = 0; bindex < bend; bindex++) {
		br = au_sbr(sb, bindex);
		if (au_br_fhsm(br->br_perm))
			au_fhsm_wrote(sb, bindex, force);
	}
}
Ejemplo n.º 4
0
static ssize_t au_fhsm_do_read(struct super_block *sb,
			       struct aufs_stbr __user *stbr, size_t count)
{
	ssize_t err;
	int nstbr;
	aufs_bindex_t bindex, bend;
	struct au_branch *br;
	struct au_br_fhsm *bf;

	/* except the bottom branch */
	err = 0;
	nstbr = 0;
	bend = au_fhsm_bottom(sb);
	for (bindex = 0; !err && bindex < bend; bindex++) {
		br = au_sbr(sb, bindex);
		if (!au_br_fhsm(br->br_perm))
			continue;

		bf = br->br_fhsm;
		mutex_lock(&bf->bf_lock);
		if (bf->bf_readable) {
			err = -EFAULT;
			if (count >= sizeof(*stbr))
				err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs,
							  br->br_id);
			if (!err) {
				bf->bf_readable = 0;
				count -= sizeof(*stbr);
				nstbr++;
			}
		}
		mutex_unlock(&bf->bf_lock);
	}
	if (!err)
		err = sizeof(*stbr) * nstbr;

	return err;
}
Ejemplo n.º 5
0
int au_opts_verify(struct super_block *sb, unsigned long sb_flags,
		   unsigned int pending)
{
	int err, fhsm;
	aufs_bindex_t bindex, bend;
	unsigned char do_plink, skip, do_free;
	struct au_branch *br;
	struct au_wbr *wbr;
	struct dentry *root;
	struct inode *dir, *h_dir;
	struct au_sbinfo *sbinfo;
	struct au_hinode *hdir;

	SiMustAnyLock(sb);

	sbinfo = au_sbi(sb);
	AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA));

	if (!(sb_flags & MS_RDONLY)) {
		if (unlikely(!au_br_writable(au_sbr_perm(sb, 0))))
			pr_warn("first branch should be rw\n");
		if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH)))
			pr_warn("shwh should be used with ro\n");
	}

	if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY)
	    && !au_opt_test(sbinfo->si_mntflags, XINO))
		pr_warn("udba=*notify requires xino\n");

	if (au_opt_test(sbinfo->si_mntflags, DIRPERM1))
		pr_warn("dirperm1 breaks the protection"
			" by the permission bits on the lower branch\n");

	err = 0;
	fhsm = 0;
	root = sb->s_root;
	dir = root->d_inode;
	do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK);
	bend = au_sbend(sb);
	for (bindex = 0; !err && bindex <= bend; bindex++) {
		skip = 0;
		h_dir = au_h_iptr(dir, bindex);
		br = au_sbr(sb, bindex);

		if ((br->br_perm & AuBrAttr_ICEX)
		    && !h_dir->i_op->listxattr)
			br->br_perm &= ~AuBrAttr_ICEX;
#if 0
		if ((br->br_perm & AuBrAttr_ICEX_SEC)
		    && (au_br_sb(br)->s_flags & MS_NOSEC))
			br->br_perm &= ~AuBrAttr_ICEX_SEC;
#endif

		do_free = 0;
		wbr = br->br_wbr;
		if (wbr)
			wbr_wh_read_lock(wbr);

		if (!au_br_writable(br->br_perm)) {
			do_free = !!wbr;
			skip = (!wbr
				|| (!wbr->wbr_whbase
				    && !wbr->wbr_plink
				    && !wbr->wbr_orph));
		} else if (!au_br_wh_linkable(br->br_perm)) {
			/* skip = (!br->br_whbase && !br->br_orph); */
			skip = (!wbr || !wbr->wbr_whbase);
			if (skip && wbr) {
				if (do_plink)
					skip = !!wbr->wbr_plink;
				else
					skip = !wbr->wbr_plink;
			}
		} else {
			/* skip = (br->br_whbase && br->br_ohph); */
			skip = (wbr && wbr->wbr_whbase);
			if (skip) {
				if (do_plink)
					skip = !!wbr->wbr_plink;
				else
					skip = !wbr->wbr_plink;
			}
		}
		if (wbr)
			wbr_wh_read_unlock(wbr);

		if (au_br_fhsm(br->br_perm)) {
			fhsm++;
			AuDebugOn(!br->br_fhsm);
		}

		if (skip)
			continue;

		hdir = au_hi(dir, bindex);
		au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT);
		if (wbr)
			wbr_wh_write_lock(wbr);
		err = au_wh_init(br, sb);
		if (wbr)
			wbr_wh_write_unlock(wbr);
		au_hn_imtx_unlock(hdir);

		if (!err && do_free) {
			kfree(wbr);
			br->br_wbr = NULL;
		}
	}

	if (fhsm >= 2) {
		au_fset_si(sbinfo, FHSM);
		for (bindex = bend; bindex >= 0; bindex--) {
			br = au_sbr(sb, bindex);
			if (au_br_fhsm(br->br_perm)) {
				au_fhsm_set_bottom(sb, bindex);
				break;
			}
		}
	} else {
		au_fclr_si(sbinfo, FHSM);
		au_fhsm_set_bottom(sb, -1);
	}

	return err;
}